summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorMårten Nordheim <marten.nordheim@qt.io>2021-09-23 15:01:47 +0200
committerMårten Nordheim <marten.nordheim@qt.io>2021-10-07 19:08:26 +0200
commit589389843c1850e725972b4a6ba901d32bb59d73 (patch)
tree9aca331fc6700db3d08f2eca2e58b4f5ef04115e /src/plugins
parent7fb855e175df6aa5937b00ea05312cf7ed323afa (diff)
QNetworkInformation: add support for transportMedium on Android
It's part of the capabilities which we are already using. It also lets us work around a pre-existing edge-case where, if you have a VPN enabled and enable Airplane mode it will continue to tell you it is Online even when it is not. This happens because VPN is reported as a transport and when Airplane mode is enabled it may be left enabled as the _only_ transport. At the same time clear the default filters (if any), and filter out suspended connections. May not necessarily make any difference. And add a comment for why we cannot use a technically more suitable type of callback. Task-number: QTBUG-91023 Change-Id: Ic26c4d4e8da139ec8606a0b1bf5fb7157bd0beaf Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java60
-rw-r--r--src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp36
-rw-r--r--src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp16
-rw-r--r--src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h15
4 files changed, 124 insertions, 3 deletions
diff --git a/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java b/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
index 0e89d23ab4..403286121e 100644
--- a/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
+++ b/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
@@ -48,12 +48,14 @@ import android.net.ConnectivityManager.NetworkCallback;
import android.net.NetworkRequest;
import android.net.NetworkCapabilities;
import android.net.Network;
+import android.os.Build;
public class QtAndroidNetworkInformation {
private static final String LOG_TAG = "QtAndroidNetworkInformation";
private static native void connectivityChanged();
private static native void behindCaptivePortalChanged(boolean state);
+ private static native void transportMediumChanged(Transport transportMedium);
private static QtNetworkInformationCallback m_callback = null;
private static final Object m_lock = new Object();
@@ -62,8 +64,21 @@ public class QtAndroidNetworkInformation {
Connected, Unknown, Disconnected
}
+ // Keep synchronized with AndroidTransport in androidconnectivitymanager.h
+ enum Transport {
+ Unknown,
+ Bluetooth,
+ Cellular,
+ Ethernet,
+ LoWPAN,
+ Usb,
+ WiFi,
+ WiFiAware,
+ }
+
private static class QtNetworkInformationCallback extends NetworkCallback {
public AndroidConnectivity previousState = null;
+ public Transport previousTransport = null;
QtNetworkInformationCallback() {
}
@@ -77,13 +92,42 @@ public class QtAndroidNetworkInformation {
s = AndroidConnectivity.Connected;
else
s = AndroidConnectivity.Unknown; // = we _may_ have Internet access
+
+ final Transport transport = getTransport(capabilities);
+ if (transport == Transport.Unknown) // If we don't have any transport media: override
+ s = AndroidConnectivity.Unknown;
+
setState(s);
+ setTransportMedium(transport);
final boolean captive
= capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
behindCaptivePortalChanged(captive);
}
+ private Transport getTransport(NetworkCapabilities capabilities)
+ {
+ if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ return Transport.WiFi;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ return Transport.Cellular;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
+ return Transport.Bluetooth;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
+ return Transport.Ethernet;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
+ // Build.VERSION_CODES.O
+ return Transport.WiFiAware;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)) {
+ // Build.VERSION_CODES.O_MR1
+ return Transport.LoWPAN;
+ }/* else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_USB)) {
+ // Build.VERSION_CODES.S
+ return Transport.Usb;
+ }*/ // @todo: Uncomment once we can use SDK 31
+ return Transport.Unknown;
+ }
+
private void setState(AndroidConnectivity s) {
if (previousState != s) {
previousState = s;
@@ -91,6 +135,13 @@ public class QtAndroidNetworkInformation {
}
}
+ private void setTransportMedium(Transport t) {
+ if (previousTransport != t) {
+ previousTransport = t;
+ transportMediumChanged(t);
+ }
+ }
+
@Override
public void onLost(Network network) {
setState(AndroidConnectivity.Disconnected);
@@ -112,10 +163,17 @@ public class QtAndroidNetworkInformation {
ConnectivityManager manager = getConnectivityManager(context);
m_callback = new QtNetworkInformationCallback();
NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+ builder = builder.clearCapabilities();
builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND);
+ }
NetworkRequest request = builder.build();
+
+ // Can't use registerDefaultNetworkCallback because it doesn't let us know when
+ // the network disconnects!
manager.registerNetworkCallback(request, m_callback);
}
}
diff --git a/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp b/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
index 9eef471989..33103b00b7 100644
--- a/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
+++ b/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
@@ -65,13 +65,17 @@ public:
static QNetworkInformation::Features featuresSupportedStatic()
{
using Feature = QNetworkInformation::Feature;
- return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal);
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
+ | Feature::TransportMedium);
}
bool isValid() { return m_valid; }
private:
Q_DISABLE_COPY_MOVE(QAndroidNetworkInformationBackend);
+
+ void updateTransportMedium(AndroidConnectivityManager::AndroidTransport transport);
+
bool m_valid = false;
};
@@ -129,6 +133,36 @@ QAndroidNetworkInformationBackend::QAndroidNetworkInformationBackend()
connect(conman, &AndroidConnectivityManager::captivePortalChanged, this,
&QAndroidNetworkInformationBackend::setBehindCaptivePortal);
+
+ connect(conman, &AndroidConnectivityManager::transportMediumChanged, this,
+ &QAndroidNetworkInformationBackend::updateTransportMedium);
+}
+
+void QAndroidNetworkInformationBackend::updateTransportMedium(
+ AndroidConnectivityManager::AndroidTransport transport)
+{
+ using AndroidTransport = AndroidConnectivityManager::AndroidTransport;
+ using TransportMedium = QNetworkInformation::TransportMedium;
+ static const auto mapTransport = [](AndroidTransport state) -> TransportMedium {
+ switch (state) {
+ case AndroidTransport::Cellular:
+ return TransportMedium::Cellular;
+ case AndroidTransport::WiFi:
+ return TransportMedium::WiFi;
+ case AndroidTransport::Bluetooth:
+ return TransportMedium::Bluetooth;
+ case AndroidTransport::Ethernet:
+ return TransportMedium::Ethernet;
+ // These are not covered yet (but may be in the future)
+ case AndroidTransport::Usb:
+ case AndroidTransport::LoWPAN:
+ case AndroidTransport::WiFiAware:
+ case AndroidTransport::Unknown:
+ return TransportMedium::Unknown;
+ }
+ };
+
+ setTransportMedium(mapTransport(transport));
}
QT_END_NAMESPACE
diff --git a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
index e88fe7d955..281ad4a2a6 100644
--- a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
+++ b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
@@ -70,6 +70,15 @@ static void behindCaptivePortalChanged(JNIEnv *env, jobject obj, jboolean state)
Q_EMIT androidConnManagerInstance->connManager->captivePortalChanged(state);
}
+static void transportMediumChangedCallback(JNIEnv *env, jobject obj, jobject enumValue)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(obj);
+ const jint value = QJniObject(enumValue).callMethod<jint>("ordinal");
+ const auto transport = static_cast<AndroidConnectivityManager::AndroidTransport>(value);
+ emit androidConnManagerInstance->connManager->transportMediumChanged(transport);
+}
+
AndroidConnectivityManager::AndroidConnectivityManager()
{
if (!registerNatives())
@@ -132,11 +141,16 @@ bool AndroidConnectivityManager::registerNatives()
if (!networkReceiver.isValid())
return false;
+ const QByteArray transportEnumSig =
+ QByteArray("(L") + networkInformationClass + "$Transport;)V";
+
jclass clazz = env->GetObjectClass(networkReceiver.object());
static JNINativeMethod methods[] = {
{ "connectivityChanged", "()V", reinterpret_cast<void *>(networkConnectivityChanged) },
{ "behindCaptivePortalChanged", "(Z)V",
- reinterpret_cast<void *>(behindCaptivePortalChanged) }
+ reinterpret_cast<void *>(behindCaptivePortalChanged) },
+ { "transportMediumChanged", transportEnumSig.data(),
+ reinterpret_cast<void *>(transportMediumChangedCallback) },
};
const bool ret = (env->RegisterNatives(clazz, methods, std::size(methods)) == JNI_OK);
env->DeleteLocalRef(clazz);
diff --git a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
index 14f5aa9b57..790f6f3bd0 100644
--- a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
+++ b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
@@ -51,6 +51,20 @@ class AndroidConnectivityManager : public QObject
public:
enum class AndroidConnectivity { Connected, Unknown, Disconnected };
Q_ENUM(AndroidConnectivity);
+
+ // Keep synchronized with Transport in QtAndroidNetworkInformation.java
+ enum class AndroidTransport {
+ Unknown,
+ Bluetooth,
+ Cellular,
+ Ethernet,
+ LoWPAN,
+ Usb,
+ WiFi,
+ WiFiAware,
+ };
+ Q_ENUM(AndroidTransport);
+
static AndroidConnectivityManager *getInstance();
~AndroidConnectivityManager();
@@ -60,6 +74,7 @@ public:
Q_SIGNALS:
void connectivityChanged();
void captivePortalChanged(bool state);
+ void transportMediumChanged(AndroidTransport transport);
private:
friend struct AndroidConnectivityManagerInstance;