1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.googlecode.android_scripting.facade;
18 
19 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
20 
21 import android.app.Service;
22 import android.app.usage.NetworkStats;
23 import android.app.usage.NetworkStats.Bucket;
24 import android.app.usage.NetworkStatsManager;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.net.ConnectivityManager;
30 import android.net.LinkProperties;
31 import android.net.Network;
32 import android.net.NetworkCapabilities;
33 import android.net.NetworkInfo;
34 import android.net.NetworkPolicy;
35 import android.net.NetworkPolicyManager;
36 import android.net.NetworkRequest;
37 import android.net.NetworkSpecifier;
38 import android.net.ProxyInfo;
39 import android.net.RouteInfo;
40 import android.net.Uri;
41 import android.net.wifi.WifiNetworkSpecifier;
42 import android.os.Bundle;
43 import android.os.RemoteException;
44 import android.provider.Settings;
45 import android.telephony.TelephonyManager;
46 
47 import com.android.modules.utils.build.SdkLevel;
48 
49 import com.google.common.io.ByteStreams;
50 import com.googlecode.android_scripting.FileUtils;
51 import com.googlecode.android_scripting.Log;
52 import com.googlecode.android_scripting.facade.wifi.WifiAwareManagerFacade;
53 import com.googlecode.android_scripting.facade.wifi.WifiManagerFacade;
54 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
55 import com.googlecode.android_scripting.rpc.Rpc;
56 import com.googlecode.android_scripting.rpc.RpcOptional;
57 import com.googlecode.android_scripting.rpc.RpcParameter;
58 
59 import org.json.JSONArray;
60 import org.json.JSONException;
61 import org.json.JSONObject;
62 
63 import java.io.BufferedInputStream;
64 import java.io.File;
65 import java.io.FileOutputStream;
66 import java.io.IOException;
67 import java.io.InputStream;
68 import java.io.OutputStream;
69 import java.net.Inet4Address;
70 import java.net.Inet6Address;
71 import java.net.InetAddress;
72 import java.net.NetworkInterface;
73 import java.net.SocketException;
74 import java.net.URL;
75 import java.net.URLConnection;
76 import java.security.GeneralSecurityException;
77 import java.util.ArrayList;
78 import java.util.Collections;
79 import java.util.Enumeration;
80 import java.util.HashMap;
81 import java.util.List;
82 
83 /**
84  * Access ConnectivityManager functions.
85  */
86 public class ConnectivityManagerFacade extends RpcReceiver {
87 
88     public static int AIRPLANE_MODE_OFF = 0;
89     public static int AIRPLANE_MODE_ON = 1;
90     public static int DATA_ROAMING_ON = 1;
91 
92     private static HashMap<Long, Network> sNetworkHashMap = new HashMap<Long, Network>();
93 
94     class ConnectivityReceiver extends BroadcastReceiver {
95 
96         @Override
onReceive(Context context, Intent intent)97         public void onReceive(Context context, Intent intent) {
98             String action = intent.getAction();
99 
100             if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
101                 Log.e("ConnectivityReceiver received non-connectivity action!");
102                 return;
103             }
104 
105             Bundle b = intent.getExtras();
106 
107             if (b == null) {
108                 Log.e("ConnectivityReceiver failed to receive extras!");
109                 return;
110             }
111 
112             int netType =
113                     b.getInt(ConnectivityManager.EXTRA_NETWORK_TYPE,
114                             ConnectivityManager.TYPE_NONE);
115 
116             if (netType == ConnectivityManager.TYPE_NONE) {
117                 Log.i("ConnectivityReceiver received change to TYPE_NONE.");
118                 return;
119             }
120 
121             /*
122              * Technically there is a race condition here, but retrieving the NetworkInfo from the
123              * bundle is deprecated. See ConnectivityManager.EXTRA_NETWORK_INFO
124              */
125             for (NetworkInfo info : mManager.getAllNetworkInfo()) {
126                 if (info.getType() == netType) {
127                     mEventFacade.postEvent(ConnectivityConstants.EventConnectivityChanged, info);
128                 }
129             }
130         }
131     }
132 
133     /**
134      * Used to dispatch to a different constructor depending on R or S, since
135      * {@link ConnectivityManager.NetworkCallback#NetworkCallback(int)} was added in S.
136      */
newNetworkCallback(int events)137     private NetworkCallback newNetworkCallback(int events) {
138         if (SdkLevel.isAtLeastS()) {
139             return new NetworkCallback(events);
140         } else {
141             return new NetworkCallback(events, false);
142         }
143     }
144 
145     private class NetworkCallback extends ConnectivityManager.NetworkCallback {
146         public static final int EVENT_INVALID = -1;
147         public static final int EVENT_NONE = 0;
148         public static final int EVENT_PRECHECK = 1 << 0;
149         public static final int EVENT_AVAILABLE = 1 << 1;
150         public static final int EVENT_LOSING = 1 << 2;
151         public static final int EVENT_LOST = 1 << 3;
152         public static final int EVENT_UNAVAILABLE = 1 << 4;
153         public static final int EVENT_CAPABILITIES_CHANGED = 1 << 5;
154         public static final int EVENT_SUSPENDED = 1 << 6;
155         public static final int EVENT_RESUMED = 1 << 7;
156         public static final int EVENT_LINK_PROPERTIES_CHANGED = 1 << 8;
157         public static final int EVENT_BLOCKED_STATUS_CHANGED = 1 << 9;
158         public static final int EVENT_ALL =
159                 EVENT_PRECHECK
160                         | EVENT_AVAILABLE
161                         | EVENT_LOSING
162                         | EVENT_LOST
163                         | EVENT_UNAVAILABLE
164                         | EVENT_CAPABILITIES_CHANGED
165                         | EVENT_SUSPENDED
166                         | EVENT_RESUMED
167                         | EVENT_LINK_PROPERTIES_CHANGED
168                         | EVENT_BLOCKED_STATUS_CHANGED;
169 
170         private int mEvents;
171         public String mId;
172         private long mCreateTimestamp;
173 
174         /** Called in >= Android S where super(int) does exist. */
NetworkCallback(int events)175         private NetworkCallback(int events) {
176             super(ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO);
177             init(events);
178         }
179 
180         /**
181          * Called in <= Android R where super(int) doesn't exist.
182          * @param ignore placeholder argument to differentiate between R and S constructors' method
183          *              signatures.
184          */
NetworkCallback(int events, boolean ignore)185         private NetworkCallback(int events, boolean ignore) {
186             super();
187             init(events);
188         }
189 
init(int events)190         private void init(int events) {
191             mEvents = events;
192             mId = this.toString();
193             mCreateTimestamp = System.currentTimeMillis();
194         }
195 
startListeningForEvents(int events)196         public void startListeningForEvents(int events) {
197             mEvents |= events & EVENT_ALL;
198         }
199 
stopListeningForEvents(int events)200         public void stopListeningForEvents(int events) {
201             mEvents &= ~(events & EVENT_ALL);
202         }
203 
204         @Override
onPreCheck(Network network)205         public void onPreCheck(Network network) {
206             Log.d("NetworkCallback onPreCheck");
207             if ((mEvents & EVENT_PRECHECK) == EVENT_PRECHECK) {
208                 mEventFacade.postEvent(
209                         ConnectivityConstants.EventNetworkCallback,
210                     new ConnectivityEvents.NetworkCallbackEventBase(
211                         mId,
212                         getNetworkCallbackEventString(EVENT_PRECHECK), mCreateTimestamp));
213             }
214         }
215 
216         @Override
onAvailable(Network network)217         public void onAvailable(Network network) {
218             Log.d("NetworkCallback onAvailable");
219             if ((mEvents & EVENT_AVAILABLE) == EVENT_AVAILABLE) {
220                 mEventFacade.postEvent(
221                         ConnectivityConstants.EventNetworkCallback,
222                     new ConnectivityEvents.NetworkCallbackEventBase(
223                         mId,
224                         getNetworkCallbackEventString(EVENT_AVAILABLE), mCreateTimestamp));
225             }
226         }
227 
228         @Override
onLosing(Network network, int maxMsToLive)229         public void onLosing(Network network, int maxMsToLive) {
230             Log.d("NetworkCallback onLosing");
231             if ((mEvents & EVENT_LOSING) == EVENT_LOSING) {
232                 mEventFacade.postEvent(
233                         ConnectivityConstants.EventNetworkCallback,
234                     new ConnectivityEvents.NetworkCallbackEventOnLosing(
235                         mId,
236                         getNetworkCallbackEventString(EVENT_LOSING), mCreateTimestamp,
237                         maxMsToLive));
238             }
239         }
240 
241         @Override
onLost(Network network)242         public void onLost(Network network) {
243             Log.d("NetworkCallback onLost");
244             if ((mEvents & EVENT_LOST) == EVENT_LOST) {
245                 mEventFacade.postEvent(
246                         ConnectivityConstants.EventNetworkCallback,
247                     new ConnectivityEvents.NetworkCallbackEventBase(
248                         mId,
249                         getNetworkCallbackEventString(EVENT_LOST), mCreateTimestamp));
250             }
251         }
252 
253         @Override
onUnavailable()254         public void onUnavailable() {
255             Log.d("NetworkCallback onUnavailable");
256             if ((mEvents & EVENT_UNAVAILABLE) == EVENT_UNAVAILABLE) {
257                 mEventFacade.postEvent(
258                         ConnectivityConstants.EventNetworkCallback,
259                     new ConnectivityEvents.NetworkCallbackEventBase(
260                         mId,
261                         getNetworkCallbackEventString(EVENT_UNAVAILABLE), mCreateTimestamp));
262             }
263         }
264 
265         @Override
onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)266         public void onCapabilitiesChanged(Network network,
267                 NetworkCapabilities networkCapabilities) {
268             Log.d("NetworkCallback onCapabilitiesChanged. RSSI:" +
269                     networkCapabilities.getSignalStrength());
270             if ((mEvents & EVENT_CAPABILITIES_CHANGED) == EVENT_CAPABILITIES_CHANGED) {
271                 mEventFacade.postEvent(
272                         ConnectivityConstants.EventNetworkCallback,
273                     new ConnectivityEvents.NetworkCallbackEventOnCapabilitiesChanged(
274                         mId,
275                         getNetworkCallbackEventString(EVENT_CAPABILITIES_CHANGED), mCreateTimestamp,
276                         networkCapabilities));
277             }
278         }
279 
280         @Override
onBlockedStatusChanged(Network network, boolean blocked)281         public void onBlockedStatusChanged(Network network, boolean blocked) {
282             Log.d("NetworkCallback onBlockedStatusChanged");
283             if ((mEvents & EVENT_BLOCKED_STATUS_CHANGED) == EVENT_BLOCKED_STATUS_CHANGED) {
284                 mEventFacade.postEvent(
285                         ConnectivityConstants.EventNetworkCallback,
286                         new ConnectivityEvents.NetworkCallbackEventBase(
287                             mId,
288                             getNetworkCallbackEventString(EVENT_BLOCKED_STATUS_CHANGED),
289                             mCreateTimestamp));
290             }
291         }
292 
293         @Override
onNetworkSuspended(Network network)294         public void onNetworkSuspended(Network network) {
295             Log.d("NetworkCallback onNetworkSuspended");
296             if ((mEvents & EVENT_SUSPENDED) == EVENT_SUSPENDED) {
297                 mEventFacade.postEvent(
298                         ConnectivityConstants.EventNetworkCallback,
299                     new ConnectivityEvents.NetworkCallbackEventBase(
300                         mId,
301                         getNetworkCallbackEventString(EVENT_SUSPENDED), mCreateTimestamp));
302             }
303         }
304 
305         @Override
onLinkPropertiesChanged(Network network, LinkProperties linkProperties)306         public void onLinkPropertiesChanged(Network network,
307                 LinkProperties linkProperties) {
308             Log.d("NetworkCallback onLinkPropertiesChanged");
309             if ((mEvents & EVENT_LINK_PROPERTIES_CHANGED) == EVENT_LINK_PROPERTIES_CHANGED) {
310                 mEventFacade.postEvent(
311                         ConnectivityConstants.EventNetworkCallback,
312                         new ConnectivityEvents.NetworkCallbackEventOnLinkPropertiesChanged(mId,
313                                 getNetworkCallbackEventString(EVENT_LINK_PROPERTIES_CHANGED),
314                                 mCreateTimestamp,
315                                 linkProperties.getInterfaceName()));
316             }
317         }
318 
319         @Override
onNetworkResumed(Network network)320         public void onNetworkResumed(Network network) {
321             Log.d("NetworkCallback onNetworkResumed");
322             if ((mEvents & EVENT_RESUMED) == EVENT_RESUMED) {
323                 mEventFacade.postEvent(
324                         ConnectivityConstants.EventNetworkCallback,
325                     new ConnectivityEvents.NetworkCallbackEventBase(
326                         mId,
327                         getNetworkCallbackEventString(EVENT_RESUMED), mCreateTimestamp));
328             }
329         }
330     }
331 
getNetworkCallbackEvent(String event)332     private static int getNetworkCallbackEvent(String event) {
333         switch (event) {
334             case ConnectivityConstants.NetworkCallbackPreCheck:
335                 return NetworkCallback.EVENT_PRECHECK;
336             case ConnectivityConstants.NetworkCallbackAvailable:
337                 return NetworkCallback.EVENT_AVAILABLE;
338             case ConnectivityConstants.NetworkCallbackLosing:
339                 return NetworkCallback.EVENT_LOSING;
340             case ConnectivityConstants.NetworkCallbackLost:
341                 return NetworkCallback.EVENT_LOST;
342             case ConnectivityConstants.NetworkCallbackUnavailable:
343                 return NetworkCallback.EVENT_UNAVAILABLE;
344             case ConnectivityConstants.NetworkCallbackCapabilitiesChanged:
345                 return NetworkCallback.EVENT_CAPABILITIES_CHANGED;
346             case ConnectivityConstants.NetworkCallbackSuspended:
347                 return NetworkCallback.EVENT_SUSPENDED;
348             case ConnectivityConstants.NetworkCallbackResumed:
349                 return NetworkCallback.EVENT_RESUMED;
350             case ConnectivityConstants.NetworkCallbackLinkPropertiesChanged:
351                 return NetworkCallback.EVENT_LINK_PROPERTIES_CHANGED;
352             case ConnectivityConstants.NetworkCallbackBlockedStatusChanged:
353                 return NetworkCallback.EVENT_BLOCKED_STATUS_CHANGED;
354         }
355         return NetworkCallback.EVENT_INVALID;
356     }
357 
getNetworkCallbackEventString(int event)358     private static String getNetworkCallbackEventString(int event) {
359         switch (event) {
360             case NetworkCallback.EVENT_PRECHECK:
361                 return ConnectivityConstants.NetworkCallbackPreCheck;
362             case NetworkCallback.EVENT_AVAILABLE:
363                 return ConnectivityConstants.NetworkCallbackAvailable;
364             case NetworkCallback.EVENT_LOSING:
365                 return ConnectivityConstants.NetworkCallbackLosing;
366             case NetworkCallback.EVENT_LOST:
367                 return ConnectivityConstants.NetworkCallbackLost;
368             case NetworkCallback.EVENT_UNAVAILABLE:
369                 return ConnectivityConstants.NetworkCallbackUnavailable;
370             case NetworkCallback.EVENT_CAPABILITIES_CHANGED:
371                 return ConnectivityConstants.NetworkCallbackCapabilitiesChanged;
372             case NetworkCallback.EVENT_SUSPENDED:
373                 return ConnectivityConstants.NetworkCallbackSuspended;
374             case NetworkCallback.EVENT_RESUMED:
375                 return ConnectivityConstants.NetworkCallbackResumed;
376             case NetworkCallback.EVENT_LINK_PROPERTIES_CHANGED:
377                 return ConnectivityConstants.NetworkCallbackLinkPropertiesChanged;
378             case NetworkCallback.EVENT_BLOCKED_STATUS_CHANGED:
379                 return ConnectivityConstants.NetworkCallbackBlockedStatusChanged;
380         }
381         return ConnectivityConstants.NetworkCallbackInvalid;
382     }
383 
384     /**
385      * Callbacks used in ConnectivityManager to confirm tethering has started/failed.
386      */
387     class OnStartTetheringCallback extends ConnectivityManager.OnStartTetheringCallback {
388         @Override
onTetheringStarted()389         public void onTetheringStarted() {
390             mEventFacade.postEvent(ConnectivityConstants.TetheringStartedCallback, null);
391         }
392 
393         @Override
onTetheringFailed()394         public void onTetheringFailed() {
395             mEventFacade.postEvent(ConnectivityConstants.TetheringFailedCallback, null);
396         }
397     }
398 
399     private final ConnectivityManager mManager;
400     private NetworkPolicyManager mNetPolicyManager;
401     private NetworkStatsManager mNetStatsManager;
402     private final Service mService;
403     private final Context mContext;
404     private final ConnectivityReceiver mConnectivityReceiver;
405     private final EventFacade mEventFacade;
406     private NetworkCallback mNetworkCallback;
407     private TelephonyManager mTelephonyManager;
408     private static HashMap<String, NetworkCallback> mNetworkCallbackMap =
409             new HashMap<String, NetworkCallback>();
410     private boolean mTrackingConnectivityStateChange;
411 
ConnectivityManagerFacade(FacadeManager manager)412     public ConnectivityManagerFacade(FacadeManager manager) {
413         super(manager);
414         mService = manager.getService();
415         mContext = mService.getBaseContext();
416         mManager = (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE);
417         mNetPolicyManager = NetworkPolicyManager.from(mContext);
418         mNetStatsManager = (NetworkStatsManager)
419               mService.getSystemService(Context.NETWORK_STATS_SERVICE);
420         mEventFacade = manager.getReceiver(EventFacade.class);
421         mConnectivityReceiver = new ConnectivityReceiver();
422         mTrackingConnectivityStateChange = false;
423         mTelephonyManager = (TelephonyManager) mService.getSystemService(Context.TELEPHONY_SERVICE);
424     }
425 
426     @Rpc(description = "Listen for connectivity changes")
connectivityStartTrackingConnectivityStateChange()427     public void connectivityStartTrackingConnectivityStateChange() {
428         if (!mTrackingConnectivityStateChange) {
429             mTrackingConnectivityStateChange = true;
430             mContext.registerReceiver(mConnectivityReceiver,
431                     new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
432         }
433     }
434 
435     @Rpc(description = "start listening for NetworkCallback Event")
connectivityNetworkCallbackStartListeningForEvent(String key, String eventString)436     public Boolean connectivityNetworkCallbackStartListeningForEvent(String key, String eventString) {
437         NetworkCallback mNetworkCallback = mNetworkCallbackMap.get(key);
438         if (mNetworkCallback != null) {
439             int event = getNetworkCallbackEvent(eventString);
440             if (event == NetworkCallback.EVENT_INVALID) {
441                 return false;
442             }
443             mNetworkCallback.startListeningForEvents(event);
444             return true;
445         } else {
446             return false;
447         }
448     }
449 
450     @Rpc(description = "stop listening for NetworkCallback Event")
connectivityNetworkCallbackStopListeningForEvent(String key, String eventString)451     public Boolean connectivityNetworkCallbackStopListeningForEvent(String key, String eventString) {
452         NetworkCallback mNetworkCallback = mNetworkCallbackMap.get(key);
453         if (mNetworkCallback != null) {
454             int event = getNetworkCallbackEvent(eventString);
455             if (event == NetworkCallback.EVENT_INVALID) {
456                 return false;
457             }
458             mNetworkCallback.stopListeningForEvents(event);
459             return true;
460         } else {
461             return false;
462         }
463     }
464 
465     @Rpc(description = "Set Rssi Threshold Monitor")
connectivitySetRssiThresholdMonitor(Integer rssi)466     public String connectivitySetRssiThresholdMonitor(Integer rssi) {
467         Log.d("SL4A:setRssiThresholdMonitor rssi = " + rssi);
468         NetworkRequest.Builder builder = new NetworkRequest.Builder();
469         builder.setSignalStrength((int) rssi);
470         builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
471         NetworkRequest networkRequest = builder.build();
472         mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL);
473         mManager.registerNetworkCallback(networkRequest, mNetworkCallback);
474         String key = mNetworkCallback.mId;
475         mNetworkCallbackMap.put(key, mNetworkCallback);
476         return key;
477     }
478 
479     @Rpc(description = "Stop Rssi Threshold Monitor")
connectivityStopRssiThresholdMonitor(String key)480     public Boolean connectivityStopRssiThresholdMonitor(String key) {
481         Log.d("SL4A:stopRssiThresholdMonitor key = " + key);
482         return connectivityUnregisterNetworkCallback(key);
483     }
484 
buildNetworkRequestFromJson(JSONObject configJson)485     private NetworkRequest buildNetworkRequestFromJson(JSONObject configJson)
486             throws JSONException {
487         return makeNetworkRequestBuilderFromJson(configJson).build();
488     }
489 
buildWifiAwareNetworkRequestFromJson(JSONObject configJson)490     private NetworkRequest buildWifiAwareNetworkRequestFromJson(JSONObject configJson)
491             throws JSONException {
492         final NetworkRequest.Builder builder = makeNetworkRequestBuilderFromJson(configJson);
493         if (configJson.has("NetworkSpecifier")) {
494             final String strSpecifier = configJson.getString("NetworkSpecifier");
495             Log.d("build NetworkSpecifier" + strSpecifier);
496             final NetworkSpecifier specifier = WifiAwareManagerFacade.getNetworkSpecifier(
497                     new JSONObject(strSpecifier));
498             builder.setNetworkSpecifier(specifier);
499         }
500         return builder.build();
501     }
502 
makeNetworkRequestBuilderFromJson(JSONObject configJson)503     private NetworkRequest.Builder makeNetworkRequestBuilderFromJson(JSONObject configJson)
504             throws JSONException {
505         NetworkRequest.Builder builder = new NetworkRequest.Builder();
506 
507         if (configJson.has("ClearCapabilities")) {
508             /* the 'ClearCapabilities' property does not have a value (that we use). Its presence
509              is used to clear the capabilities of the constructed network request (which is
510              constructed with some default capabilities already present). */
511             Log.d("build ClearCapabilities");
512             builder.clearCapabilities();
513         }
514         if (configJson.has(ConnectivityConstants.NET_CAPABILITIES_TRANSPORT_TYPE)) {
515             Log.d("build TransportType"
516                     + configJson.getInt(ConnectivityConstants.NET_CAPABILITIES_TRANSPORT_TYPE));
517             builder.addTransportType(
518                     configJson.getInt(ConnectivityConstants.NET_CAPABILITIES_TRANSPORT_TYPE));
519         }
520         if (configJson.has("SignalStrength")) {
521             Log.d("build SignalStrength" + configJson.getInt("SignalStrength"));
522             builder.setSignalStrength(configJson.getInt("SignalStrength"));
523         }
524         if (configJson.has(ConnectivityConstants.NET_CAPABILITIES_CAPABILITIES)) {
525             JSONArray capabilities =
526                     configJson.getJSONArray(ConnectivityConstants.NET_CAPABILITIES_CAPABILITIES);
527             for (int i = 0; i < capabilities.length(); i++) {
528                 Log.d("build Capability" + capabilities.getInt(i));
529                 builder.addCapability(capabilities.getInt(i));
530             }
531         }
532         if (configJson.has("LinkUpstreamBandwidthKbps")) {
533             Log.d("build LinkUpstreamBandwidthKbps" + configJson.getInt(
534                     "LinkUpstreamBandwidthKbps"));
535             builder.setLinkUpstreamBandwidthKbps(configJson.getInt(
536                     "LinkUpstreamBandwidthKbps"));
537         }
538         if (configJson.has("LinkDownstreamBandwidthKbps")) {
539             Log.d("build LinkDownstreamBandwidthKbps" + configJson.getInt(
540                     "LinkDownstreamBandwidthKbps"));
541             builder.setLinkDownstreamBandwidthKbps(configJson.getInt(
542                     "LinkDownstreamBandwidthKbps"));
543         }
544         return builder;
545     }
546 
547     @Rpc(description = "register a network callback")
connectivityRegisterNetworkCallback(@pcParametername = "configJson") JSONObject configJson)548     public String connectivityRegisterNetworkCallback(@RpcParameter(name = "configJson")
549     JSONObject configJson) throws JSONException {
550         NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson);
551         mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL);
552         mManager.registerNetworkCallback(networkRequest, mNetworkCallback);
553         String key = mNetworkCallback.mId;
554         mNetworkCallbackMap.put(key, mNetworkCallback);
555         return key;
556     }
557 
558     @Rpc(description = "unregister a network callback")
connectivityUnregisterNetworkCallback(@pcParametername = "key") String key)559     public Boolean connectivityUnregisterNetworkCallback(@RpcParameter(name = "key")
560     String key) {
561         mNetworkCallback = mNetworkCallbackMap.get(key);
562         if (mNetworkCallback != null) {
563             mNetworkCallbackMap.remove(key);
564             mManager.unregisterNetworkCallback(mNetworkCallback);
565             return true;
566         } else {
567             return false;
568         }
569     }
570 
571     @Rpc(description = "register a default network callback")
connectivityRegisterDefaultNetworkCallback()572     public String connectivityRegisterDefaultNetworkCallback() {
573         mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL);
574         mManager.registerDefaultNetworkCallback(mNetworkCallback);
575         String key = mNetworkCallback.mId;
576         mNetworkCallbackMap.put(key, mNetworkCallback);
577         return key;
578     }
579 
580     @Rpc(description = "request a network")
connectivityRequestNetwork(@pcParametername = "configJson") JSONObject configJson)581     public String connectivityRequestNetwork(@RpcParameter(name = "configJson")
582     JSONObject configJson) throws JSONException {
583         NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson);
584         mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL);
585         mManager.requestNetwork(networkRequest, mNetworkCallback);
586         String key = mNetworkCallback.mId;
587         mNetworkCallbackMap.put(key, mNetworkCallback);
588         return key;
589     }
590 
591     @Rpc(description = "Request a Wi-Fi Aware network")
connectivityRequestWifiAwareNetwork(@pcParametername = "configJson") JSONObject configJson)592     public String connectivityRequestWifiAwareNetwork(@RpcParameter(name = "configJson")
593             JSONObject configJson) throws JSONException {
594         NetworkRequest networkRequest = buildWifiAwareNetworkRequestFromJson(configJson);
595         mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL);
596         mManager.requestNetwork(networkRequest, mNetworkCallback);
597         String key = mNetworkCallback.mId;
598         mNetworkCallbackMap.put(key, mNetworkCallback);
599         return key;
600     }
601 
602     /**
603      * Initiates a network request {@link NetworkRequest} using {@link WifiNetworkSpecifier}.
604      *
605      * @param wNs JSONObject Dictionary of wifi network specifier parameters
606      * @param timeoutInMs Timeout for the request. 0 indicates no timeout.
607      * @throws JSONException
608      * @throws GeneralSecurityException
609      */
610     @Rpc(description = "Initiates a network request using the provided network specifier")
connectivityRequestWifiNetwork( @pcParametername = "wifiNetworkSpecifier") JSONObject wNs, @RpcParameter(name = "timeoutInMS") Integer timeoutInMs)611     public String connectivityRequestWifiNetwork(
612             @RpcParameter(name = "wifiNetworkSpecifier") JSONObject wNs,
613             @RpcParameter(name = "timeoutInMS") Integer timeoutInMs)
614             throws JSONException, GeneralSecurityException {
615         NetworkRequest networkRequest = new NetworkRequest.Builder()
616                 .addTransportType(TRANSPORT_WIFI)
617                 .setNetworkSpecifier(WifiManagerFacade.genWifiNetworkSpecifier(wNs))
618                 .build();
619         mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL);
620         if (timeoutInMs != 0) {
621             mManager.requestNetwork(networkRequest, mNetworkCallback, timeoutInMs);
622         } else {
623             mManager.requestNetwork(networkRequest, mNetworkCallback);
624         }
625         String key = mNetworkCallback.mId;
626         mNetworkCallbackMap.put(key, mNetworkCallback);
627         return key;
628     }
629 
630     @Rpc(description = "Stop listening for connectivity changes")
connectivityStopTrackingConnectivityStateChange()631     public void connectivityStopTrackingConnectivityStateChange() {
632         if (mTrackingConnectivityStateChange) {
633             mTrackingConnectivityStateChange = false;
634             mContext.unregisterReceiver(mConnectivityReceiver);
635         }
636     }
637 
638     @Rpc(description = "Get the extra information about the network state provided by lower network layers.")
connectivityNetworkGetActiveConnectionExtraInfo()639     public String connectivityNetworkGetActiveConnectionExtraInfo() {
640         NetworkInfo current = mManager.getActiveNetworkInfo();
641         if (current == null) {
642             Log.d("No network is active at the moment.");
643             return null;
644         }
645         return current.getExtraInfo();
646     }
647 
648     @Rpc(description = "Return the subtype name of the current network, null if not connected")
connectivityNetworkGetActiveConnectionSubtypeName()649     public String connectivityNetworkGetActiveConnectionSubtypeName() {
650         NetworkInfo current = mManager.getActiveNetworkInfo();
651         if (current == null) {
652             Log.d("No network is active at the moment.");
653             return null;
654         }
655         return current.getSubtypeName();
656     }
657 
658     @Rpc(description = "Return a human-readable name describe the type of the network, e.g. WIFI")
connectivityNetworkGetActiveConnectionTypeName()659     public String connectivityNetworkGetActiveConnectionTypeName() {
660         NetworkInfo current = mManager.getActiveNetworkInfo();
661         if (current == null) {
662             Log.d("No network is active at the moment.");
663             return null;
664         }
665         return current.getTypeName();
666     }
667 
668     @Rpc(description = "Get connection status information about all network types supported by the device.")
connectivityNetworkGetAllInfo()669     public NetworkInfo[] connectivityNetworkGetAllInfo() {
670         return mManager.getAllNetworkInfo();
671     }
672 
673     @Rpc(description = "Get connection status information about all network types supported by the device.")
connectivityNetworkGetAllCapabilities()674     public NetworkCapabilities[] connectivityNetworkGetAllCapabilities() {
675         Network[] networks = mManager.getAllNetworks();
676         NetworkCapabilities[] networkCapabilties = new NetworkCapabilities[networks.length];
677         for (int i = 0; i < networks.length; i++) {
678             networkCapabilties[i] = mManager.getNetworkCapabilities(networks[i]);
679         }
680         return networkCapabilties;
681     }
682 
683     @Rpc(description = "Check whether the active network is connected to the Internet.")
connectivityNetworkIsConnected()684     public Boolean connectivityNetworkIsConnected() {
685         NetworkInfo current = mManager.getActiveNetworkInfo();
686         if (current == null) {
687             Log.d("No network is active at the moment.");
688             return false;
689         }
690         return current.isConnected();
691     }
692 
693     @Rpc(description = "Checks the airplane mode setting.",
694             returns = "True if airplane mode is enabled.")
connectivityCheckAirplaneMode()695     public Boolean connectivityCheckAirplaneMode() {
696         try {
697             return Settings.Global.getInt(mService.getContentResolver(),
698                     Settings.Global.AIRPLANE_MODE_ON) == AIRPLANE_MODE_ON;
699         } catch (Settings.SettingNotFoundException e) {
700             Log.e("Settings.Global.AIRPLANE_MODE_ON not found!");
701             return false;
702         }
703     }
704 
705     @Rpc(description = "Toggles airplane mode on and off.",
706             returns = "True if airplane mode is enabled.")
connectivityToggleAirplaneMode(@pcParametername = "enabled") @pcOptional Boolean enabled)707     public void connectivityToggleAirplaneMode(@RpcParameter(name = "enabled")
708     @RpcOptional
709     Boolean enabled) {
710         if (enabled == null) {
711             enabled = !connectivityCheckAirplaneMode();
712         }
713         mManager.setAirplaneMode(enabled);
714     }
715 
716     /**
717     * Check global data roaming setting.
718     * @return True if roaming is enabled; false otherwise.
719     */
720     @Rpc(description = "Checks data roaming mode setting.",
721             returns = "True if data roaming mode is enabled.")
connectivityCheckDataRoamingMode()722     public Boolean connectivityCheckDataRoamingMode() {
723         return mTelephonyManager.isDataRoamingEnabled();
724     }
725 
726     /**
727     * Enable or disable data roaming.
728     * @param roaming 1: Enable data roaming; 0: Disable data roaming.
729     * @return True for setting roaming mode successfully; false otherwise.
730     */
731     @Rpc(description = "Set Data Roaming Enabled or Disabled")
connectivitySetDataRoaming( @pcParametername = "roaming") Integer roaming)732     public boolean connectivitySetDataRoaming(
733             @RpcParameter(name = "roaming") Integer roaming) {
734         Log.d("connectivitySetDataRoaming by SubscriptionManager");
735         return Settings.Global.putInt(mService.getContentResolver(),
736                     Settings.Global.DATA_ROAMING, roaming);
737     }
738 
739     @Rpc(description = "Check if tethering supported or not.",
740             returns = "True if tethering is supported.")
connectivityIsTetheringSupported()741     public boolean connectivityIsTetheringSupported() {
742         return mManager.isTetheringSupported();
743     }
744 
745     @Rpc(description = "Call to start tethering with a provisioning check if needed")
connectivityStartTethering(@pcParametername = "type") Integer type, @RpcParameter(name = "showProvisioningUi") Boolean showProvisioningUi)746     public void connectivityStartTethering(@RpcParameter(name = "type") Integer type,
747             @RpcParameter(name = "showProvisioningUi") Boolean showProvisioningUi) {
748         Log.d("startTethering for type: " + type + " showProvUi: " + showProvisioningUi);
749         OnStartTetheringCallback tetherCallback = new OnStartTetheringCallback();
750         mManager.startTethering(type, showProvisioningUi, tetherCallback);
751     }
752 
753     @Rpc(description = "Call to stop tethering")
connectivityStopTethering(@pcParametername = "type") Integer type)754     public void connectivityStopTethering(@RpcParameter(name = "type") Integer type) {
755         Log.d("stopTethering for type: " + type);
756         mManager.stopTethering(type);
757     }
758 
getInetAddrsForInterface(String ifaceName)759     private Enumeration<InetAddress> getInetAddrsForInterface(String ifaceName) {
760         NetworkInterface iface = null;
761         try {
762             iface = NetworkInterface.getByName(ifaceName);
763         } catch (SocketException e) {
764             return null;
765         }
766 
767         if (iface == null)
768             return null;
769         return iface.getInetAddresses();
770     }
771 
772     @Rpc(description = "Returns the link local IPv6 address of the interface.")
connectivityGetLinkLocalIpv6Address(@pcParametername = "ifaceName") String ifaceName)773     public String connectivityGetLinkLocalIpv6Address(@RpcParameter(name = "ifaceName")
774             String ifaceName) {
775         Inet6Address inet6Address = null;
776         Enumeration<InetAddress> inetAddresses = getInetAddrsForInterface(ifaceName);
777         if (inetAddresses == null) {
778             return null;
779         }
780 
781         while (inetAddresses.hasMoreElements()) {
782             InetAddress addr = inetAddresses.nextElement();
783             if (addr instanceof Inet6Address) {
784                 if (((Inet6Address) addr).isLinkLocalAddress()) {
785                     inet6Address = (Inet6Address) addr;
786                     break;
787                 }
788             }
789         }
790 
791         if (inet6Address == null) {
792             return null;
793         }
794 
795         return inet6Address.getHostAddress();
796     }
797 
798     @Rpc(description = "Return IPv4 address of an interface")
connectivityGetIPv4Addresses( @pcParametername = "ifaceName") String ifaceName)799     public List<String> connectivityGetIPv4Addresses(
800             @RpcParameter(name = "ifaceName") String ifaceName) {
801         Enumeration<InetAddress> inetAddresses
802                 = getInetAddrsForInterface(ifaceName);
803         if (inetAddresses == null)
804             return null;
805 
806         List<String> inetAddrs = new ArrayList<String>();
807         while (inetAddresses.hasMoreElements()) {
808             InetAddress addr = inetAddresses.nextElement();
809             if (addr instanceof Inet4Address) {
810                 Inet4Address inet4Address =  (Inet4Address) addr;
811                 inetAddrs.add(inet4Address.getHostAddress());
812             }
813         }
814 
815         return inetAddrs;
816     }
817 
818     @Rpc(description = "Return IPv6 addrs of an interface except link local")
connectivityGetIPv6Addresses( @pcParametername = "ifaceName") String ifaceName)819     public List<String> connectivityGetIPv6Addresses(
820             @RpcParameter(name = "ifaceName") String ifaceName) {
821         Enumeration<InetAddress> inetAddresses
822                 = getInetAddrsForInterface(ifaceName);
823         if (inetAddresses == null)
824             return null;
825 
826         List<String> inetAddrs = new ArrayList<String>();
827         while (inetAddresses.hasMoreElements()) {
828             InetAddress addr = inetAddresses.nextElement();
829             if (addr instanceof Inet6Address) {
830                 if (((Inet6Address) addr).isLinkLocalAddress())
831                     continue;
832                 Inet6Address inet6Address =  (Inet6Address) addr;
833                 inetAddrs.add(inet6Address.getHostAddress());
834             }
835         }
836 
837         return inetAddrs;
838     }
839 
840     @Rpc(description = "Returns active link properties")
connectivityGetActiveLinkProperties()841     public LinkProperties connectivityGetActiveLinkProperties() {
842         return mManager.getActiveLinkProperties();
843     }
844 
845     /**
846      * Get the IPv4 default gateway for the active network.
847      */
848     @Rpc(description = "Return default gateway of the active network")
connectivityGetIPv4DefaultGateway()849     public String connectivityGetIPv4DefaultGateway() {
850         LinkProperties linkProp = mManager.getActiveLinkProperties();
851         List<RouteInfo> routeInfos = linkProp.getRoutes();
852         for (RouteInfo routeInfo: routeInfos) {
853             if (routeInfo.isIPv4Default()) {
854                 return routeInfo.getGateway().toString().split("/")[1];
855             }
856         }
857         return null;
858     }
859 
860     @Rpc(description = "Returns all IP addresses of the active link")
connectivityGetAllAddressesOfActiveLink()861     public List<InetAddress> connectivityGetAllAddressesOfActiveLink() {
862         LinkProperties linkProp = mManager.getActiveLinkProperties();
863         return linkProp.getAllAddresses();
864     }
865 
866     @Rpc(description = "Check if active link has default IPv6 route")
connectivityHasIPv6DefaultRoute()867     public boolean connectivityHasIPv6DefaultRoute() {
868         LinkProperties linkProp = mManager.getActiveLinkProperties();
869         return linkProp.hasIPv6DefaultRoute();
870     }
871 
872     @Rpc(description = "Factory reset of network policies")
connectivityFactoryResetNetworkPolicies(String subscriberId)873     public void connectivityFactoryResetNetworkPolicies(String subscriberId) {
874         mNetPolicyManager.factoryReset(subscriberId);
875     }
876 
877     /**
878      * Method to set data warning limit on the device.
879      */
880     @Rpc(description = "Set data warning limit for subscriber ID")
connectivitySetDataWarningLimit(String subscriberId, Long dataLimit)881     public void connectivitySetDataWarningLimit(String subscriberId, Long dataLimit) {
882         NetworkPolicy[] allPolicies = mNetPolicyManager.getNetworkPolicies();
883         for (int i = 0; i < allPolicies.length; i++) {
884             String subId = allPolicies[i].template.getSubscriberId();
885             if (subId != null && subId.equals(subscriberId)) {
886                 allPolicies[i].warningBytes = dataLimit.longValue();
887                 break;
888             }
889         }
890         mNetPolicyManager.setNetworkPolicies(allPolicies);
891     }
892 
893     /**
894      * Method to set data usage limit on the device.
895      */
896     @Rpc(description = "Set data usage limit for subscriber ID")
connectivitySetDataUsageLimit(String subscriberId, Long dataLimit)897     public void connectivitySetDataUsageLimit(String subscriberId, Long dataLimit) {
898         NetworkPolicy[] allPolicies = mNetPolicyManager.getNetworkPolicies();
899         for (int i = 0; i < allPolicies.length; i++) {
900             String subId = allPolicies[i].template.getSubscriberId();
901             if (subId != null && subId.equals(subscriberId)) {
902                 allPolicies[i].limitBytes = dataLimit.longValue();
903                 break;
904             }
905         }
906         mNetPolicyManager.setNetworkPolicies(allPolicies);
907     }
908 
909     /**
910      * Method to get data usage limit on the device.
911      */
912     @Rpc(description = "Get data usage limit for subscriber ID")
connectivityGetDataUsageLimit(String subscriberId)913     public long connectivityGetDataUsageLimit(String subscriberId) {
914         NetworkPolicy[] allPolicies = mNetPolicyManager.getNetworkPolicies();
915         for (int i = 0; i < allPolicies.length; i++) {
916             String subId = allPolicies[i].template.getSubscriberId();
917             if (subId != null && subId.equals(subscriberId)) return allPolicies[i].limitBytes;
918         }
919         return -1;
920     }
921 
922     /**
923      * Method to get data warning limit on the device
924      */
925     @Rpc(description = "Get data warning limit for subscriber ID")
connectivityGetDataWarningLimit(String subscriberId)926     public long connectivityGetDataWarningLimit(String subscriberId) {
927         NetworkPolicy[] allPolicies = mNetPolicyManager.getNetworkPolicies();
928         for (int i = 0; i < allPolicies.length; i++) {
929             String subId = allPolicies[i].template.getSubscriberId();
930             if (subId != null && subId.equals(subscriberId)) return allPolicies[i].warningBytes;
931         }
932         return -1;
933     }
934 
935     @Rpc(description = "Get network stats for device")
connectivityQuerySummaryForDevice(Integer connType, String subscriberId, Long startTime, Long endTime)936     public long connectivityQuerySummaryForDevice(Integer connType,
937             String subscriberId, Long startTime, Long endTime)
938             throws SecurityException, RemoteException {
939         Bucket bucket = mNetStatsManager.querySummaryForDevice(
940               connType, subscriberId, startTime, endTime);
941         return bucket.getTxBytes() + bucket.getRxBytes();
942     }
943 
944     @Rpc(description = "Get network stats for device - Rx bytes")
connectivityQuerySummaryForDeviceRxBytes(Integer connType, String subscriberId, Long startTime, Long endTime)945     public long connectivityQuerySummaryForDeviceRxBytes(Integer connType,
946             String subscriberId, Long startTime, Long endTime)
947             throws SecurityException, RemoteException {
948         Bucket bucket = mNetStatsManager.querySummaryForDevice(
949               connType, subscriberId, startTime, endTime);
950         return bucket.getRxBytes();
951     }
952 
953     @Rpc(description = "Get network stats for UID")
connectivityQueryDetailsForUid(Integer connType, String subscriberId, Long startTime, Long endTime, Integer uid)954     public long connectivityQueryDetailsForUid(Integer connType,
955             String subscriberId, Long startTime, Long endTime, Integer uid)
956             throws SecurityException, RemoteException {
957         long totalData = 0;
958         NetworkStats netStats = mNetStatsManager.queryDetailsForUid(
959                 connType, subscriberId, startTime, endTime, uid);
960         Bucket bucket = new Bucket();
961         while(netStats.hasNextBucket() && netStats.getNextBucket(bucket)) {
962             totalData += bucket.getTxBytes() + bucket.getRxBytes();
963         }
964         netStats.close();
965         return totalData;
966     }
967 
968     @Rpc(description = "Get network stats for UID - Rx bytes")
connectivityQueryDetailsForUidRxBytes(Integer connType, String subscriberId, Long startTime, Long endTime, Integer uid)969     public long connectivityQueryDetailsForUidRxBytes(Integer connType,
970             String subscriberId, Long startTime, Long endTime, Integer uid)
971             throws SecurityException, RemoteException {
972         long rxBytes = 0;
973         NetworkStats netStats = mNetStatsManager.queryDetailsForUid(
974                 connType, subscriberId, startTime, endTime, uid);
975         Bucket bucket = new Bucket();
976         while(netStats.hasNextBucket() && netStats.getNextBucket(bucket)) {
977             rxBytes += bucket.getRxBytes();
978         }
979         netStats.close();
980         return rxBytes;
981     }
982 
983     @Rpc(description = "Returns all interfaces on the android deivce")
connectivityGetNetworkInterfaces()984     public List<NetworkInterface> connectivityGetNetworkInterfaces() {
985         List<NetworkInterface> interfaces = null;
986         try {
987             interfaces = Collections.list(
988                   NetworkInterface.getNetworkInterfaces());
989         } catch (SocketException e) {
990             return null;
991         };
992 
993         return interfaces;
994     }
995 
996     /**
997     * Get multipath preference for a given network.
998     * @param networkId : network id of wifi or cell network
999     * @return Integer value of multipath preference
1000     */
1001     @Rpc(description = "Return Multipath preference for a given network")
connectivityGetMultipathPreferenceForNetwork(Long networkId)1002     public Integer connectivityGetMultipathPreferenceForNetwork(Long networkId) {
1003         Network network = sNetworkHashMap.get(networkId.longValue());
1004         return mManager.getMultipathPreference(network);
1005     }
1006 
1007     /**
1008     * Return HashMap key for Network object.
1009     * @return long value of Network object key
1010     */
1011     @Rpc(description = "Return key to active network stored in a hash map")
connectivityGetActiveNetwork()1012     public long connectivityGetActiveNetwork() {
1013         Network network = mManager.getActiveNetwork();
1014         long id = network.getNetworkHandle();
1015         sNetworkHashMap.put(id, network);
1016         return id;
1017     }
1018 
1019     /**
1020     * Get mutlipath preference for active network.
1021     * @return Integer value of multipath preference
1022     */
1023     @Rpc(description = "Return Multipath preference for active network")
connectivityGetMultipathPreference()1024     public Integer connectivityGetMultipathPreference() {
1025         Network network = mManager.getActiveNetwork();
1026         return mManager.getMultipathPreference(network);
1027     }
1028 
1029     /**
1030     * Download file of a given url using Network#openConnection call.
1031     * @param networkId : network id of wifi or cell network
1032     * @param urlString : url in String format
1033     */
1034     @Rpc(description = "Download file on a given network with Network#openConnection")
connectivityNetworkOpenConnection(Long networkId, String urlString)1035     public void connectivityNetworkOpenConnection(Long networkId, String urlString) {
1036         Network network = sNetworkHashMap.get(networkId.longValue());
1037         try {
1038             URL url = new URL(urlString);
1039             URLConnection urlConnection = network.openConnection(url);
1040             File outFile = FileUtils.getExternalDownload();
1041             int lastIdx = urlString.lastIndexOf('/');
1042             String filename = urlString.substring(lastIdx + 1);
1043             Log.d("Using name from url: " + filename);
1044             outFile = new File(outFile, filename);
1045             InputStream in = new BufferedInputStream(urlConnection.getInputStream());
1046             OutputStream output = new FileOutputStream(outFile);
1047             ByteStreams.copy(in, output);
1048         } catch (IOException e) {
1049             Log.e("Failed to download file: " + e.toString());
1050         }
1051     }
1052 
1053     /**
1054      * Sets the global proxy using the given information.
1055      *
1056      * @param hostname hostname of the proxy
1057      * @param port     port set on the proxy server
1058      * @param exclList List of hostnames excluded
1059      */
1060     @Rpc(description = "Set global proxy")
connectivitySetGlobalProxy(String hostname, Integer port, String exclList)1061     public void connectivitySetGlobalProxy(String hostname, Integer port, String exclList) {
1062         ProxyInfo proxyInfo = new ProxyInfo(hostname, port.intValue(), exclList);
1063         mManager.setGlobalProxy(proxyInfo);
1064     }
1065 
1066     /**
1067      * Sets the global proxy using a PAC URI.
1068      *
1069      * @param pac PAC URI in string
1070      */
1071     @Rpc(description = "Set global proxy with proxy autoconfig")
connectivitySetGlobalPacProxy(String pac)1072     public void connectivitySetGlobalPacProxy(String pac) {
1073         Uri uri = Uri.parse(pac);
1074         ProxyInfo proxyInfo = new ProxyInfo(uri);
1075         mManager.setGlobalProxy(proxyInfo);
1076     }
1077 
1078     /**
1079      * Gets the global proxy settings.
1080      *
1081      * @return ProxyInfo object in dictionary
1082      */
1083     @Rpc(description = "Get global proxy")
connectivityGetGlobalProxy()1084     public ProxyInfo connectivityGetGlobalProxy() {
1085         ProxyInfo proxyInfo = mManager.getGlobalProxy();
1086         if (proxyInfo == null) return null;
1087         return proxyInfo;
1088     }
1089 
1090     /**
1091      * Resets the global proxy settings.
1092      */
1093     @Rpc(description = "Reset global proxy")
connectivityResetGlobalProxy()1094     public void connectivityResetGlobalProxy() {
1095         mManager.setGlobalProxy(null);
1096     }
1097 
1098     /**
1099      * Check if active network is metered.
1100      */
1101     @Rpc(description = "Is active network metered")
connectivityIsActiveNetworkMetered()1102     public boolean connectivityIsActiveNetworkMetered() {
1103         return mManager.isActiveNetworkMetered();
1104     }
1105 
1106     /**
1107      * Check if device connected to WiFi network
1108      */
1109     @Rpc(description = "Is active network WiFi")
connectivityIsActiveNetworkWiFi()1110     public boolean connectivityIsActiveNetworkWiFi() {
1111         NetworkInfo mWifi = mManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
1112         return mWifi.isConnected();
1113     }
1114 
1115     @Override
shutdown()1116     public void shutdown() {
1117         connectivityStopTrackingConnectivityStateChange();
1118         for (NetworkCallback networkCallback : mNetworkCallbackMap.values()) {
1119             mManager.unregisterNetworkCallback(networkCallback);
1120         }
1121     }
1122 }
1123