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