Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qnetworkinformation.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4// #define DEBUG_LOADING
5
7#include <QtNetwork/private/qnetworkinformation_p.h>
8#include <QtNetwork/qnetworkinformation.h>
9
10#include <QtCore/private/qobject_p.h>
11#include <QtCore/qcoreapplication.h>
12#include <QtCore/qmutex.h>
13#include <QtCore/qthread.h>
14#include <QtCore/private/qfactoryloader_p.h>
15
16#include <algorithm>
17#include <memory>
18#include <mutex>
19
20QT_BEGIN_NAMESPACE
21Q_DECLARE_LOGGING_CATEGORY(lcNetInfo)
22Q_LOGGING_CATEGORY(lcNetInfo, "qt.network.info");
23
25{
26 void operator()(QNetworkInformation *information) { delete information; }
27};
28
29Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qniLoader,
30 (QNetworkInformationBackendFactory_iid,
31 QStringLiteral("/networkinformation")))
32
33struct QStaticNetworkInformationDataHolder
34{
35 QMutex instanceMutex;
36 std::unique_ptr<QNetworkInformation, QNetworkInformationDeleter> instanceHolder;
37 QList<QNetworkInformationBackendFactory *> factories;
38};
39Q_GLOBAL_STATIC(QStaticNetworkInformationDataHolder, dataHolder);
40
41static void networkInfoCleanup()
42{
43 if (!dataHolder.exists())
44 return;
45 QMutexLocker locker(&dataHolder->instanceMutex);
46 QNetworkInformation *instance = dataHolder->instanceHolder.get();
47 if (!instance)
48 return;
49
50 dataHolder->instanceHolder.reset();
51}
52
53using namespace Qt::Literals::StringLiterals;
54
57public:
58 QString name() const override { return u"dummy"_s; }
60 {
61 return {};
62 }
63};
64
66{
67 Q_DECLARE_PUBLIC(QNetworkInformation)
68public:
72
74 static QNetworkInformation *create(QStringView name);
77 {
78 if (!dataHolder())
79 return nullptr;
80 QMutexLocker locker(&dataHolder->instanceMutex);
81 return dataHolder->instanceHolder.get();
82 }
84 static void addToList(QNetworkInformationBackendFactory *factory);
85 static void removeFromList(QNetworkInformationBackendFactory *factory);
86
87private:
88 static bool initializeList();
89
90 std::unique_ptr<QNetworkInformationBackend> backend;
91};
92
93bool QNetworkInformationPrivate::initializeList()
94{
95 if (!qniLoader())
96 return false;
97 if (!dataHolder())
98 return false;
99 Q_CONSTINIT static QBasicMutex mutex;
100 QMutexLocker initLocker(&mutex);
101
102#if QT_CONFIG(library)
103 qniLoader->update();
104#endif
105 // Instantiates the plugins (and registers the factories)
106 int index = 0;
107 while (qniLoader->instance(index))
108 ++index;
109 initLocker.unlock();
110
111 // Now sort the list on number of features available (then name)
112 const auto featuresNameOrder = [](QNetworkInformationBackendFactory *a,
113 QNetworkInformationBackendFactory *b) {
114 if (!a || !b)
115 return a && !b;
116 auto aFeaturesSupported = qPopulationCount(unsigned(a->featuresSupported()));
117 auto bFeaturesSupported = qPopulationCount(unsigned(b->featuresSupported()));
118 return aFeaturesSupported > bFeaturesSupported
119 || (aFeaturesSupported == bFeaturesSupported
120 && a->name().compare(b->name(), Qt::CaseInsensitive) < 0);
121 };
122 QMutexLocker instanceLocker(&dataHolder->instanceMutex);
123 std::sort(dataHolder->factories.begin(), dataHolder->factories.end(), featuresNameOrder);
124
125 return !dataHolder->factories.isEmpty();
126}
127
128void QNetworkInformationPrivate::addToList(QNetworkInformationBackendFactory *factory)
129{
130 // @note: factory is in the base class ctor
131 if (!dataHolder())
132 return;
133 QMutexLocker locker(&dataHolder->instanceMutex);
134 dataHolder->factories.append(factory);
135}
136
137void QNetworkInformationPrivate::removeFromList(QNetworkInformationBackendFactory *factory)
138{
139 // @note: factory is in the base class dtor
140 if (!dataHolder.exists())
141 return;
142 QMutexLocker locker(&dataHolder->instanceMutex);
143 dataHolder->factories.removeAll(factory);
144}
145
146QStringList QNetworkInformationPrivate::backendNames()
147{
148 if (!dataHolder())
149 return {};
150 if (!initializeList())
151 return {};
152
153 QMutexLocker locker(&dataHolder->instanceMutex);
154 const QList copy = dataHolder->factories;
155 locker.unlock();
156
157 QStringList result;
158 result.reserve(copy.size());
159 for (const auto *factory : copy)
160 result << factory->name();
161 return result;
162}
163
164QNetworkInformation *QNetworkInformationPrivate::create(QStringView name)
165{
166 if (name.isEmpty())
167 return nullptr;
168 if (!dataHolder())
169 return nullptr;
170#ifdef DEBUG_LOADING
171 qDebug().nospace() << "create() called with name=\"" << name
172 << "\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
173#endif
174 if (!initializeList()) {
175#ifdef DEBUG_LOADING
176 qDebug("Failed to initialize list, returning.");
177#endif
178 return nullptr;
179 }
180
181 QMutexLocker locker(&dataHolder->instanceMutex);
182 if (dataHolder->instanceHolder)
183 return dataHolder->instanceHolder.get();
184
185
186 const auto nameMatches = [name](QNetworkInformationBackendFactory *factory) {
187 return factory->name().compare(name, Qt::CaseInsensitive) == 0;
188 };
189 auto it = std::find_if(dataHolder->factories.cbegin(), dataHolder->factories.cend(),
190 nameMatches);
191 if (it == dataHolder->factories.cend()) {
192#ifdef DEBUG_LOADING
193 if (dataHolder->factories.isEmpty()) {
194 qDebug("No plugins available");
195 } else {
196 QString listNames;
197 listNames.reserve(8 * dataHolder->factories.count());
198 for (const auto *factory : std::as_const(dataHolder->factories))
199 listNames += factory->name() + ", "_L1;
200 listNames.chop(2);
201 qDebug().nospace() << "Couldn't find " << name << " in list with names: { "
202 << listNames << " }";
203 }
204#endif
205 return nullptr;
206 }
207#ifdef DEBUG_LOADING
208 qDebug() << "Creating instance using loader named " << (*it)->name();
209#endif
210 QNetworkInformationBackend *backend = (*it)->create((*it)->featuresSupported());
211 if (!backend)
212 return nullptr;
213 dataHolder->instanceHolder.reset(new QNetworkInformation(backend));
214 Q_ASSERT(name.isEmpty()
215 || dataHolder->instanceHolder->backendName().compare(name, Qt::CaseInsensitive) == 0);
216 return dataHolder->instanceHolder.get();
217}
218
219QNetworkInformation *QNetworkInformationPrivate::create(QNetworkInformation::Features features)
220{
221 if (!dataHolder())
222 return nullptr;
223#ifdef DEBUG_LOADING
224 qDebug().nospace() << "create() called with features=\"" << features
225 << "\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
226#endif
227 if (features == 0)
228 return nullptr;
229
230 if (!initializeList()) {
231#ifdef DEBUG_LOADING
232 qDebug("Failed to initialize list, returning.");
233#endif
234 return nullptr;
235 }
236 QMutexLocker locker(&dataHolder->instanceMutex);
237 if (dataHolder->instanceHolder)
238 return dataHolder->instanceHolder.get();
239
240 const auto supportsRequestedFeatures = [features](QNetworkInformationBackendFactory *factory) {
241 return factory && factory->featuresSupported().testFlags(features);
242 };
243
244 for (auto it = dataHolder->factories.cbegin(), end = dataHolder->factories.cend(); it != end;
245 ++it) {
246 it = std::find_if(it, end, supportsRequestedFeatures);
247 if (it == end) {
248#ifdef DEBUG_LOADING
249 if (dataHolder->factories.isEmpty()) {
250 qDebug("No plugins available");
251 } else {
252 QStringList names;
253 names.reserve(dataHolder->factories.count());
254 for (const auto *factory : std::as_const(dataHolder->factories))
255 names += factory->name();
256 qDebug() << "None of the following backends has all the requested features:"
257 << names << features;
258 }
259#endif
260 break;
261 }
262#ifdef DEBUG_LOADING
263 qDebug() << "Creating instance using loader named" << (*it)->name();
264#endif
265 if (QNetworkInformationBackend *backend = (*it)->create(features)) {
266 dataHolder->instanceHolder.reset(new QNetworkInformation(backend));
267 Q_ASSERT(dataHolder->instanceHolder->supports(features));
268 return dataHolder->instanceHolder.get();
269 }
270#ifdef DEBUG_LOADING
271 else {
272 qDebug() << "The factory returned a nullptr";
273 }
274#endif
275 }
276#ifdef DEBUG_LOADING
277 qDebug() << "Couldn't find/create an appropriate backend.";
278#endif
279 return nullptr;
280}
281
282QNetworkInformation *QNetworkInformationPrivate::createDummy()
283{
284 if (!dataHolder())
285 return nullptr;
286
287 QMutexLocker locker(&dataHolder->instanceMutex);
288 if (dataHolder->instanceHolder)
289 return dataHolder->instanceHolder.get();
290
291 QNetworkInformationBackend *backend = new QNetworkInformationDummyBackend;
292 dataHolder->instanceHolder.reset(new QNetworkInformation(backend));
293 return dataHolder->instanceHolder.get();
294}
295
296/*!
297 \class QNetworkInformationBackend
298 \internal (Semi-private)
299 \brief QNetworkInformationBackend provides the interface with
300 which QNetworkInformation does all of its actual work.
301
302 Deriving from and implementing this class makes it a candidate
303 for use with QNetworkInformation. The derived class must, on
304 updates, call setters in the QNetworkInformationBackend which
305 will update the values and emit signals if the value has changed.
306
307 \sa QNetworkInformationBackendFactory
308*/
309
310/*!
311 \internal
312 Destroys base backend class.
313*/
314QNetworkInformationBackend::~QNetworkInformationBackend() = default;
315
316/*!
317 \fn QNetworkInformationBackend::name()
318
319 Backend name, return the same in
320 QNetworkInformationBackendFactory::name().
321*/
322
323/*!
324 \fn QNetworkInformation::Features QNetworkInformationBackend::featuresSupported()
325
326 Features supported, return the same in
327 QNetworkInformationBackendFactory::featuresSupported().
328*/
329
330/*!
331 \fn void QNetworkInformationBackend::reachabilityChanged(NetworkInformation::Reachability reachability)
332
333 You should not emit this signal manually, call setReachability()
334 instead which will emit this signal when the value changes.
335
336 \sa setReachability
337*/
338
339/*!
340 \fn void QNetworkInformationBackend::setReachability(QNetworkInformation::Reachability reachability)
341
342 Call this when reachability has changed. It will automatically
343 emit reachabilityChanged().
344
345 \sa setReachability
346*/
347
348/*!
349 \class QNetworkInformationBackendFactory
350 \internal (Semi-private)
351 \brief QNetworkInformationBackendFactory provides the interface
352 for creating instances of QNetworkInformationBackend.
353
354 Deriving from and implementing this class will let you register
355 your plugin with QNetworkInformation. It must provide some basic
356 information for querying information about the backend, and must
357 also create the backend if requested. If some pre-conditions for
358 the backend is not met it must return \nullptr.
359*/
360
361/*!
362 \internal
363 Adds the factory to an internal list.
364*/
365QNetworkInformationBackendFactory::QNetworkInformationBackendFactory()
366{
367 QNetworkInformationPrivate::addToList(this);
368}
369
370/*!
371 \internal
372 Removes the factory from an internal list.
373*/
374QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory()
375{
376 QNetworkInformationPrivate::removeFromList(this);
377}
378
379/*!
380 \fn QString QNetworkInformationBackendFactory::name()
381
382 Backend name, return the same in
383 QNetworkInformationBackend::name().
384*/
385
386/*!
387 \fn QNetworkInformation::Features QNetworkInformationBackendFactory::featuresSupported()
388
389 Features supported, return the same in
390 QNetworkInformationBackend::featuresSupported().
391 The factory should not promise support for features that wouldn't
392 be available after creating the backend.
393*/
394
395/*!
396 \fn QNetworkInformationBackend *QNetworkInformationBackendFactory::create()
397
398 Create and return an instance of QNetworkInformationBackend. It
399 will be deallocated by QNetworkInformation on shutdown. If some
400 precondition is not met, meaning the backend would not function
401 correctly, then you must return \nullptr.
402*/
403
404/*!
405 \class QNetworkInformation
406 \inmodule QtNetwork
407 \since 6.1
408 \brief QNetworkInformation exposes various network information
409 through native backends.
410
411 QNetworkInformation provides a cross-platform interface to
412 network-related information through plugins.
413
414 Various plugins can have various functionality supported, and so
415 you can load() plugins based on which features are needed.
416
417 QNetworkInformation is a singleton and stays alive from the first
418 successful load() until destruction of the QCoreApplication object.
419 If you destroy and re-create the QCoreApplication object you must call
420 load() again.
421
422 \note Because the class is a singleton while also relying on
423 QCoreApplication, QNetworkInformation should always first be loaded
424 in the same thread as the QCoreApplication object. This is because the
425 object will also be destroyed in this thread, and various backend-specific
426 components may rely on being destroyed in the same thread as it is created.
427
428 \sa QNetworkInformation::Feature
429*/
430
431/*!
432 \enum QNetworkInformation::Feature
433
434 Lists all of the features that a plugin may currently support.
435 This can be used in QNetworkInformation::load().
436
437 \value Reachability
438 If the plugin supports this feature then the \c reachability property
439 will provide useful results. Otherwise it will always return
440 \c{Reachability::Unknown}.
441 See also QNetworkInformation::Reachability.
442
443 \value CaptivePortal
444 If the plugin supports this feature then the \c isBehindCaptivePortal
445 property will provide useful results. Otherwise it will always return
446 \c{false}.
447
448 \value TransportMedium
449 If the plugin supports this feature then the \c transportMedium
450 property will provide useful results. Otherwise it will always return
451 \c{TransportMedium::Unknown}.
452 See also QNetworkInformation::TransportMedium.
453
454 \value Metered
455 If the plugin supports this feature then the \c isMetered
456 property will provide useful results. Otherwise it will always return
457 \c{false}.
458*/
459
460/*!
461 \enum QNetworkInformation::Reachability
462
463 \value Unknown
464 If this value is returned then we may be connected but the OS
465 has still not confirmed full connectivity, or this feature
466 is not supported.
467 \value Disconnected
468 Indicates that the system may have no connectivity at all.
469 \value Local
470 Indicates that the system is connected to a network, but it
471 might only be able to access devices on the local network.
472 \value Site
473 Indicates that the system is connected to a network, but it
474 might only be able to access devices on the local subnet or an
475 intranet.
476 \value Online
477 Indicates that the system is connected to a network and
478 able to access the Internet.
479
480 \sa QNetworkInformation::reachability
481*/
482
483/*!
484 \enum QNetworkInformation::TransportMedium
485 \since 6.3
486
487 Lists the currently recognized media with which one can connect to the
488 internet.
489
490 \value Unknown
491 Returned if either the OS reports no active medium, the active medium is
492 not recognized by Qt, or the TransportMedium feature is not supported.
493 \value Ethernet
494 Indicates that the currently active connection is using ethernet.
495 Note: This value may also be returned when Windows is connected to a
496 Bluetooth personal area network.
497 \value Cellular
498 Indicates that the currently active connection is using a cellular
499 network.
500 \value WiFi
501 Indicates that the currently active connection is using Wi-Fi.
502 \value Bluetooth
503 Indicates that the currently active connection is connected using
504 Bluetooth.
505
506 \sa QNetworkInformation::transportMedium
507*/
508
509/*!
510 \internal ctor
511*/
512QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend)
513 : QObject(*(new QNetworkInformationPrivate(backend)))
514{
515 connect(backend, &QNetworkInformationBackend::reachabilityChanged, this,
516 &QNetworkInformation::reachabilityChanged);
517 connect(backend, &QNetworkInformationBackend::behindCaptivePortalChanged, this,
518 &QNetworkInformation::isBehindCaptivePortalChanged);
519 connect(backend, &QNetworkInformationBackend::transportMediumChanged, this,
520 &QNetworkInformation::transportMediumChanged);
521 connect(backend, &QNetworkInformationBackend::isMeteredChanged, this,
522 &QNetworkInformation::isMeteredChanged);
523
524 QThread *main = nullptr;
525
526 if (QCoreApplication::instance())
527 main = QCoreApplication::instance()->thread();
528
529 if (main && thread() != main)
530 moveToThread(main);
531}
532
533/*!
534 \internal dtor
535*/
536QNetworkInformation::~QNetworkInformation() = default;
537
538/*!
539 \property QNetworkInformation::reachability
540 \brief The current state of the system's network connectivity.
541
542 Indicates the level of connectivity that can be expected. Do note
543 that this is only based on what the plugin/operating system
544 reports. In certain scenarios this is known to be wrong. For
545 example, on Windows the 'Online' check, by default, is performed
546 by Windows connecting to a Microsoft-owned server. If this server
547 is for any reason blocked then it will assume it does not have
548 Online reachability. Because of this you should not use this as a
549 pre-check before attempting to make a connection.
550*/
551
552QNetworkInformation::Reachability QNetworkInformation::reachability() const
553{
554 return d_func()->backend->reachability();
555}
556
557/*!
558 \property QNetworkInformation::isBehindCaptivePortal
559 \brief Lets you know if the user's device is behind a captive portal.
560 \since 6.2
561
562 This property indicates if the user's device is currently known to be
563 behind a captive portal. This functionality relies on the operating system's
564 detection of captive portals and is not supported on systems that don't
565 report this. On systems where this is not supported this will always return
566 \c{false}.
567*/
568bool QNetworkInformation::isBehindCaptivePortal() const
569{
570 return d_func()->backend->behindCaptivePortal();
571}
572
573/*!
574 \property QNetworkInformation::transportMedium
575 \brief The currently active transport medium for the application
576 \since 6.3
577
578 This property returns the currently active transport medium for the
579 application, on operating systems where such information is available.
580
581 When the current transport medium changes a signal is emitted, this can,
582 for instance, occur when a user leaves the range of a WiFi network, unplugs
583 their ethernet cable or enables Airplane mode.
584*/
585QNetworkInformation::TransportMedium QNetworkInformation::transportMedium() const
586{
587 return d_func()->backend->transportMedium();
588}
589
590/*!
591 \property QNetworkInformation::isMetered
592 \brief Check if the current connection is metered
593 \since 6.3
594
595 This property returns whether the current connection is (known to be)
596 metered or not. You can use this as a guiding factor to decide whether your
597 application should perform certain network requests or uploads.
598 For instance, you may not want to upload logs or diagnostics while this
599 property is \c true.
600*/
601bool QNetworkInformation::isMetered() const
602{
603 return d_func()->backend->isMetered();
604}
605
606/*!
607 Returns the name of the currently loaded backend.
608*/
609QString QNetworkInformation::backendName() const
610{
611 return d_func()->backend->name();
612}
613
614/*!
615 Returns \c true if the currently loaded backend supports
616 \a features.
617*/
618bool QNetworkInformation::supports(Features features) const
619{
620 return (d_func()->backend->featuresSupported() & features) == features;
621}
622
623/*!
624 \since 6.3
625
626 Returns all the supported features of the current backend.
627*/
628QNetworkInformation::Features QNetworkInformation::supportedFeatures() const
629{
630 return d_func()->backend->featuresSupported();
631}
632
633/*!
634 \since 6.3
635
636 Attempts to load the platform-default backend.
637
638 \note Starting with 6.7 this tries to load any backend that supports
639 \l{QNetworkInformation::Feature::Reachability}{Reachability} if the
640 platform-default backend is not available or fails to load.
641 If this also fails it will fall back to a backend that only returns
642 the default values for all properties.
643
644 This platform-to-plugin mapping is as follows:
645
646 \table
647 \header
648 \li Platform
649 \li Plugin-name
650 \row
651 \li Windows
652 \li networklistmanager
653 \row
654 \li Apple (macOS/iOS)
655 \li applenetworkinformation
656 \row
657 \li Android
658 \li android
659 \row
660 \li Linux
661 \li networkmanager
662 \endtable
663
664 This function is provided for convenience where the logic earlier
665 is good enough. If you require a specific plugin then you should call
666 loadBackendByName() or loadBackendByFeatures() directly instead.
667
668 Determines a suitable backend to load and returns \c true if this backend
669 is already loaded or on successful loading of it. Returns \c false if any
670 other backend has already been loaded, or if loading of the selected
671 backend fails.
672
673 \sa instance(), load()
674*/
675bool QNetworkInformation::loadDefaultBackend()
676{
677 int index = -1;
678#ifdef Q_OS_WIN
679 index = QNetworkInformationBackend::PluginNamesWindowsIndex;
680#elif defined(Q_OS_DARWIN)
681 index = QNetworkInformationBackend::PluginNamesAppleIndex;
682#elif defined(Q_OS_ANDROID)
683 index = QNetworkInformationBackend::PluginNamesAndroidIndex;
684#elif defined(Q_OS_LINUX)
685 index = QNetworkInformationBackend::PluginNamesLinuxIndex;
686#endif
687 if (index != -1 && loadBackendByName(QNetworkInformationBackend::PluginNames[index]))
688 return true;
689 // We assume reachability is the most commonly wanted feature, and try to
690 // load the backend that advertises the most features including that:
691 if (loadBackendByFeatures(Feature::Reachability))
692 return true;
693
694 // Fall back to the dummy backend
695 return loadBackendByName(u"dummy");
696}
697
698/*!
699 \since 6.4
700
701 Attempts to load a backend whose name matches \a backend
702 (case insensitively).
703
704 Returns \c true if it managed to load the requested backend or
705 if it was already loaded. Returns \c false otherwise.
706
707 \sa instance
708*/
709bool QNetworkInformation::loadBackendByName(QStringView backend)
710{
711 if (backend == u"dummy")
712 return QNetworkInformationPrivate::createDummy() != nullptr;
713
714 auto loadedBackend = QNetworkInformationPrivate::create(backend);
715 return loadedBackend && loadedBackend->backendName().compare(backend, Qt::CaseInsensitive) == 0;
716}
717
718#if QT_DEPRECATED_SINCE(6,4)
719/*!
720 \deprecated [6.4] Use loadBackendByName() instead.
721
722 \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures()
723*/
724bool QNetworkInformation::load(QStringView backend)
725{
726 return loadBackendByName(backend);
727}
728#endif // QT_DEPRECATED_SINCE(6,4)
729
730/*!
731 \since 6.4
732 Load a backend which supports \a features.
733
734 Returns \c true if it managed to load the requested backend or
735 if it was already loaded. Returns \c false otherwise.
736
737 \sa instance
738*/
739bool QNetworkInformation::loadBackendByFeatures(Features features)
740{
741 auto loadedBackend = QNetworkInformationPrivate::create(features);
742 return loadedBackend && loadedBackend->supports(features);
743}
744
745#if QT_DEPRECATED_SINCE(6,4)
746/*!
747 \deprecated [6.4] Use loadBackendByFeatures() instead.
748
749 \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures()
750*/
751bool QNetworkInformation::load(Features features)
752{
753 return loadBackendByFeatures(features);
754}
755#endif // QT_DEPRECATED_SINCE(6,4)
756
757/*!
758 Returns a list of the names of all currently available backends.
759*/
760QStringList QNetworkInformation::availableBackends()
761{
762 return QNetworkInformationPrivate::backendNames();
763}
764
765/*!
766 Returns a pointer to the instance of the QNetworkInformation,
767 if any.
768
769 \sa load()
770*/
771QNetworkInformation *QNetworkInformation::instance()
772{
773 return QNetworkInformationPrivate::instance();
774}
775
776QT_END_NAMESPACE
777
778#include "moc_qnetworkinformation.cpp"
779#include "moc_qnetworkinformation_p.cpp"
780#include "qnetworkinformation.moc"
static QNetworkInformation * create(QStringView name)
static QNetworkInformation * createDummy()
static void addToList(QNetworkInformationBackendFactory *factory)
static QNetworkInformation * instance()
static void removeFromList(QNetworkInformationBackendFactory *factory)
static void networkInfoCleanup()
Q_GLOBAL_STATIC(QStaticNetworkInformationDataHolder, dataHolder)
Q_GLOBAL_STATIC_WITH_ARGS(PermissionStatusHash, g_permissionStatusHash,({ { qMetaTypeId< QCameraPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QMicrophonePermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QBluetoothPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QContactsPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QCalendarPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QLocationPermission >(), Qt::PermissionStatus::Undetermined } }))
void operator()(QNetworkInformation *information)