diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp index c36b1c4698f..c1e184f961b 100644 --- a/src/network/kernel/qnetworkinformation.cpp +++ b/src/network/kernel/qnetworkinformation.cpp @@ -470,6 +470,21 @@ QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory() \sa QNetworkInformation::reachability */ +/*! + \enum QNetworkInformation::TriState + \since 6.2 + + A bool with a 3rd, unknown, state. + + \value False + Known to be \c{false}. + \value True + Known to be \c{true}. + \value Unknown + The state cannot be determined at present, either because the query is + not supported on this platform or because the OS lacks the information. +*/ + /*! \internal ctor */ @@ -478,6 +493,9 @@ QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend) { connect(backend, &QNetworkInformationBackend::reachabilityChanged, this, [this]() { emit reachabilityChanged(d_func()->backend->reachability()); }); + connect(backend, &QNetworkInformationBackend::behindCaptivePortalChanged, this, [this]() { + emit behindCaptivePortalChanged(d_func()->backend->behindCaptivePortal()); + }); } /*! @@ -504,6 +522,24 @@ QNetworkInformation::Reachability QNetworkInformation::reachability() const return d_func()->backend->reachability(); } +/*! + \property QNetworkInformation::behindCaptivePortal + \brief Lets you know if the user's device is behind a captive portal. + \since 6.2 + + This property indicates if the user's device is currently behind a captive + portal. This functionality relies on the operating system's detection of + captive portals and is not supported on systems that don't report this. + On systems where this is not supported this will always return + TriState::Unknown. + + \sa TriState +*/ +QNetworkInformation::TriState QNetworkInformation::behindCaptivePortal() const +{ + return d_func()->backend->behindCaptivePortal(); +} + /*! Returns the name of the currently loaded backend. */ diff --git a/src/network/kernel/qnetworkinformation.h b/src/network/kernel/qnetworkinformation.h index 07f4fe873db..6e700747bb3 100644 --- a/src/network/kernel/qnetworkinformation.h +++ b/src/network/kernel/qnetworkinformation.h @@ -55,6 +55,7 @@ class Q_NETWORK_EXPORT QNetworkInformation : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QNetworkInformation) Q_PROPERTY(Reachability reachability READ reachability NOTIFY reachabilityChanged) + Q_PROPERTY(TriState behindCaptivePortal READ behindCaptivePortal NOTIFY behindCaptivePortalChanged) public: enum class Reachability { Unknown, @@ -65,14 +66,24 @@ public: }; Q_ENUM(Reachability) + enum class TriState { + False, + True, + Unknown, + }; + Q_ENUM(TriState) + enum class Feature { Reachability = 0x1, + CaptivePortal = 0x2, }; Q_DECLARE_FLAGS(Features, Feature) Q_FLAG(Features) Reachability reachability() const; + TriState behindCaptivePortal() const; + QString backendName() const; bool supports(Features features) const; @@ -84,6 +95,7 @@ public: Q_SIGNALS: void reachabilityChanged(Reachability newReachability); + void behindCaptivePortalChanged(TriState state); private: friend struct QNetworkInformationDeleter; diff --git a/src/network/kernel/qnetworkinformation_p.h b/src/network/kernel/qnetworkinformation_p.h index 8cb31e66414..c71e7787a4e 100644 --- a/src/network/kernel/qnetworkinformation_p.h +++ b/src/network/kernel/qnetworkinformation_p.h @@ -70,9 +70,11 @@ public: virtual QNetworkInformation::Features featuresSupported() const = 0; QNetworkInformation::Reachability reachability() const { return m_reachability; } + QNetworkInformation::TriState behindCaptivePortal() const { return m_behindCaptivePortal; } Q_SIGNALS: void reachabilityChanged(); + void behindCaptivePortalChanged(); protected: void setReachability(QNetworkInformation::Reachability reachability) @@ -83,8 +85,18 @@ protected: } } + void setBehindCaptivePortal(QNetworkInformation::TriState behindPortal) + { + if (m_behindCaptivePortal != behindPortal) { + m_behindCaptivePortal = behindPortal; + emit behindCaptivePortalChanged(); + } + } + private: QNetworkInformation::Reachability m_reachability = QNetworkInformation::Reachability::Unknown; + QNetworkInformation::TriState m_behindCaptivePortal = + QNetworkInformation::TriState::Unknown; Q_DISABLE_COPY_MOVE(QNetworkInformationBackend) friend class QNetworkInformation; diff --git a/tests/auto/network/kernel/qnetworkinformation/tst_qnetworkinformation.cpp b/tests/auto/network/kernel/qnetworkinformation/tst_qnetworkinformation.cpp index 09fa65273d0..188355d3738 100644 --- a/tests/auto/network/kernel/qnetworkinformation/tst_qnetworkinformation.cpp +++ b/tests/auto/network/kernel/qnetworkinformation/tst_qnetworkinformation.cpp @@ -40,6 +40,7 @@ class tst_QNetworkInformation : public QObject private slots: void initTestCase(); void reachability(); + void behindCaptivePortal(); void cleanupTestCase(); private: @@ -56,6 +57,7 @@ public: Q_ASSERT(!instance); instance = this; setReachability(QNetworkInformation::Reachability::Online); + setNewBehindCaptivePortal(QNetworkInformation::TriState::False); } ~MockBackend() { instance = nullptr; } @@ -72,9 +74,16 @@ public: instance->setReachability(value); } + static void setNewBehindCaptivePortal(QNetworkInformation::TriState value) + { + Q_ASSERT(instance); + instance->setBehindCaptivePortal(value); + } + static QNetworkInformation::Features featuresSupportedStatic() { - return { QNetworkInformation::Feature::Reachability }; + return { QNetworkInformation::Feature::Reachability, + QNetworkInformation::Feature::CaptivePortal }; } private: @@ -152,5 +161,31 @@ void tst_QNetworkInformation::reachability() QCOMPARE(boundIsOnline, QNetworkInformation::Reachability::Site); } +void tst_QNetworkInformation::behindCaptivePortal() +{ + auto info = QNetworkInformation::instance(); + QNetworkInformation::TriState behindPortal = QNetworkInformation::TriState::Unknown; + bool signalEmitted = false; + + connect(info, &QNetworkInformation::behindCaptivePortalChanged, this, + [&, info](QNetworkInformation::TriState state) { + signalEmitted = true; + QCOMPARE(state, info->behindCaptivePortal()); + behindPortal = info->behindCaptivePortal(); + }); + QCOMPARE(info->behindCaptivePortal(), QNetworkInformation::TriState::False); + MockBackend::setNewBehindCaptivePortal(QNetworkInformation::TriState::True); + QCoreApplication::processEvents(); + QVERIFY(signalEmitted); + QCOMPARE(info->behindCaptivePortal(), QNetworkInformation::TriState::True); + QCOMPARE(behindPortal, QNetworkInformation::TriState::True); + + // Set the same value again, signal should not be emitted again + signalEmitted = false; + MockBackend::setNewBehindCaptivePortal(QNetworkInformation::TriState::True); + QCoreApplication::processEvents(); + QVERIFY(!signalEmitted); +} + QTEST_MAIN(tst_QNetworkInformation); #include "tst_qnetworkinformation.moc" diff --git a/tests/manual/qnetworkinformation/tst_qnetworkinformation.cpp b/tests/manual/qnetworkinformation/tst_qnetworkinformation.cpp index ab6b5335f97..79ca27a4d1e 100644 --- a/tests/manual/qnetworkinformation/tst_qnetworkinformation.cpp +++ b/tests/manual/qnetworkinformation/tst_qnetworkinformation.cpp @@ -48,7 +48,13 @@ int main(int argc, char **argv) qDebug() << "Updated:" << newStatus; }); - qDebug() << "Initial:" << info->reachability(); + QObject::connect(info, &QNetworkInformation::behindCaptivePortalChanged, + [](QNetworkInformation::TriState status) { + qDebug() << "Updated, behind captive portal:" << status; + }); + + qDebug() << "Initial reachability:" << info->reachability(); + qDebug() << "Behind captive portal:" << info->behindCaptivePortal(); return app.exec(); }