1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "androidconnectivitymanager.h"
41 #include <QtCore/private/qjni_p.h>
42 #include <QtCore/private/qjnihelpers_p.h>
43
44 QT_BEGIN_NAMESPACE
45
exceptionCheckAndClear(JNIEnv * env)46 static inline bool exceptionCheckAndClear(JNIEnv *env)
47 {
48 if (!env->ExceptionCheck())
49 return false;
50
51 #ifdef QT_DEBUG
52 env->ExceptionDescribe();
53 #endif // QT_DEBUG
54 env->ExceptionClear();
55
56 return true;
57 }
58
59 struct AndroidConnectivityManagerInstance
60 {
AndroidConnectivityManagerInstanceAndroidConnectivityManagerInstance61 AndroidConnectivityManagerInstance()
62 : connManager(new AndroidConnectivityManager)
63 { }
~AndroidConnectivityManagerInstanceAndroidConnectivityManagerInstance64 ~AndroidConnectivityManagerInstance()
65 {
66 delete connManager;
67 }
68
69 AndroidConnectivityManager* connManager;
70 };
71
72 Q_GLOBAL_STATIC(AndroidConnectivityManagerInstance, androidConnManagerInstance)
73
74 static const char networkReceiverClass[] = "org/qtproject/qt5/android/bearer/QtNetworkReceiver";
75 static const char trafficStatsClass[] = "android/net/TrafficStats";
76
77 /**
78 * Returns the number of bytes transmitted over the mobile network since last device boot.
79 */
getMobileTxBytes()80 qint64 AndroidTrafficStats::getMobileTxBytes()
81 {
82 return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass,
83 "getMobileTxBytes",
84 "()J");
85 }
86
87 /**
88 * Returns the number of bytes received over the mobile network since last device boot.
89 */
getMobileRxBytes()90 qint64 AndroidTrafficStats::getMobileRxBytes()
91 {
92 return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass,
93 "getMobileRxBytes",
94 "()J");
95 }
96
97 /**
98 * Returns the total transmitted bytes since last device boot.
99 */
getTotalTxBytes()100 qint64 AndroidTrafficStats::getTotalTxBytes()
101 {
102 return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass,
103 "getTotalTxBytes",
104 "()J");
105 }
106
107 /**
108 * Returns the total received bytes since last device boot.
109 */
getTotalRxBytes()110 qint64 AndroidTrafficStats::getTotalRxBytes()
111 {
112 return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass,
113 "getTotalRxBytes",
114 "()J");
115 }
116
isTrafficStatsSupported()117 bool AndroidTrafficStats::isTrafficStatsSupported()
118 {
119 // Before API level 18 DataStatistics might not be supported, so make sure that we get something
120 // else then -1 from from getXXBytes().
121 return (AndroidTrafficStats::getMobileRxBytes() != -1
122 && AndroidTrafficStats::getTotalRxBytes() != -1);
123 }
124
stateForName(const QString & stateName)125 static AndroidNetworkInfo::NetworkState stateForName(const QString &stateName)
126 {
127 if (stateName == QLatin1String("CONNECTED"))
128 return AndroidNetworkInfo::Connected;
129 else if (stateName == QLatin1String("CONNECTING"))
130 return AndroidNetworkInfo::Connecting;
131 else if (stateName == QLatin1String("DISCONNECTED"))
132 return AndroidNetworkInfo::Disconnected;
133 else if (stateName == QLatin1String("DISCONNECTING"))
134 return AndroidNetworkInfo::Disconnecting;
135 else if (stateName == QLatin1String("SUSPENDED"))
136 return AndroidNetworkInfo::Suspended;
137
138 return AndroidNetworkInfo::UnknownState;
139 }
140
getDetailedState() const141 AndroidNetworkInfo::NetworkState AndroidNetworkInfo::getDetailedState() const
142 {
143 QJNIObjectPrivate enumObject = m_networkInfo.callObjectMethod("getDetailedState",
144 "()Landroid/net/NetworkInfo$DetailedState;");
145 if (!enumObject.isValid())
146 return UnknownState;
147
148 QJNIObjectPrivate enumName = enumObject.callObjectMethod<jstring>("name");
149 if (!enumName.isValid())
150 return UnknownState;
151
152 return stateForName(enumName.toString());
153 }
154
getExtraInfo() const155 QString AndroidNetworkInfo::getExtraInfo() const
156 {
157 QJNIObjectPrivate extraInfo = m_networkInfo.callObjectMethod<jstring>("getExtraInfo");
158 if (!extraInfo.isValid())
159 return QString();
160
161 return extraInfo.toString();
162 }
163
getReason() const164 QString AndroidNetworkInfo::getReason() const
165 {
166 QJNIObjectPrivate reason = m_networkInfo.callObjectMethod<jstring>("getReason");
167 if (!reason.isValid())
168 return QString();
169
170 return reason.toString();
171 }
172
getState() const173 AndroidNetworkInfo::NetworkState AndroidNetworkInfo::getState() const
174 {
175 QJNIObjectPrivate enumObject = m_networkInfo.callObjectMethod("getState",
176 "()Landroid/net/NetworkInfo$State;");
177 if (!enumObject.isValid())
178 return UnknownState;
179
180 QJNIObjectPrivate enumName = enumObject.callObjectMethod<jstring>("name");
181 if (!enumName.isValid())
182 return UnknownState;
183
184 return stateForName(enumName.toString());
185 }
186
getSubtype() const187 AndroidNetworkInfo::NetworkSubType AndroidNetworkInfo::getSubtype() const
188 {
189 return AndroidNetworkInfo::NetworkSubType(m_networkInfo.callMethod<jint>("getSubtype"));
190 }
191
getSubtypeName() const192 QString AndroidNetworkInfo::getSubtypeName() const
193 {
194 QJNIObjectPrivate subtypeName = m_networkInfo.callObjectMethod<jstring>("getSubtypeName");
195 if (!subtypeName.isValid())
196 return QString();
197
198 return subtypeName.toString();
199 }
200
getType() const201 AndroidNetworkInfo::NetworkType AndroidNetworkInfo::getType() const
202 {
203 return AndroidNetworkInfo::NetworkType(m_networkInfo.callMethod<jint>("getType"));
204 }
205
getTypeName() const206 QString AndroidNetworkInfo::getTypeName() const
207 {
208 QJNIObjectPrivate typeName = m_networkInfo.callObjectMethod<jstring>("getTypeName");
209 if (!typeName.isValid())
210 return QString();
211
212 return typeName.toString();
213 }
214
isAvailable() const215 bool AndroidNetworkInfo::isAvailable() const
216 {
217 return m_networkInfo.callMethod<jboolean>("isAvailable");
218 }
219
isConnected() const220 bool AndroidNetworkInfo::isConnected() const
221 {
222 return m_networkInfo.callMethod<jboolean>("isConnected");
223 }
224
isConnectedOrConnecting() const225 bool AndroidNetworkInfo::isConnectedOrConnecting() const
226 {
227 return m_networkInfo.callMethod<jboolean>("isConnectedOrConnecting");
228 }
229
isFailover() const230 bool AndroidNetworkInfo::isFailover() const
231 {
232 return m_networkInfo.callMethod<jboolean>("isFailover");
233 }
234
isRoaming() const235 bool AndroidNetworkInfo::isRoaming() const
236 {
237 return m_networkInfo.callMethod<jboolean>("isRoaming");
238 }
239
isValid() const240 bool AndroidNetworkInfo::isValid() const
241 {
242 return m_networkInfo.isValid();
243 }
244
AndroidConnectivityManager()245 AndroidConnectivityManager::AndroidConnectivityManager()
246 {
247 QJNIEnvironmentPrivate env;
248 if (!registerNatives(env))
249 return;
250
251 m_connectivityManager = QJNIObjectPrivate::callStaticObjectMethod(networkReceiverClass,
252 "getConnectivityManager",
253 "(Landroid/content/Context;)Landroid/net/ConnectivityManager;",
254 QtAndroidPrivate::context());
255 if (!m_connectivityManager.isValid())
256 return;
257
258 QJNIObjectPrivate::callStaticMethod<void>(networkReceiverClass,
259 "registerReceiver",
260 "(Landroid/content/Context;)V",
261 QtAndroidPrivate::context());
262 }
263
getInstance()264 AndroidConnectivityManager *AndroidConnectivityManager::getInstance()
265 {
266 return androidConnManagerInstance->connManager->isValid()
267 ? androidConnManagerInstance->connManager
268 : 0;
269 }
270
~AndroidConnectivityManager()271 AndroidConnectivityManager::~AndroidConnectivityManager()
272 {
273 QJNIObjectPrivate::callStaticMethod<void>(networkReceiverClass,
274 "unregisterReceiver",
275 "(Landroid/content/Context;)V",
276 QtAndroidPrivate::context());
277 }
278
getActiveNetworkInfo() const279 AndroidNetworkInfo AndroidConnectivityManager::getActiveNetworkInfo() const
280 {
281 QJNIObjectPrivate networkInfo = m_connectivityManager.callObjectMethod("getActiveNetworkInfo",
282 "()Landroid/net/NetworkInfo;");
283 return networkInfo;
284 }
285
getAllNetworkInfo() const286 QList<AndroidNetworkInfo> AndroidConnectivityManager::getAllNetworkInfo() const
287 {
288 QJNIEnvironmentPrivate env;
289 QJNIObjectPrivate objArray = m_connectivityManager.callObjectMethod("getAllNetworkInfo",
290 "()[Landroid/net/NetworkInfo;");
291 QList<AndroidNetworkInfo> list;
292 if (!objArray.isValid())
293 return list;
294
295 const jsize length = env->GetArrayLength(static_cast<jarray>(objArray.object()));
296 if (exceptionCheckAndClear(env))
297 return list;
298
299 for (int i = 0; i != length; ++i) {
300 jobject lref = env->GetObjectArrayElement(static_cast<jobjectArray>(objArray.object()), i);
301 if (exceptionCheckAndClear(env))
302 break;
303
304 list << AndroidNetworkInfo(QJNIObjectPrivate::fromLocalRef(lref));
305 }
306
307 return list;
308 }
309
getBackgroundDataSetting() const310 bool AndroidConnectivityManager::getBackgroundDataSetting() const
311 {
312 return m_connectivityManager.callMethod<jboolean>("getBackgroundDataSetting");
313 }
314
getNetworkInfo(int networkType) const315 AndroidNetworkInfo AndroidConnectivityManager::getNetworkInfo(int networkType) const
316 {
317 QJNIObjectPrivate networkInfo = m_connectivityManager.callObjectMethod("getNetworkInfo",
318 "(I)Landroid/net/NetworkInfo;",
319 networkType);
320 return networkInfo;
321 }
322
getNetworkPreference() const323 int AndroidConnectivityManager::getNetworkPreference() const
324 {
325 return m_connectivityManager.callMethod<jint>("getNetworkPreference");
326 }
327
isActiveNetworkMetered() const328 bool AndroidConnectivityManager::isActiveNetworkMetered() const
329 {
330 return m_connectivityManager.callMethod<jboolean>("isActiveNetworkMetered");
331 }
332
isNetworkTypeValid(int networkType)333 bool AndroidConnectivityManager::isNetworkTypeValid(int networkType)
334 {
335 return QJNIObjectPrivate::callStaticMethod<jboolean>("android/net/ConnectivityManager",
336 "isNetworkTypeValid",
337 "(I)Z",
338 networkType);
339 }
340
requestRouteToHost(int networkType,int hostAddress)341 bool AndroidConnectivityManager::requestRouteToHost(int networkType, int hostAddress)
342 {
343 return m_connectivityManager.callMethod<jboolean>("requestRouteToHost", "(II)Z", networkType, hostAddress);
344 }
345
setNetworkPreference(int preference)346 void AndroidConnectivityManager::setNetworkPreference(int preference)
347 {
348 m_connectivityManager.callMethod<void>("setNetworkPreference", "(I)V", preference);
349 }
350
startUsingNetworkFeature(int networkType,const QString & feature)351 int AndroidConnectivityManager::startUsingNetworkFeature(int networkType, const QString &feature)
352 {
353 QJNIObjectPrivate jfeature = QJNIObjectPrivate::fromString(feature);
354 return m_connectivityManager.callMethod<jint>("startUsingNetworkFeature",
355 "(ILjava/lang/String;)I",
356 networkType,
357 jfeature.object());
358 }
359
stopUsingNetworkFeature(int networkType,const QString & feature)360 int AndroidConnectivityManager::stopUsingNetworkFeature(int networkType, const QString &feature)
361 {
362 QJNIObjectPrivate jfeature = QJNIObjectPrivate::fromString(feature);
363 return m_connectivityManager.callMethod<jint>("stopUsingNetworkFeature",
364 "(ILjava/lang/String;)I",
365 networkType,
366 jfeature.object());
367 }
368
activeNetworkInfoChanged()369 static void activeNetworkInfoChanged()
370 {
371 Q_EMIT androidConnManagerInstance->connManager->activeNetworkChanged();
372 }
373
registerNatives(JNIEnv * env)374 bool AndroidConnectivityManager::registerNatives(JNIEnv *env)
375 {
376 QJNIObjectPrivate networkReceiver(networkReceiverClass);
377 if (!networkReceiver.isValid())
378 return false;
379
380 jclass clazz = env->GetObjectClass(networkReceiver.object());
381 static JNINativeMethod method = {"activeNetworkInfoChanged", "()V", reinterpret_cast<void *>(activeNetworkInfoChanged)};
382 const bool ret = (env->RegisterNatives(clazz, &method, 1) == JNI_OK);
383 env->DeleteLocalRef(clazz);
384 return ret;
385 }
386
387 QT_END_NAMESPACE
388