QNetworkInformation backend for Android

Based on the old bearer manager code!

A lot of the old code went away though since it had been deprecated
in the time since it was written.

Pick-to: dev
Task-number: QTBUG-86966
Change-Id: I21a6db1d4ebd8367084355a8e3202f4c05d9dce5
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
Mårten Nordheim 2021-01-26 12:39:11 +01:00
parent 677797929d
commit 8652493529
6 changed files with 520 additions and 0 deletions

View File

@ -9,3 +9,7 @@ endif()
if(APPLE)
add_subdirectory(scnetworkreachability)
endif()
if(ANDROID)
add_subdirectory(android)
endif()

View File

@ -0,0 +1,47 @@
set(java_sources
jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
)
qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend
INCLUDE_JARS ${QT_ANDROID_JAR}
SOURCES ${java_sources}
OUTPUT_DIR "${QT_BUILD_DIR}/jar"
)
install_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend
DESTINATION jar
COMPONENT Devel
)
qt_internal_add_plugin(QAndroidNetworkInformationBackend
OUTPUT_NAME androidnetworkinformationbackend
TYPE networkinformationbackends
DEFAULT_IF ANDROID
SOURCES
qandroidnetworkinformationbackend.cpp
wrapper/androidconnectivitymanager.cpp wrapper/androidconnectivitymanager.h
LIBRARIES
Qt::NetworkPrivate
DEFINES
QT_USE_QSTRINGBUILDER
)
# @todo: androiddeployqt doesn't deploy JARs bundled with plugins, needs fix, temporarily bundle with Network
# QTBUG-90812
set_property(
TARGET
# QAndroidNetworkInformationBackend
Network
APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
jar/Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend.jar
)
# @todo: same as above, but for permissions
set_property(
TARGET
# QAndroidNetworkInformationBackend
Network
APPEND PROPERTY QT_ANDROID_PERMISSIONS
android.permission.ACCESS_NETWORK_STATE
)

View File

@ -0,0 +1,131 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
package org.qtproject.qt.android.networkinformation;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.NetworkRequest;
import android.net.NetworkCapabilities;
import android.net.Network;
public class QtAndroidNetworkInformation {
private static final String LOG_TAG = "QtAndroidNetworkInformation";
private static native void connectivityChanged();
private static QtNetworkInformationCallback m_callback = null;
private static final Object m_lock = new Object();
enum AndroidConnectivity {
Connected, Unknown, Disconnected
}
private static class QtNetworkInformationCallback extends NetworkCallback {
public AndroidConnectivity previousState = null;
QtNetworkInformationCallback() {
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities capabilities) {
AndroidConnectivity s;
if (!capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET))
s = AndroidConnectivity.Disconnected;
else if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED))
s = AndroidConnectivity.Connected;
else
s = AndroidConnectivity.Unknown; // = we _may_ have Internet access
setState(s);
}
private void setState(AndroidConnectivity s) {
if (previousState != s) {
previousState = s;
connectivityChanged();
}
}
@Override
public void onLost(Network network) {
setState(AndroidConnectivity.Disconnected);
}
}
private QtAndroidNetworkInformation() {
}
public static AndroidConnectivity state() {
if (m_callback != null && m_callback.previousState != null)
return m_callback.previousState;
return AndroidConnectivity.Unknown;
}
public static void registerReceiver(final Context context) {
synchronized (m_lock) {
if (m_callback == null) {
ConnectivityManager manager = getConnectivityManager(context);
m_callback = new QtNetworkInformationCallback();
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P)
builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND);
NetworkRequest request = builder.build();
manager.registerNetworkCallback(request, m_callback);
}
}
}
public static void unregisterReceiver(final Context context) {
synchronized (m_lock) {
if (m_callback != null) {
getConnectivityManager(context).unregisterNetworkCallback(m_callback);
m_callback = null;
}
}
}
public static ConnectivityManager getConnectivityManager(final Context context) {
return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
}

View File

@ -0,0 +1,132 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtNetwork/private/qnetworkinformation_p.h>
#include "wrapper/androidconnectivitymanager.h"
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcNetInfoAndroid)
Q_LOGGING_CATEGORY(lcNetInfoAndroid, "qt.network.info.android");
static const QString backendName = QStringLiteral("android");
class QAndroidNetworkInformationBackend : public QNetworkInformationBackend
{
Q_OBJECT
public:
QAndroidNetworkInformationBackend();
~QAndroidNetworkInformationBackend() { m_valid = false; }
QString name() const override { return backendName; }
QNetworkInformation::Features featuresSupported() const override
{
return featuresSupportedStatic();
}
static QNetworkInformation::Features featuresSupportedStatic()
{
return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability);
}
bool isValid() { return m_valid; }
private:
Q_DISABLE_COPY_MOVE(QAndroidNetworkInformationBackend);
bool m_valid = false;
};
class QAndroidNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
Q_INTERFACES(QNetworkInformationBackendFactory)
public:
QAndroidNetworkInformationBackendFactory() = default;
~QAndroidNetworkInformationBackendFactory() = default;
QString name() const override { return backendName; }
QNetworkInformation::Features featuresSupported() const override
{
return QAndroidNetworkInformationBackend::featuresSupportedStatic();
}
QNetworkInformationBackend *
create(QNetworkInformation::Features requiredFeatures) const override
{
if ((requiredFeatures & featuresSupported()) != requiredFeatures)
return nullptr;
auto backend = new QAndroidNetworkInformationBackend();
if (!backend->isValid())
delete std::exchange(backend, nullptr);
return backend;
}
private:
Q_DISABLE_COPY_MOVE(QAndroidNetworkInformationBackendFactory);
};
QAndroidNetworkInformationBackend::QAndroidNetworkInformationBackend()
{
auto conman = AndroidConnectivityManager::getInstance();
if (!conman)
return;
m_valid = true;
setReachability(QNetworkInformation::Reachability::Unknown);
connect(conman, &AndroidConnectivityManager::connectivityChanged, this, [this, conman]() {
static const auto mapState = [](AndroidConnectivityManager::AndroidConnectivity state) {
switch (state) {
case AndroidConnectivityManager::AndroidConnectivity::Connected:
return QNetworkInformation::Reachability::Online;
case AndroidConnectivityManager::AndroidConnectivity::Disconnected:
return QNetworkInformation::Reachability::Disconnected;
case AndroidConnectivityManager::AndroidConnectivity::Unknown:
default:
return QNetworkInformation::Reachability::Unknown;
}
};
setReachability(mapState(conman->networkConnectivity()));
});
}
QT_END_NAMESPACE
#include "qandroidnetworkinformationbackend.moc"

