Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: webrtc/api/android/java/src/org/webrtc/NetworkMonitorAutoDetect.java

Issue 2547483003: Move /webrtc/api/android files to /webrtc/sdk/android (Closed)
Patch Set: Move to api folder under Android instead of src Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 package org.webrtc;
12
13 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
14 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
15
16 import android.Manifest.permission;
17 import android.annotation.SuppressLint;
18 import android.content.BroadcastReceiver;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.IntentFilter;
22 import android.net.ConnectivityManager;
23 import android.net.ConnectivityManager.NetworkCallback;
24 import android.net.LinkAddress;
25 import android.net.LinkProperties;
26 import android.net.Network;
27 import android.net.NetworkCapabilities;
28 import android.net.NetworkInfo;
29 import android.net.NetworkRequest;
30 import android.net.wifi.WifiInfo;
31 import android.net.wifi.WifiManager;
32 import android.os.Build;
33 import android.telephony.TelephonyManager;
34
35 import java.util.ArrayList;
36 import java.util.List;
37
38 /**
39 * Borrowed from Chromium's
40 * src/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.jav a
41 *
42 * Used by the NetworkMonitor to listen to platform changes in connectivity.
43 * Note that use of this class requires that the app have the platform
44 * ACCESS_NETWORK_STATE permission.
45 */
46 public class NetworkMonitorAutoDetect extends BroadcastReceiver {
47 public static enum ConnectionType {
48 CONNECTION_UNKNOWN,
49 CONNECTION_ETHERNET,
50 CONNECTION_WIFI,
51 CONNECTION_4G,
52 CONNECTION_3G,
53 CONNECTION_2G,
54 CONNECTION_UNKNOWN_CELLULAR,
55 CONNECTION_BLUETOOTH,
56 CONNECTION_NONE
57 }
58
59 public static class IPAddress {
60 public final byte[] address;
61 public IPAddress(byte[] address) {
62 this.address = address;
63 }
64 }
65
66 /** Java version of NetworkMonitor.NetworkInformation */
67 public static class NetworkInformation {
68 public final String name;
69 public final ConnectionType type;
70 public final long handle;
71 public final IPAddress[] ipAddresses;
72 public NetworkInformation(
73 String name, ConnectionType type, long handle, IPAddress[] addresses) {
74 this.name = name;
75 this.type = type;
76 this.handle = handle;
77 this.ipAddresses = addresses;
78 }
79 };
80
81 static class NetworkState {
82 private final boolean connected;
83 // Defined from ConnectivityManager.TYPE_XXX for non-mobile; for mobile, it is
84 // further divided into 2G, 3G, or 4G from the subtype.
85 private final int type;
86 // Defined from NetworkInfo.subtype, which is one of the TelephonyManager.NE TWORK_TYPE_XXXs.
87 // Will be useful to find the maximum bandwidth.
88 private final int subtype;
89
90 public NetworkState(boolean connected, int type, int subtype) {
91 this.connected = connected;
92 this.type = type;
93 this.subtype = subtype;
94 }
95
96 public boolean isConnected() {
97 return connected;
98 }
99
100 public int getNetworkType() {
101 return type;
102 }
103
104 public int getNetworkSubType() {
105 return subtype;
106 }
107 }
108 /**
109 * The methods in this class get called when the network changes if the callba ck
110 * is registered with a proper network request. It is only available in Androi d Lollipop
111 * and above.
112 */
113 @SuppressLint("NewApi")
114 private class SimpleNetworkCallback extends NetworkCallback {
115 @Override
116 public void onAvailable(Network network) {
117 Logging.d(TAG, "Network becomes available: " + network.toString());
118 onNetworkChanged(network);
119 }
120
121 @Override
122 public void onCapabilitiesChanged(Network network, NetworkCapabilities netwo rkCapabilities) {
123 // A capabilities change may indicate the ConnectionType has changed,
124 // so forward the new NetworkInformation along to the observer.
125 Logging.d(TAG, "capabilities changed: " + networkCapabilities.toString());
126 onNetworkChanged(network);
127 }
128
129 @Override
130 public void onLinkPropertiesChanged(Network network, LinkProperties linkProp erties) {
131 // A link property change may indicate the IP address changes.
132 // so forward the new NetworkInformation to the observer.
133 Logging.d(TAG, "link properties changed: " + linkProperties.toString());
134 onNetworkChanged(network);
135 }
136
137 @Override
138 public void onLosing(Network network, int maxMsToLive) {
139 // Tell the network is going to lose in MaxMsToLive milliseconds.
140 // We may use this signal later.
141 Logging.d(
142 TAG, "Network " + network.toString() + " is about to lose in " + maxMs ToLive + "ms");
143 }
144
145 @Override
146 public void onLost(Network network) {
147 Logging.d(TAG, "Network " + network.toString() + " is disconnected");
148 observer.onNetworkDisconnect(networkToNetId(network));
149 }
150
151 private void onNetworkChanged(Network network) {
152 NetworkInformation networkInformation = connectivityManagerDelegate.networ kToInfo(network);
153 if (networkInformation != null) {
154 observer.onNetworkConnect(networkInformation);
155 }
156 }
157 }
158
159 /** Queries the ConnectivityManager for information about the current connecti on. */
160 static class ConnectivityManagerDelegate {
161 /**
162 * Note: In some rare Android systems connectivityManager is null. We hand le that
163 * gracefully below.
164 */
165 private final ConnectivityManager connectivityManager;
166
167 ConnectivityManagerDelegate(Context context) {
168 connectivityManager =
169 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SE RVICE);
170 }
171
172 // For testing.
173 ConnectivityManagerDelegate() {
174 // All the methods below should be overridden.
175 connectivityManager = null;
176 }
177
178 /**
179 * Returns connection type and status information about the current
180 * default network.
181 */
182 NetworkState getNetworkState() {
183 if (connectivityManager == null) {
184 return new NetworkState(false, -1, -1);
185 }
186 return getNetworkState(connectivityManager.getActiveNetworkInfo());
187 }
188
189 /**
190 * Returns connection type and status information about |network|.
191 * Only callable on Lollipop and newer releases.
192 */
193 @SuppressLint("NewApi")
194 NetworkState getNetworkState(Network network) {
195 if (connectivityManager == null) {
196 return new NetworkState(false, -1, -1);
197 }
198 return getNetworkState(connectivityManager.getNetworkInfo(network));
199 }
200
201 /**
202 * Returns connection type and status information gleaned from networkInfo.
203 */
204 NetworkState getNetworkState(NetworkInfo networkInfo) {
205 if (networkInfo == null || !networkInfo.isConnected()) {
206 return new NetworkState(false, -1, -1);
207 }
208 return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtyp e());
209 }
210
211 /**
212 * Returns all connected networks.
213 * Only callable on Lollipop and newer releases.
214 */
215 @SuppressLint("NewApi")
216 Network[] getAllNetworks() {
217 if (connectivityManager == null) {
218 return new Network[0];
219 }
220 return connectivityManager.getAllNetworks();
221 }
222
223 List<NetworkInformation> getActiveNetworkList() {
224 if (!supportNetworkCallback()) {
225 return null;
226 }
227 ArrayList<NetworkInformation> netInfoList = new ArrayList<NetworkInformati on>();
228 for (Network network : getAllNetworks()) {
229 NetworkInformation info = networkToInfo(network);
230 if (info != null) {
231 netInfoList.add(info);
232 }
233 }
234 return netInfoList;
235 }
236
237 /**
238 * Returns the NetID of the current default network. Returns
239 * INVALID_NET_ID if no current default network connected.
240 * Only callable on Lollipop and newer releases.
241 */
242 @SuppressLint("NewApi")
243 long getDefaultNetId() {
244 if (!supportNetworkCallback()) {
245 return INVALID_NET_ID;
246 }
247 // Android Lollipop had no API to get the default network; only an
248 // API to return the NetworkInfo for the default network. To
249 // determine the default network one can find the network with
250 // type matching that of the default network.
251 final NetworkInfo defaultNetworkInfo = connectivityManager.getActiveNetwor kInfo();
252 if (defaultNetworkInfo == null) {
253 return INVALID_NET_ID;
254 }
255 final Network[] networks = getAllNetworks();
256 long defaultNetId = INVALID_NET_ID;
257 for (Network network : networks) {
258 if (!hasInternetCapability(network)) {
259 continue;
260 }
261 final NetworkInfo networkInfo = connectivityManager.getNetworkInfo(netwo rk);
262 if (networkInfo != null && networkInfo.getType() == defaultNetworkInfo.g etType()) {
263 // There should not be multiple connected networks of the
264 // same type. At least as of Android Marshmallow this is
265 // not supported. If this becomes supported this assertion
266 // may trigger. At that point we could consider using
267 // ConnectivityManager.getDefaultNetwork() though this
268 // may give confusing results with VPNs and is only
269 // available with Android Marshmallow.
270 assert defaultNetId == INVALID_NET_ID;
271 defaultNetId = networkToNetId(network);
272 }
273 }
274 return defaultNetId;
275 }
276
277 @SuppressLint("NewApi")
278 private NetworkInformation networkToInfo(Network network) {
279 LinkProperties linkProperties = connectivityManager.getLinkProperties(netw ork);
280 // getLinkProperties will return null if the network is unknown.
281 if (linkProperties == null) {
282 Logging.w(TAG, "Detected unknown network: " + network.toString());
283 return null;
284 }
285 if (linkProperties.getInterfaceName() == null) {
286 Logging.w(TAG, "Null interface name for network " + network.toString());
287 return null;
288 }
289
290 NetworkState networkState = getNetworkState(network);
291 if (networkState.connected && networkState.getNetworkType() == Connectivit yManager.TYPE_VPN) {
292 // If a VPN network is in place, we can find the underlying network type via querying the
293 // active network info thanks to
294 // https://android.googlesource.com/platform/frameworks/base/+/d6a7980d
295 networkState = getNetworkState();
296 }
297 ConnectionType connectionType = getConnectionType(networkState);
298 if (connectionType == ConnectionType.CONNECTION_NONE) {
299 // This may not be an error. The OS may signal a network event with conn ection type
300 // NONE when the network disconnects.
301 Logging.d(TAG, "Network " + network.toString() + " is disconnected");
302 return null;
303 }
304
305 // Some android device may return a CONNECTION_UNKNOWN_CELLULAR or CONNECT ION_UNKNOWN type,
306 // which appears to be usable. Just log them here.
307 if (connectionType == ConnectionType.CONNECTION_UNKNOWN
308 || connectionType == ConnectionType.CONNECTION_UNKNOWN_CELLULAR) {
309 Logging.d(TAG, "Network " + network.toString() + " connection type is " + connectionType
310 + " because it has type " + networkState.getNetworkType() + " an d subtype "
311 + networkState.getNetworkSubType());
312 }
313
314 NetworkInformation networkInformation =
315 new NetworkInformation(linkProperties.getInterfaceName(), connectionTy pe,
316 networkToNetId(network), getIPAddresses(linkProperties));
317 return networkInformation;
318 }
319
320 /**
321 * Returns true if {@code network} can provide Internet access. Can be used to
322 * ignore specialized networks (e.g. IMS, FOTA).
323 */
324 @SuppressLint("NewApi")
325 boolean hasInternetCapability(Network network) {
326 if (connectivityManager == null) {
327 return false;
328 }
329 final NetworkCapabilities capabilities = connectivityManager.getNetworkCap abilities(network);
330 return capabilities != null && capabilities.hasCapability(NET_CAPABILITY_I NTERNET);
331 }
332
333 /** Only callable on Lollipop and newer releases. */
334 @SuppressLint("NewApi")
335 public void registerNetworkCallback(NetworkCallback networkCallback) {
336 connectivityManager.registerNetworkCallback(
337 new NetworkRequest.Builder().addCapability(NET_CAPABILITY_INTERNET).bu ild(),
338 networkCallback);
339 }
340
341 /** Only callable on Lollipop and newer releases. */
342 @SuppressLint("NewApi")
343 public void requestMobileNetwork(NetworkCallback networkCallback) {
344 NetworkRequest.Builder builder = new NetworkRequest.Builder();
345 builder.addCapability(NET_CAPABILITY_INTERNET).addTransportType(TRANSPORT_ CELLULAR);
346 connectivityManager.requestNetwork(builder.build(), networkCallback);
347 }
348
349 @SuppressLint("NewApi")
350 IPAddress[] getIPAddresses(LinkProperties linkProperties) {
351 IPAddress[] ipAddresses = new IPAddress[linkProperties.getLinkAddresses(). size()];
352 int i = 0;
353 for (LinkAddress linkAddress : linkProperties.getLinkAddresses()) {
354 ipAddresses[i] = new IPAddress(linkAddress.getAddress().getAddress());
355 ++i;
356 }
357 return ipAddresses;
358 }
359
360 @SuppressLint("NewApi")
361 public void releaseCallback(NetworkCallback networkCallback) {
362 if (supportNetworkCallback()) {
363 Logging.d(TAG, "Unregister network callback");
364 connectivityManager.unregisterNetworkCallback(networkCallback);
365 }
366 }
367
368 public boolean supportNetworkCallback() {
369 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && connectivi tyManager != null;
370 }
371 }
372
373 /** Queries the WifiManager for SSID of the current Wifi connection. */
374 static class WifiManagerDelegate {
375 private final Context context;
376 WifiManagerDelegate(Context context) {
377 this.context = context;
378 }
379
380 // For testing.
381 WifiManagerDelegate() {
382 // All the methods below should be overridden.
383 context = null;
384 }
385
386 String getWifiSSID() {
387 final Intent intent = context.registerReceiver(
388 null, new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION));
389 if (intent != null) {
390 final WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WI FI_INFO);
391 if (wifiInfo != null) {
392 final String ssid = wifiInfo.getSSID();
393 if (ssid != null) {
394 return ssid;
395 }
396 }
397 }
398 return "";
399 }
400 }
401
402 static final long INVALID_NET_ID = -1;
403 private static final String TAG = "NetworkMonitorAutoDetect";
404
405 // Observer for the connection type change.
406 private final Observer observer;
407 private final IntentFilter intentFilter;
408 private final Context context;
409 // Used to request mobile network. It does not do anything except for keeping
410 // the callback for releasing the request.
411 private final NetworkCallback mobileNetworkCallback;
412 // Used to receive updates on all networks.
413 private final NetworkCallback allNetworkCallback;
414 // connectivityManagerDelegate and wifiManagerDelegate are only non-final for testing.
415 private ConnectivityManagerDelegate connectivityManagerDelegate;
416 private WifiManagerDelegate wifiManagerDelegate;
417
418 private boolean isRegistered;
419 private ConnectionType connectionType;
420 private String wifiSSID;
421
422 /**
423 * Observer interface by which observer is notified of network changes.
424 */
425 public static interface Observer {
426 /**
427 * Called when default network changes.
428 */
429 public void onConnectionTypeChanged(ConnectionType newConnectionType);
430 public void onNetworkConnect(NetworkInformation networkInfo);
431 public void onNetworkDisconnect(long networkHandle);
432 }
433
434 /**
435 * Constructs a NetworkMonitorAutoDetect. Should only be called on UI thread.
436 */
437 @SuppressLint("NewApi")
438 public NetworkMonitorAutoDetect(Observer observer, Context context) {
439 this.observer = observer;
440 this.context = context;
441 connectivityManagerDelegate = new ConnectivityManagerDelegate(context);
442 wifiManagerDelegate = new WifiManagerDelegate(context);
443
444 final NetworkState networkState = connectivityManagerDelegate.getNetworkStat e();
445 connectionType = getConnectionType(networkState);
446 wifiSSID = getWifiSSID(networkState);
447 intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
448
449 registerReceiver();
450 if (connectivityManagerDelegate.supportNetworkCallback()) {
451 // On Android 6.0.0, the WRITE_SETTINGS permission is necessary for
452 // requestNetwork, so it will fail. This was fixed in Android 6.0.1.
453 NetworkCallback tempNetworkCallback = new NetworkCallback();
454 try {
455 connectivityManagerDelegate.requestMobileNetwork(tempNetworkCallback);
456 } catch (java.lang.SecurityException e) {
457 Logging.w(TAG, "Unable to obtain permission to request a cellular networ k.");
458 tempNetworkCallback = null;
459 }
460 mobileNetworkCallback = tempNetworkCallback;
461 allNetworkCallback = new SimpleNetworkCallback();
462 connectivityManagerDelegate.registerNetworkCallback(allNetworkCallback);
463 } else {
464 mobileNetworkCallback = null;
465 allNetworkCallback = null;
466 }
467 }
468
469 /**
470 * Allows overriding the ConnectivityManagerDelegate for tests.
471 */
472 void setConnectivityManagerDelegateForTests(ConnectivityManagerDelegate delega te) {
473 connectivityManagerDelegate = delegate;
474 }
475
476 /**
477 * Allows overriding the WifiManagerDelegate for tests.
478 */
479 void setWifiManagerDelegateForTests(WifiManagerDelegate delegate) {
480 wifiManagerDelegate = delegate;
481 }
482
483 /**
484 * Returns whether the object has registered to receive network connectivity i ntents.
485 * Visible for testing.
486 */
487 boolean isReceiverRegisteredForTesting() {
488 return isRegistered;
489 }
490
491 List<NetworkInformation> getActiveNetworkList() {
492 return connectivityManagerDelegate.getActiveNetworkList();
493 }
494
495 public void destroy() {
496 if (allNetworkCallback != null) {
497 connectivityManagerDelegate.releaseCallback(allNetworkCallback);
498 }
499 if (mobileNetworkCallback != null) {
500 connectivityManagerDelegate.releaseCallback(mobileNetworkCallback);
501 }
502 unregisterReceiver();
503 }
504
505 /**
506 * Registers a BroadcastReceiver in the given context.
507 */
508 private void registerReceiver() {
509 if (isRegistered)
510 return;
511
512 isRegistered = true;
513 context.registerReceiver(this, intentFilter);
514 }
515
516 /**
517 * Unregisters the BroadcastReceiver in the given context.
518 */
519 private void unregisterReceiver() {
520 if (!isRegistered)
521 return;
522
523 isRegistered = false;
524 context.unregisterReceiver(this);
525 }
526
527 public NetworkState getCurrentNetworkState() {
528 return connectivityManagerDelegate.getNetworkState();
529 }
530
531 /**
532 * Returns NetID of device's current default connected network used for
533 * communication.
534 * Only implemented on Lollipop and newer releases, returns INVALID_NET_ID
535 * when not implemented.
536 */
537 public long getDefaultNetId() {
538 return connectivityManagerDelegate.getDefaultNetId();
539 }
540
541 public static ConnectionType getConnectionType(NetworkState networkState) {
542 if (!networkState.isConnected()) {
543 return ConnectionType.CONNECTION_NONE;
544 }
545
546 switch (networkState.getNetworkType()) {
547 case ConnectivityManager.TYPE_ETHERNET:
548 return ConnectionType.CONNECTION_ETHERNET;
549 case ConnectivityManager.TYPE_WIFI:
550 return ConnectionType.CONNECTION_WIFI;
551 case ConnectivityManager.TYPE_WIMAX:
552 return ConnectionType.CONNECTION_4G;
553 case ConnectivityManager.TYPE_BLUETOOTH:
554 return ConnectionType.CONNECTION_BLUETOOTH;
555 case ConnectivityManager.TYPE_MOBILE:
556 // Use information from TelephonyManager to classify the connection.
557 switch (networkState.getNetworkSubType()) {
558 case TelephonyManager.NETWORK_TYPE_GPRS:
559 case TelephonyManager.NETWORK_TYPE_EDGE:
560 case TelephonyManager.NETWORK_TYPE_CDMA:
561 case TelephonyManager.NETWORK_TYPE_1xRTT:
562 case TelephonyManager.NETWORK_TYPE_IDEN:
563 return ConnectionType.CONNECTION_2G;
564 case TelephonyManager.NETWORK_TYPE_UMTS:
565 case TelephonyManager.NETWORK_TYPE_EVDO_0:
566 case TelephonyManager.NETWORK_TYPE_EVDO_A:
567 case TelephonyManager.NETWORK_TYPE_HSDPA:
568 case TelephonyManager.NETWORK_TYPE_HSUPA:
569 case TelephonyManager.NETWORK_TYPE_HSPA:
570 case TelephonyManager.NETWORK_TYPE_EVDO_B:
571 case TelephonyManager.NETWORK_TYPE_EHRPD:
572 case TelephonyManager.NETWORK_TYPE_HSPAP:
573 return ConnectionType.CONNECTION_3G;
574 case TelephonyManager.NETWORK_TYPE_LTE:
575 return ConnectionType.CONNECTION_4G;
576 default:
577 return ConnectionType.CONNECTION_UNKNOWN_CELLULAR;
578 }
579 default:
580 return ConnectionType.CONNECTION_UNKNOWN;
581 }
582 }
583
584 private String getWifiSSID(NetworkState networkState) {
585 if (getConnectionType(networkState) != ConnectionType.CONNECTION_WIFI)
586 return "";
587 return wifiManagerDelegate.getWifiSSID();
588 }
589
590 // BroadcastReceiver
591 @Override
592 public void onReceive(Context context, Intent intent) {
593 final NetworkState networkState = getCurrentNetworkState();
594 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
595 connectionTypeChanged(networkState);
596 }
597 }
598
599 private void connectionTypeChanged(NetworkState networkState) {
600 ConnectionType newConnectionType = getConnectionType(networkState);
601 String newWifiSSID = getWifiSSID(networkState);
602 if (newConnectionType == connectionType && newWifiSSID.equals(wifiSSID))
603 return;
604
605 connectionType = newConnectionType;
606 wifiSSID = newWifiSSID;
607 Logging.d(TAG, "Network connectivity changed, type is: " + connectionType);
608 observer.onConnectionTypeChanged(newConnectionType);
609 }
610
611 /**
612 * Extracts NetID of network on Lollipop and NetworkHandle (which is mungled
613 * NetID) on Marshmallow and newer releases. Only available on Lollipop and
614 * newer releases. Returns long since getNetworkHandle returns long.
615 */
616 @SuppressLint("NewApi")
617 private static long networkToNetId(Network network) {
618 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
619 return network.getNetworkHandle();
620 }
621
622 // NOTE(honghaiz): This depends on Android framework implementation details.
623 // These details cannot change because Lollipop has been released.
624 return Integer.parseInt(network.toString());
625 }
626 }
OLDNEW
« no previous file with comments | « webrtc/api/android/java/src/org/webrtc/NetworkMonitor.java ('k') | webrtc/api/android/java/src/org/webrtc/OWNERS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698