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

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

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

Powered by Google App Engine
This is Rietveld 408576698