forked from apache/cordova-plugin-network-information
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathNetworkManager.java
More file actions
executable file
·399 lines (356 loc) · 15.8 KB
/
NetworkManager.java
File metadata and controls
executable file
·399 lines (356 loc) · 15.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova.networkinformation;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.telephony.ServiceState;
import androidx.core.app.ActivityCompat;
import java.util.Locale;
import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE;
public class NetworkManager extends CordovaPlugin {
public static int NOT_REACHABLE = 0;
public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
public static int REACHABLE_VIA_WIFI_NETWORK = 2;
public static final String WIFI = "wifi";
public static final String WIMAX = "wimax";
// mobile
public static final String MOBILE = "mobile";
// Android L calls this Cellular, because I have no idea!
public static final String CELLULAR = "cellular";
// 2G network types
public static final String TWO_G = "2g";
public static final String GSM = "gsm";
public static final String GPRS = "gprs";
public static final String EDGE = "edge";
// 3G network types
public static final String THREE_G = "3g";
public static final String CDMA = "cdma";
public static final String UMTS = "umts";
public static final String HSPA = "hspa";
public static final String HSUPA = "hsupa";
public static final String HSDPA = "hsdpa";
public static final String ONEXRTT = "1xrtt";
public static final String EHRPD = "ehrpd";
// 4G network types
public static final String FOUR_G = "4g";
public static final String LTE = "lte";
public static final String UMB = "umb";
public static final String HSPA_PLUS = "hspa+";
// 5G network types
public static final String FIVE_G = "5g";
public static final String NR = "nr";
// return type
public static final String TYPE_UNKNOWN = "unknown";
public static final String TYPE_ETHERNET = "ethernet";
public static final String TYPE_ETHERNET_SHORT = "eth";
public static final String TYPE_WIFI = "wifi";
public static final String TYPE_2G = "2g";
public static final String TYPE_3G = "3g";
public static final String TYPE_4G = "4g";
public static final String TYPE_5G = "5g";
public static final String TYPE_NONE = "none";
public static final int NETWORK_TYPE_NR = 20;
public static final int NETWORK_TYPE_LTE_CA = 19;
private static final String LOG_TAG = "NetworkManager";
private CallbackContext connectionCallbackContext;
ConnectivityManager sockMan;
BroadcastReceiver receiver;
private String lastTypeOfNetwork = TYPE_UNKNOWN;
TelephonyManager telMan;
private static boolean isNrAvailable;
/**
* Sets the context of the Command. This can then be used to do things like
* get file paths associated with the Activity.
*
* @param cordova The context of the main Activity.
* @param webView The CordovaWebView Cordova is running in.
*/
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
this.sockMan = (ConnectivityManager) cordova.getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
this.telMan = (TelephonyManager) cordova.getActivity().getSystemService(Context.TELEPHONY_SERVICE);
this.telMan.listen( phoneStateListener, LISTEN_SERVICE_STATE);
this.connectionCallbackContext = null;
this.registerConnectivityActionReceiver();
}
/**
* Executes the request and returns PluginResult.
*
* @param action The action to execute.
* @param args JSONArry of arguments for the plugin.
* @param callbackContext The callback id used when calling back into JavaScript.
* @return True if the action was valid, false otherwise.
*/
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
if (action.equals("getConnectionInfo")) {
this.connectionCallbackContext = callbackContext;
NetworkInfo info = sockMan.getActiveNetworkInfo();
String connectionType = this.getTypeOfNetworkFallbackToTypeNoneIfNotConnected(info);
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, connectionType);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
return true;
}
return false;
}
/**
* Stop network receiver.
*/
public void onDestroy() {
this.unregisterReceiver();
}
@Override
public void onPause(boolean multitasking) {
this.unregisterReceiver();
}
@Override
public void onResume(boolean multitasking) {
super.onResume(multitasking);
this.unregisterReceiver();
this.registerConnectivityActionReceiver();
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
private void registerConnectivityActionReceiver() {
// We need to listen to connectivity events to update navigator.connection
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
if (this.receiver == null) {
this.receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// (The null check is for the ARM Emulator, please use Intel Emulator for better results)
if (NetworkManager.this.webView != null) {
updateConnectionInfo(sockMan.getActiveNetworkInfo(), true);
}
String connectionType;
if (NetworkManager.this.lastTypeOfNetwork == null) {
connectionType = TYPE_NONE;
} else {
connectionType = NetworkManager.this.lastTypeOfNetwork;
}
// Lollipop always returns false for the EXTRA_NO_CONNECTIVITY flag => fix for Android M and above.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && TYPE_NONE.equals(connectionType)) {
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
LOG.d(LOG_TAG, "Intent no connectivity: " + noConnectivity);
if(noConnectivity) {
LOG.d(LOG_TAG, "Really no connectivity");
} else {
LOG.d(LOG_TAG, "!!! Switching to unknown, Intent states there is a connectivity.");
sendUpdate(TYPE_UNKNOWN);
}
}
}
};
}
webView.getContext().registerReceiver(this.receiver, intentFilter);
}
private void unregisterReceiver() {
if (this.receiver != null) {
try {
webView.getContext().unregisterReceiver(this.receiver);
} catch (Exception e) {
LOG.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
} finally {
receiver = null;
}
}
}
/**
* Updates the JavaScript side whenever the connection changes
*
* @param info the current active network info
* @return
*/
private void updateConnectionInfo(NetworkInfo info, boolean forceRefresh) {
// send update to javascript "navigator.connection"
// Jellybean sends its own info
String currentNetworkType = this.getTypeOfNetworkFallbackToTypeNoneIfNotConnected(info, forceRefresh);
if (currentNetworkType.equals(this.lastTypeOfNetwork)) {
LOG.d(LOG_TAG, "Networkinfo state didn't change, there is no event propagated to the JavaScript side.");
} else {
sendUpdate(currentNetworkType);
this.lastTypeOfNetwork = currentNetworkType;
}
}
/**
* Gets the type of network connection of the NetworkInfo input
*
* @param info the current active network info
* @return type the type of network
*/
private String getTypeOfNetworkFallbackToTypeNoneIfNotConnected(NetworkInfo info, Boolean forceRefresh) {
// the info might still be null in this part of the code
String type;
if (info != null) {
// If we are not connected to any network set type to none
if (!info.isConnected()) {
type = TYPE_NONE;
} else {
if(lastTypeOfNetwork.equals(TYPE_UNKNOWN) || forceRefresh) {
type = getType(info);
} else {
type = lastTypeOfNetwork;
}
}
} else {
type = TYPE_NONE;
}
LOG.d(LOG_TAG, "Connection Type: " + type);
return type;
}
private String getTypeOfNetworkFallbackToTypeNoneIfNotConnected(NetworkInfo info) {
// the info might still be null in this part of the code
return this.getTypeOfNetworkFallbackToTypeNoneIfNotConnected(info, false);
}
/**
* Create a new plugin result and send it back to JavaScript
*
* @param connection the network info to set as navigator.connection
*/
private void sendUpdate(String type) {
if (connectionCallbackContext != null) {
PluginResult result = new PluginResult(PluginResult.Status.OK, type);
result.setKeepCallback(true);
connectionCallbackContext.sendPluginResult(result);
}
webView.postMessage("networkconnection", type);
}
/**
* Determine the type of connection
*
* @param info the network info so we can determine connection type.
* @return the type of network we are on
*/
private String getType(NetworkInfo info) {
String type = info.getTypeName().toLowerCase(Locale.US);
LOG.d(LOG_TAG, "toLower : " + type);
if (type.equals(WIFI)) {
return TYPE_WIFI;
} else if (type.toLowerCase().equals(TYPE_ETHERNET) || type.toLowerCase().startsWith(TYPE_ETHERNET_SHORT)) {
return TYPE_ETHERNET;
} else if (type.equals(MOBILE) || type.equals(CELLULAR)) {
return getMobileType(info);
}
return TYPE_UNKNOWN;
}
/**
* Determine the subtype of mobile connection
*
* @param info the network info so we can determine connection type.
* @return the type of mobile network we are on
*/
private String getMobileType(NetworkInfo info){
int subTypeId = info.getSubtype();
String subTypeName = info.getSubtypeName().toLowerCase(Locale.US);
if(is2G(subTypeId, subTypeName)){
return TYPE_2G;
} else if(is3G(subTypeId, subTypeName)) {
return TYPE_3G;
} else if(is4G(subTypeId, subTypeName)) {
if(isNrAvailable){ // if is LTE network could be 5g if NR is available
return TYPE_5G;
}
return TYPE_4G;
} else if(is5G(subTypeId, subTypeName)) {
return TYPE_5G;
}
return TYPE_UNKNOWN;
}
private boolean is2G(int type, String name){
return type == TelephonyManager.NETWORK_TYPE_GPRS ||
type == TelephonyManager.NETWORK_TYPE_EDGE ||
type == TelephonyManager.NETWORK_TYPE_CDMA ||
type == TelephonyManager.NETWORK_TYPE_1xRTT ||
type == TelephonyManager.NETWORK_TYPE_IDEN || // api< 8: replace by 11
type == TelephonyManager.NETWORK_TYPE_GSM || // api<25: replace by 16
name.equals(GSM) ||
name.equals(GPRS) ||
name.equals(EDGE) ||
name.equals(TWO_G);
}
private boolean is3G(int type, String name){
return type == TelephonyManager.NETWORK_TYPE_UMTS ||
type == TelephonyManager.NETWORK_TYPE_EVDO_0 ||
type == TelephonyManager.NETWORK_TYPE_EVDO_A ||
type == TelephonyManager.NETWORK_TYPE_HSDPA ||
type == TelephonyManager.NETWORK_TYPE_HSUPA ||
type == TelephonyManager.NETWORK_TYPE_HSPA ||
type == TelephonyManager.NETWORK_TYPE_EVDO_B || // api< 9: replace by 12
type == TelephonyManager.NETWORK_TYPE_EHRPD || // api<11: replace by 14
type == TelephonyManager.NETWORK_TYPE_HSPAP || // api<13: replace by 15
type == TelephonyManager.NETWORK_TYPE_TD_SCDMA || // api<25: replace by 17
name.startsWith(CDMA) ||
name.equals(UMTS) ||
name.equals(ONEXRTT) ||
name.equals(EHRPD) ||
name.equals(HSUPA) ||
name.equals(HSDPA) ||
name.equals(HSPA) ||
name.equals(THREE_G);
}
private boolean is4G(int type, String name){
return type == TelephonyManager.NETWORK_TYPE_LTE && name.equals(FOUR_G) || // api<11: replace by 13
type == TelephonyManager.NETWORK_TYPE_IWLAN || // api<25: replace by 18
type == NETWORK_TYPE_LTE_CA || // LTE_CA
name.equals(LTE) ||
name.equals(UMB) ||
name.equals(HSPA_PLUS) ||
name.equals(FOUR_G);
}
private boolean is5G(int type, String name){
return type == TelephonyManager.NETWORK_TYPE_LTE && name.equals(FIVE_G) || // api<11: replace by 13
type == NETWORK_TYPE_NR || // api<25: replace by 18
name.equals(FIVE_G) ||
name.equals(NR);
}
private PhoneStateListener phoneStateListener = new PhoneStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
NetworkManager.this.isNrAvailable = isNrAvailable(serviceState);
updateConnectionInfo(sockMan.getActiveNetworkInfo(), true);
}
};
/**
* Determine if NR network is available, for detect sdk < 30
*
* @param serviceState the ServiceState from PhoneStateListener
* @return flag boolean if NR is available
*/
private boolean isNrAvailable(ServiceState serviceState ){
String stateStr = serviceState.toString();
return stateStr.contains("nrState=CONNECTED") || stateStr.contains("isNrAvailable = true");
}
}