View File

@ -0,0 +1,132 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "androidconnectivitymanager.h"
#include <QtCore/private/qjnihelpers_p.h>
#include <QtCore/qjnienvironment.h>
QT_BEGIN_NAMESPACE
struct AndroidConnectivityManagerInstance
{
AndroidConnectivityManagerInstance() : connManager(new AndroidConnectivityManager) { }
std::unique_ptr<AndroidConnectivityManager> connManager = nullptr;
};
Q_GLOBAL_STATIC(AndroidConnectivityManagerInstance, androidConnManagerInstance)
static const char networkInformationClass[] =
"org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation";
static void networkConnectivityChanged()
{
Q_EMIT androidConnManagerInstance->connManager->connectivityChanged();
}
AndroidConnectivityManager::AndroidConnectivityManager()
{
if (!registerNatives())
return;
m_connectivityManager = QJniObject::callStaticObjectMethod(
networkInformationClass, "getConnectivityManager",
"(Landroid/content/Context;)Landroid/net/ConnectivityManager;",
QtAndroidPrivate::context());
if (!m_connectivityManager.isValid())
return;
QJniObject::callStaticMethod<void>(networkInformationClass, "registerReceiver",
"(Landroid/content/Context;)V", QtAndroidPrivate::context());
}
AndroidConnectivityManager *AndroidConnectivityManager::getInstance()
{
if (!androidConnManagerInstance())
return nullptr;
return androidConnManagerInstance->connManager->isValid()
? androidConnManagerInstance->connManager.get()
: nullptr;
}
AndroidConnectivityManager::~AndroidConnectivityManager()
{
QJniObject::callStaticMethod<void>(networkInformationClass, "unregisterReceiver",
"(Landroid/content/Context;)V", QtAndroidPrivate::context());
}
AndroidConnectivityManager::AndroidConnectivity AndroidConnectivityManager::networkConnectivity()
{
QJniEnvironment env;
QJniObject networkReceiver(networkInformationClass);
jclass clazz = env->GetObjectClass(networkReceiver.object());
static const QByteArray functionSignature =
QByteArray(QByteArray("()L") + networkInformationClass + "$AndroidConnectivity;");
QJniObject enumObject =
QJniObject::callStaticObjectMethod(clazz, "state", functionSignature.data());
if (!enumObject.isValid())
return AndroidConnectivityManager::AndroidConnectivity::Unknown;
QJniObject enumName = enumObject.callObjectMethod<jstring>("name");
if (!enumName.isValid())
return AndroidConnectivityManager::AndroidConnectivity::Unknown;
QString name = enumName.toString();
if (name == u"Connected")
return AndroidConnectivity::Connected;
if (name == u"Disconnected")
return AndroidConnectivity::Disconnected;
return AndroidConnectivity::Unknown;
}
bool AndroidConnectivityManager::registerNatives()
{
QJniEnvironment env;
QJniObject networkReceiver(networkInformationClass);
if (!networkReceiver.isValid())
return false;
jclass clazz = env->GetObjectClass(networkReceiver.object());
static JNINativeMethod method = { "connectivityChanged", "()V",
reinterpret_cast<void *>(networkConnectivityChanged) };
const bool ret = (env->RegisterNatives(clazz, &method, 1) == JNI_OK);
env->DeleteLocalRef(clazz);
return ret;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef ANDROIDCONNECTIVITYMANAGER_H
#define ANDROIDCONNECTIVITYMANAGER_H
#include <QObject>
#include <QtCore/qjniobject.h>
QT_BEGIN_NAMESPACE
class AndroidConnectivityManager : public QObject
{
Q_OBJECT
public:
enum class AndroidConnectivity { Connected, Unknown, Disconnected };
Q_ENUM(AndroidConnectivity);
static AndroidConnectivityManager *getInstance();
~AndroidConnectivityManager();
AndroidConnectivity networkConnectivity();
inline bool isValid() const { return m_connectivityManager.isValid(); }
Q_SIGNALS:
void connectivityChanged();
private:
friend struct AndroidConnectivityManagerInstance;
AndroidConnectivityManager();
bool registerNatives();
QJniObject m_connectivityManager;
Q_DISABLE_COPY_MOVE(AndroidConnectivityManager);
};
QT_END_NAMESPACE
#endif // ANDROIDCONNECTIVITYMANAGER_H