QNetworkInfo: Add transport medium detection API

The new public API returns and notifies changes to the currently active
transport medium for the application. And there's a new private API to
report it, with backends to follow.

Task-number: QTBUG-91023
Change-Id: I527985f9dabcd7bc4a32f36597e21bc4ab664c4e
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
bb10
Mårten Nordheim 2021-09-17 17:30:36 +02:00
parent d9f6fba385
commit 7fb855e175
4 changed files with 97 additions and 4 deletions

View File

@ -485,6 +485,8 @@ QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend)
connect(backend, &QNetworkInformationBackend::behindCaptivePortalChanged, this, [this]() {
emit isBehindCaptivePortalChanged(d_func()->backend->behindCaptivePortal());
});
connect(backend, &QNetworkInformationBackend::transportMediumChanged, this,
[this]() { emit transportMediumChanged(d_func()->backend->transportMedium()); });
}
/*!
@ -527,6 +529,23 @@ bool QNetworkInformation::isBehindCaptivePortal() const
return d_func()->backend->behindCaptivePortal();
}
/*!
\property QNetworkInformation::transportMedium
\brief The currently active transport medium for the application
\since 6.3
This property returns the currently active transport medium for the
application, on operating systems where such information is available.
When the current transport medium changes a signal is emitted, this can,
for instance, occur when a user leaves the range of a WiFi network, unplugs
their ethernet cable or enables Airplane mode.
*/
QNetworkInformation::TransportMedium QNetworkInformation::transportMedium() const
{
return d_func()->backend->transportMedium();
}
/*!
Returns the name of the currently loaded backend.
*/

View File

@ -57,6 +57,7 @@ class Q_NETWORK_EXPORT QNetworkInformation : public QObject
Q_PROPERTY(Reachability reachability READ reachability NOTIFY reachabilityChanged)
Q_PROPERTY(bool isBehindCaptivePortal READ isBehindCaptivePortal
NOTIFY isBehindCaptivePortalChanged)
Q_PROPERTY(TransportMedium transportMedium READ transportMedium NOTIFY transportMediumChanged)
public:
enum class Reachability {
Unknown,
@ -67,9 +68,19 @@ public:
};
Q_ENUM(Reachability)
enum class TransportMedium {
Unknown,
Ethernet,
Cellular,
WiFi,
Bluetooth,
};
Q_ENUM(TransportMedium)
enum class Feature {
Reachability = 0x1,
CaptivePortal = 0x2,
TransportMedium = 0x4,
};
Q_DECLARE_FLAGS(Features, Feature)
Q_FLAG(Features)
@ -78,6 +89,8 @@ public:
bool isBehindCaptivePortal() const;
TransportMedium transportMedium() const;
QString backendName() const;
bool supports(Features features) const;
@ -90,6 +103,7 @@ public:
Q_SIGNALS:
void reachabilityChanged(Reachability newReachability);
void isBehindCaptivePortalChanged(bool state);
void transportMediumChanged(TransportMedium current);
private:
friend struct QNetworkInformationDeleter;

View File

@ -62,6 +62,10 @@ QT_BEGIN_NAMESPACE
class Q_NETWORK_EXPORT QNetworkInformationBackend : public QObject
{
Q_OBJECT
using Reachability = QNetworkInformation::Reachability;
using TransportMedium = QNetworkInformation::TransportMedium;
public:
QNetworkInformationBackend() = default;
~QNetworkInformationBackend() override;
@ -69,12 +73,14 @@ public:
virtual QString name() const = 0;
virtual QNetworkInformation::Features featuresSupported() const = 0;
QNetworkInformation::Reachability reachability() const { return m_reachability; }
Reachability reachability() const { return m_reachability; }
bool behindCaptivePortal() const { return m_behindCaptivePortal; }
TransportMedium transportMedium() const { return m_transportMedium; }
Q_SIGNALS:
void reachabilityChanged();
void behindCaptivePortalChanged();
void transportMediumChanged();
protected:
void setReachability(QNetworkInformation::Reachability reachability)
@ -93,8 +99,17 @@ protected:
}
}
void setTransportMedium(TransportMedium medium)
{
if (m_transportMedium != medium) {
m_transportMedium = medium;
emit transportMediumChanged();
}
}
private:
QNetworkInformation::Reachability m_reachability = QNetworkInformation::Reachability::Unknown;
Reachability m_reachability = Reachability::Unknown;
TransportMedium m_transportMedium = TransportMedium::Unknown;
bool m_behindCaptivePortal = false;
Q_DISABLE_COPY_MOVE(QNetworkInformationBackend)
@ -105,12 +120,15 @@ private:
class Q_NETWORK_EXPORT QNetworkInformationBackendFactory : public QObject
{
Q_OBJECT
using Features = QNetworkInformation::Features;
public:
QNetworkInformationBackendFactory();
virtual ~QNetworkInformationBackendFactory();
virtual QString name() const = 0;
virtual QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const = 0;
virtual QNetworkInformation::Features featuresSupported() const = 0;
virtual QNetworkInformationBackend *create(Features requiredFeatures) const = 0;
virtual Features featuresSupported() const = 0;
private:
Q_DISABLE_COPY_MOVE(QNetworkInformationBackendFactory)

View File

@ -41,6 +41,7 @@ private slots:
void initTestCase();
void reachability();
void behindCaptivePortal();
void transportMedium();
void cleanupTestCase();
private:
@ -80,6 +81,12 @@ public:
instance->setBehindCaptivePortal(value);
}
static void setNewTransportMedium(QNetworkInformation::TransportMedium medium)
{
Q_ASSERT(instance);
instance->setTransportMedium(medium);
}
static QNetworkInformation::Features featuresSupportedStatic()
{
return { QNetworkInformation::Feature::Reachability,
@ -188,5 +195,40 @@ void tst_QNetworkInformation::behindCaptivePortal()
QVERIFY(!signalEmitted);
}
void tst_QNetworkInformation::transportMedium()
{
auto info = QNetworkInformation::instance();
using TransportMedium = QNetworkInformation::TransportMedium;
TransportMedium medium = TransportMedium::Unknown;
bool signalEmitted = false;
connect(info, &QNetworkInformation::transportMediumChanged, this, [&, info](TransportMedium tm) {
signalEmitted = true;
QCOMPARE(tm, info->transportMedium());
medium = info->transportMedium();
});
QCOMPARE(info->transportMedium(), TransportMedium::Unknown); // Default is unknown
auto transportMediumEnum = QMetaEnum::fromType<TransportMedium>();
auto mediumCount = transportMediumEnum.keyCount();
// Verify index 0 is Unknown and skip it in the loop, it's the default.
QCOMPARE(TransportMedium(transportMediumEnum.value(0)), TransportMedium::Unknown);
for (int i = 1; i < mediumCount; ++i) {
signalEmitted = false;
TransportMedium m = TransportMedium(transportMediumEnum.value(i));
MockBackend::setNewTransportMedium(m);
QCoreApplication::processEvents();
QVERIFY(signalEmitted);
QCOMPARE(info->transportMedium(), m);
QCOMPARE(medium, m);
}
// Set the current value again, signal should not be emitted again
signalEmitted = false;
MockBackend::setNewTransportMedium(medium);
QCoreApplication::processEvents();
QVERIFY(!signalEmitted);
}
QTEST_MAIN(tst_QNetworkInformation);
#include "tst_qnetworkinformation.moc"