1 /*
2  * Copyright (C) 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.googlecode.android_scripting.facade;
18 
19 import android.app.Service;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.net.ConnectivityManager;
25 import android.net.ConnectivityManager.NetworkCallback;
26 import android.net.ConnectivityManager.PacketKeepaliveCallback;
27 import android.net.ConnectivityManager.PacketKeepalive;
28 import android.net.LinkProperties;
29 import android.net.Network;
30 import android.net.NetworkCapabilities;
31 import android.net.NetworkRequest;
32 import android.net.NetworkInfo;
33 import android.provider.Settings.SettingNotFoundException;
34 import android.os.Bundle;
35 
36 import com.googlecode.android_scripting.Log;
37 import com.googlecode.android_scripting.facade.telephony.TelephonyConstants;
38 import com.googlecode.android_scripting.facade.telephony.TelephonyEvents;
39 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
40 import com.googlecode.android_scripting.rpc.Rpc;
41 import com.googlecode.android_scripting.rpc.RpcOptional;
42 import com.googlecode.android_scripting.rpc.RpcParameter;
43 
44 import org.json.JSONArray;
45 import org.json.JSONException;
46 import org.json.JSONObject;
47 
48 import java.net.InetAddress;
49 import java.net.UnknownHostException;
50 import java.util.HashMap;
51 
52 /**
53  * Access ConnectivityManager functions.
54  */
55 public class ConnectivityManagerFacade extends RpcReceiver {
56 
57     public static int AIRPLANE_MODE_OFF = 0;
58     public static int AIRPLANE_MODE_ON = 1;
59 
60     class ConnectivityReceiver extends BroadcastReceiver {
61 
62         @Override
onReceive(Context context, Intent intent)63         public void onReceive(Context context, Intent intent) {
64             String action = intent.getAction();
65 
66             if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
67                 Log.e("ConnectivityReceiver received non-connectivity action!");
68                 return;
69             }
70 
71             Bundle b = intent.getExtras();
72 
73             if (b == null) {
74                 Log.e("ConnectivityReceiver failed to receive extras!");
75                 return;
76             }
77 
78             int netType =
79                     b.getInt(ConnectivityManager.EXTRA_NETWORK_TYPE,
80                             ConnectivityManager.TYPE_NONE);
81 
82             if (netType == ConnectivityManager.TYPE_NONE) {
83                 Log.i("ConnectivityReceiver received change to TYPE_NONE.");
84                 return;
85             }
86 
87             /*
88              * Technically there is a race condition here, but retrieving the NetworkInfo from the
89              * bundle is deprecated. See ConnectivityManager.EXTRA_NETWORK_INFO
90              */
91             for (NetworkInfo info : mManager.getAllNetworkInfo()) {
92                 if (info.getType() == netType) {
93                     mEventFacade.postEvent(TelephonyConstants.EventConnectivityChanged, info);
94                 }
95             }
96         }
97     }
98 
99     class PacketKeepaliveReceiver extends PacketKeepaliveCallback {
100         public static final int EVENT_INVALID = -1;
101         public static final int EVENT_NONE = 0;
102         public static final int EVENT_STARTED = 1 << 0;
103         public static final int EVENT_STOPPED = 1 << 1;
104         public static final int EVENT_ERROR = 1 << 2;
105         public static final int EVENT_ALL = EVENT_STARTED |
106                 EVENT_STOPPED |
107                 EVENT_ERROR;
108         private int mEvents;
109         public String mId;
110         public PacketKeepalive mPacketKeepalive;
111 
PacketKeepaliveReceiver(int events)112         public PacketKeepaliveReceiver(int events) {
113             super();
114             mEvents = events;
115             mId = this.toString();
116         }
117 
startListeningForEvents(int events)118         public void startListeningForEvents(int events) {
119             mEvents |= events & EVENT_ALL;
120         }
121 
stopListeningForEvents(int events)122         public void stopListeningForEvents(int events) {
123             mEvents &= ~(events & EVENT_ALL);
124         }
125 
126         @Override
onStarted()127         public void onStarted() {
128             Log.d("PacketKeepaliveCallback on start!");
129             if ((mEvents & EVENT_STARTED) == EVENT_STARTED) {
130                 mEventFacade.postEvent(
131                     TelephonyConstants.EventPacketKeepaliveCallback,
132                     new TelephonyEvents.PacketKeepaliveEvent(
133                         mId,
134                         getPacketKeepaliveReceiverEventString(EVENT_STARTED)));
135             }
136         }
137 
138         @Override
onStopped()139         public void onStopped() {
140             Log.d("PacketKeepaliveCallback on stop!");
141             if ((mEvents & EVENT_STOPPED) == EVENT_STOPPED) {
142                 mEventFacade.postEvent(
143                     TelephonyConstants.EventPacketKeepaliveCallback,
144                     new TelephonyEvents.PacketKeepaliveEvent(
145                         mId,
146                         getPacketKeepaliveReceiverEventString(EVENT_STOPPED)));
147             }
148         }
149 
150         @Override
onError(int error)151         public void onError(int error) {
152             Log.d("PacketKeepaliveCallback on error! - code:" + error);
153             if ((mEvents & EVENT_ERROR) == EVENT_ERROR) {
154                 mEventFacade.postEvent(
155                     TelephonyConstants.EventPacketKeepaliveCallback,
156                     new TelephonyEvents.PacketKeepaliveEvent(
157                         mId,
158                         getPacketKeepaliveReceiverEventString(EVENT_ERROR)));
159             }
160         }
161     }
162 
163     class NetworkCallback extends ConnectivityManager.NetworkCallback {
164         public static final int EVENT_INVALID = -1;
165         public static final int EVENT_NONE = 0;
166         public static final int EVENT_PRECHECK = 1 << 0;
167         public static final int EVENT_AVAILABLE = 1 << 1;
168         public static final int EVENT_LOSING = 1 << 2;
169         public static final int EVENT_LOST = 1 << 3;
170         public static final int EVENT_UNAVAILABLE = 1 << 4;
171         public static final int EVENT_CAPABILITIES_CHANGED = 1 << 5;
172         public static final int EVENT_SUSPENDED = 1 << 6;
173         public static final int EVENT_RESUMED = 1 << 7;
174         public static final int EVENT_LINK_PROPERTIES_CHANGED = 1 << 8;
175         public static final int EVENT_ALL = EVENT_PRECHECK |
176                 EVENT_AVAILABLE |
177                 EVENT_LOSING |
178                 EVENT_LOST |
179                 EVENT_UNAVAILABLE |
180                 EVENT_CAPABILITIES_CHANGED |
181                 EVENT_SUSPENDED |
182                 EVENT_RESUMED |
183                 EVENT_LINK_PROPERTIES_CHANGED;
184 
185         private int mEvents;
186         public String mId;
187 
NetworkCallback(int events)188         public NetworkCallback(int events) {
189             super();
190             mEvents = events;
191             mId = this.toString();
192         }
193 
startListeningForEvents(int events)194         public void startListeningForEvents(int events) {
195             mEvents |= events & EVENT_ALL;
196         }
197 
stopListeningForEvents(int events)198         public void stopListeningForEvents(int events) {
199             mEvents &= ~(events & EVENT_ALL);
200         }
201 
202         @Override
onPreCheck(Network network)203         public void onPreCheck(Network network) {
204             Log.d("NetworkCallback onPreCheck");
205             if ((mEvents & EVENT_PRECHECK) == EVENT_PRECHECK) {
206                 mEventFacade.postEvent(
207                     TelephonyConstants.EventNetworkCallback,
208                     new TelephonyEvents.NetworkCallbackEvent(
209                         mId,
210                         getNetworkCallbackEventString(EVENT_PRECHECK),
211                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE,
212                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE));
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                     TelephonyConstants.EventNetworkCallback,
222                     new TelephonyEvents.NetworkCallbackEvent(
223                         mId,
224                         getNetworkCallbackEventString(EVENT_AVAILABLE),
225                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE,
226                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE));
227             }
228         }
229 
230         @Override
onLosing(Network network, int maxMsToLive)231         public void onLosing(Network network, int maxMsToLive) {
232             Log.d("NetworkCallback onLosing");
233             if ((mEvents & EVENT_LOSING) == EVENT_LOSING) {
234                 mEventFacade.postEvent(
235                     TelephonyConstants.EventNetworkCallback,
236                     new TelephonyEvents.NetworkCallbackEvent(
237                         mId,
238                         getNetworkCallbackEventString(EVENT_LOSING),
239                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE,
240                         maxMsToLive));
241             }
242         }
243 
244         @Override
onLost(Network network)245         public void onLost(Network network) {
246             Log.d("NetworkCallback onLost");
247             if ((mEvents & EVENT_LOST) == EVENT_LOST) {
248                 mEventFacade.postEvent(
249                     TelephonyConstants.EventNetworkCallback,
250                     new TelephonyEvents.NetworkCallbackEvent(
251                         mId,
252                         getNetworkCallbackEventString(EVENT_LOST),
253                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE,
254                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE));
255             }
256         }
257 
258         @Override
onUnavailable()259         public void onUnavailable() {
260             Log.d("NetworkCallback onUnavailable");
261             if ((mEvents & EVENT_UNAVAILABLE) == EVENT_UNAVAILABLE) {
262                 mEventFacade.postEvent(
263                     TelephonyConstants.EventNetworkCallback,
264                     new TelephonyEvents.NetworkCallbackEvent(
265                         mId,
266                         getNetworkCallbackEventString(EVENT_UNAVAILABLE),
267                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE,
268                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE));
269             }
270         }
271 
272         @Override
onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)273         public void onCapabilitiesChanged(Network network,
274                 NetworkCapabilities networkCapabilities) {
275             Log.d("NetworkCallback onCapabilitiesChanged. RSSI:" +
276                     networkCapabilities.getSignalStrength());
277             if ((mEvents & EVENT_CAPABILITIES_CHANGED) == EVENT_CAPABILITIES_CHANGED) {
278                 mEventFacade.postEvent(
279                     TelephonyConstants.EventNetworkCallback,
280                     new TelephonyEvents.NetworkCallbackEvent(
281                         mId,
282                         getNetworkCallbackEventString(EVENT_CAPABILITIES_CHANGED),
283                         networkCapabilities.getSignalStrength(),
284                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE));
285             }
286         }
287 
288         @Override
onNetworkSuspended(Network network)289         public void onNetworkSuspended(Network network) {
290             Log.d("NetworkCallback onNetworkSuspended");
291             if ((mEvents & EVENT_SUSPENDED) == EVENT_SUSPENDED) {
292                 mEventFacade.postEvent(
293                     TelephonyConstants.EventNetworkCallback,
294                     new TelephonyEvents.NetworkCallbackEvent(
295                         mId,
296                         getNetworkCallbackEventString(EVENT_SUSPENDED),
297                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE,
298                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE));
299             }
300         }
301 
302         @Override
onLinkPropertiesChanged(Network network, LinkProperties linkProperties)303         public void onLinkPropertiesChanged(Network network,
304                 LinkProperties linkProperties) {
305             Log.d("NetworkCallback onLinkPropertiesChanged");
306             if ((mEvents & EVENT_LINK_PROPERTIES_CHANGED) == EVENT_LINK_PROPERTIES_CHANGED) {
307                 mEventFacade.postEvent(
308                     TelephonyConstants.EventNetworkCallback,
309                     new TelephonyEvents.NetworkCallbackEvent(
310                         mId,
311                         getNetworkCallbackEventString(EVENT_LINK_PROPERTIES_CHANGED),
312                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE,
313                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE));
314             }
315         }
316 
317         @Override
onNetworkResumed(Network network)318         public void onNetworkResumed(Network network) {
319             Log.d("NetworkCallback onNetworkResumed");
320             if ((mEvents & EVENT_RESUMED) == EVENT_RESUMED) {
321                 mEventFacade.postEvent(
322                     TelephonyConstants.EventNetworkCallback,
323                     new TelephonyEvents.NetworkCallbackEvent(
324                         mId,
325                         getNetworkCallbackEventString(EVENT_RESUMED),
326                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE,
327                         TelephonyEvents.NetworkCallbackEvent.INVALID_VALUE));
328             }
329         }
330     }
331 
getNetworkCallbackEvent(String event)332     private static int getNetworkCallbackEvent(String event) {
333         switch (event) {
334             case TelephonyConstants.NetworkCallbackPreCheck:
335                 return NetworkCallback.EVENT_PRECHECK;
336             case TelephonyConstants.NetworkCallbackAvailable:
337                 return NetworkCallback.EVENT_AVAILABLE;
338             case TelephonyConstants.NetworkCallbackLosing:
339                 return NetworkCallback.EVENT_LOSING;
340             case TelephonyConstants.NetworkCallbackLost:
341                 return NetworkCallback.EVENT_LOST;
342             case TelephonyConstants.NetworkCallbackUnavailable:
343                 return NetworkCallback.EVENT_UNAVAILABLE;
344             case TelephonyConstants.NetworkCallbackCapabilitiesChanged:
345                 return NetworkCallback.EVENT_CAPABILITIES_CHANGED;
346             case TelephonyConstants.NetworkCallbackSuspended:
347                 return NetworkCallback.EVENT_SUSPENDED;
348             case TelephonyConstants.NetworkCallbackResumed:
349                 return NetworkCallback.EVENT_RESUMED;
350             case TelephonyConstants.NetworkCallbackLinkPropertiesChanged:
351                 return NetworkCallback.EVENT_LINK_PROPERTIES_CHANGED;
352         }
353         return NetworkCallback.EVENT_INVALID;
354     }
355 
getNetworkCallbackEventString(int event)356     private static String getNetworkCallbackEventString(int event) {
357         switch (event) {
358             case NetworkCallback.EVENT_PRECHECK:
359                 return TelephonyConstants.NetworkCallbackPreCheck;
360             case NetworkCallback.EVENT_AVAILABLE:
361                 return TelephonyConstants.NetworkCallbackAvailable;
362             case NetworkCallback.EVENT_LOSING:
363                 return TelephonyConstants.NetworkCallbackLosing;
364             case NetworkCallback.EVENT_LOST:
365                 return TelephonyConstants.NetworkCallbackLost;
366             case NetworkCallback.EVENT_UNAVAILABLE:
367                 return TelephonyConstants.NetworkCallbackUnavailable;
368             case NetworkCallback.EVENT_CAPABILITIES_CHANGED:
369                 return TelephonyConstants.NetworkCallbackCapabilitiesChanged;
370             case NetworkCallback.EVENT_SUSPENDED:
371                 return TelephonyConstants.NetworkCallbackSuspended;
372             case NetworkCallback.EVENT_RESUMED:
373                 return TelephonyConstants.NetworkCallbackResumed;
374             case NetworkCallback.EVENT_LINK_PROPERTIES_CHANGED:
375                 return TelephonyConstants.NetworkCallbackLinkPropertiesChanged;
376         }
377         return TelephonyConstants.NetworkCallbackInvalid;
378     }
379 
getPacketKeepaliveReceiverEvent(String event)380     private static int getPacketKeepaliveReceiverEvent(String event) {
381         switch (event) {
382             case TelephonyConstants.PacketKeepaliveCallbackStarted:
383                 return PacketKeepaliveReceiver.EVENT_STARTED;
384             case TelephonyConstants.PacketKeepaliveCallbackStopped:
385                 return PacketKeepaliveReceiver.EVENT_STOPPED;
386             case TelephonyConstants.PacketKeepaliveCallbackError:
387                 return PacketKeepaliveReceiver.EVENT_ERROR;
388         }
389         return PacketKeepaliveReceiver.EVENT_INVALID;
390     }
391 
getPacketKeepaliveReceiverEventString(int event)392     private static String getPacketKeepaliveReceiverEventString(int event) {
393         switch (event) {
394             case PacketKeepaliveReceiver.EVENT_STARTED:
395                 return TelephonyConstants.PacketKeepaliveCallbackStarted;
396             case PacketKeepaliveReceiver.EVENT_STOPPED:
397                 return TelephonyConstants.PacketKeepaliveCallbackStopped;
398             case PacketKeepaliveReceiver.EVENT_ERROR:
399                 return TelephonyConstants.PacketKeepaliveCallbackError;
400         }
401         return TelephonyConstants.PacketKeepaliveCallbackInvalid;
402     }
403 
404     private final ConnectivityManager mManager;
405     private final Service mService;
406     private final Context mContext;
407     private final ConnectivityReceiver mConnectivityReceiver;
408     private final EventFacade mEventFacade;
409     private PacketKeepalive mPacketKeepalive;
410     private NetworkCallback mNetworkCallback;
411     private static HashMap<String, PacketKeepaliveReceiver> mPacketKeepaliveReceiverMap =
412             new HashMap<String, PacketKeepaliveReceiver>();
413     private static HashMap<String, NetworkCallback> mNetworkCallbackMap =
414             new HashMap<String, NetworkCallback>();
415     private boolean mTrackingConnectivityStateChange;
416 
ConnectivityManagerFacade(FacadeManager manager)417     public ConnectivityManagerFacade(FacadeManager manager) {
418         super(manager);
419         mService = manager.getService();
420         mContext = mService.getBaseContext();
421         mManager = (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE);
422         mEventFacade = manager.getReceiver(EventFacade.class);
423         mConnectivityReceiver = new ConnectivityReceiver();
424         mTrackingConnectivityStateChange = false;
425     }
426 
427     @Rpc(description = "Listen for connectivity changes")
connectivityStartTrackingConnectivityStateChange()428     public void connectivityStartTrackingConnectivityStateChange() {
429         if (!mTrackingConnectivityStateChange) {
430             mTrackingConnectivityStateChange = true;
431             mContext.registerReceiver(mConnectivityReceiver,
432                     new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
433         }
434     }
435 
436     @Rpc(description = "start natt keep alive")
connectivityStartNattKeepalive(Integer intervalSeconds, String srcAddrString, Integer srcPort, String dstAddrString)437     public String connectivityStartNattKeepalive(Integer intervalSeconds, String srcAddrString,
438             Integer srcPort, String dstAddrString) throws UnknownHostException {
439         try {
440             Network mNetwork = mManager.getActiveNetwork();
441             InetAddress srcAddr = InetAddress.getByName(srcAddrString);
442             InetAddress dstAddr = InetAddress.getByName(dstAddrString);
443             Log.d("startNattKeepalive srcAddr:" + srcAddr.getHostAddress());
444             Log.d("startNattKeepalive dstAddr:" + dstAddr.getHostAddress());
445             Log.d("startNattKeepalive srcPort:" + srcPort);
446             Log.d("startNattKeepalive intervalSeconds:" + intervalSeconds);
447             PacketKeepaliveReceiver mPacketKeepaliveReceiver = new PacketKeepaliveReceiver(
448                     PacketKeepaliveReceiver.EVENT_ALL);
449             mPacketKeepalive = mManager.startNattKeepalive(mNetwork, (int) intervalSeconds,
450                     mPacketKeepaliveReceiver, srcAddr, (int) srcPort, dstAddr);
451             if (mPacketKeepalive != null) {
452                 mPacketKeepaliveReceiver.mPacketKeepalive = mPacketKeepalive;
453                 String key = mPacketKeepaliveReceiver.mId;
454                 mPacketKeepaliveReceiverMap.put(key, mPacketKeepaliveReceiver);
455                 return key;
456             } else {
457                 Log.e("startNattKeepalive fail, startNattKeepalive return null");
458                 return null;
459             }
460         } catch (UnknownHostException e) {
461             Log.e("startNattKeepalive UnknownHostException");
462             return null;
463         }
464     }
465 
466     @Rpc(description = "stop natt keep alive")
connectivityStopNattKeepalive(String key)467     public Boolean connectivityStopNattKeepalive(String key) {
468         PacketKeepaliveReceiver mPacketKeepaliveReceiver =
469                 mPacketKeepaliveReceiverMap.get(key);
470         if (mPacketKeepaliveReceiver != null) {
471             mPacketKeepaliveReceiverMap.remove(key);
472             mPacketKeepaliveReceiver.mPacketKeepalive.stop();
473             return true;
474         } else {
475             return false;
476         }
477     }
478 
479     @Rpc(description = "start listening for NattKeepalive Event")
connectivityNattKeepaliveStartListeningForEvent(String key, String eventString)480     public Boolean connectivityNattKeepaliveStartListeningForEvent(String key, String eventString) {
481         PacketKeepaliveReceiver mPacketKeepaliveReceiver =
482                 mPacketKeepaliveReceiverMap.get(key);
483         if (mPacketKeepaliveReceiver != null) {
484             int event = getPacketKeepaliveReceiverEvent(eventString);
485             if (event == PacketKeepaliveReceiver.EVENT_INVALID) {
486                 return false;
487             }
488             mPacketKeepaliveReceiver.startListeningForEvents(event);
489             return true;
490         } else {
491             return false;
492         }
493     }
494 
495     @Rpc(description = "stop listening for NattKeepalive Event")
connectivityNattKeepaliveStopListeningForEvent(String key, String eventString)496     public Boolean connectivityNattKeepaliveStopListeningForEvent(String key, String eventString) {
497         PacketKeepaliveReceiver mPacketKeepaliveReceiver =
498                 mPacketKeepaliveReceiverMap.get(key);
499         if (mPacketKeepaliveReceiver != null) {
500             int event = getPacketKeepaliveReceiverEvent(eventString);
501             if (event == PacketKeepaliveReceiver.EVENT_INVALID) {
502                 return false;
503             }
504             mPacketKeepaliveReceiver.stopListeningForEvents(event);
505             return true;
506         } else {
507             return false;
508         }
509     }
510 
511     @Rpc(description = "start listening for NetworkCallback Event")
connectivityNetworkCallbackStartListeningForEvent(String key, String eventString)512     public Boolean connectivityNetworkCallbackStartListeningForEvent(String key, String eventString) {
513         NetworkCallback mNetworkCallback = mNetworkCallbackMap.get(key);
514         if (mNetworkCallback != null) {
515             int event = getNetworkCallbackEvent(eventString);
516             if (event == NetworkCallback.EVENT_INVALID) {
517                 return false;
518             }
519             mNetworkCallback.startListeningForEvents(event);
520             return true;
521         } else {
522             return false;
523         }
524     }
525 
526     @Rpc(description = "stop listening for NetworkCallback Event")
connectivityNetworkCallbackStopListeningForEvent(String key, String eventString)527     public Boolean connectivityNetworkCallbackStopListeningForEvent(String key, String eventString) {
528         NetworkCallback mNetworkCallback = mNetworkCallbackMap.get(key);
529         if (mNetworkCallback != null) {
530             int event = getNetworkCallbackEvent(eventString);
531             if (event == NetworkCallback.EVENT_INVALID) {
532                 return false;
533             }
534             mNetworkCallback.stopListeningForEvents(event);
535             return true;
536         } else {
537             return false;
538         }
539     }
540 
541     @Rpc(description = "Set Rssi Threshold Monitor")
connectivitySetRssiThresholdMonitor(Integer rssi)542     public String connectivitySetRssiThresholdMonitor(Integer rssi) {
543         Log.d("SL4A:setRssiThresholdMonitor rssi = " + rssi);
544         NetworkRequest.Builder builder = new NetworkRequest.Builder();
545         builder.setSignalStrength((int) rssi);
546         builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
547         NetworkRequest networkRequest = builder.build();
548         mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL);
549         mManager.registerNetworkCallback(networkRequest, mNetworkCallback);
550         String key = mNetworkCallback.mId;
551         mNetworkCallbackMap.put(key, mNetworkCallback);
552         return key;
553     }
554 
555     @Rpc(description = "Stop Rssi Threshold Monitor")
connectivityStopRssiThresholdMonitor(String key)556     public Boolean connectivityStopRssiThresholdMonitor(String key) {
557         Log.d("SL4A:stopRssiThresholdMonitor key = " + key);
558         return connectivityUnregisterNetworkCallback(key);
559     }
560 
buildNetworkRequestFromJson(JSONObject configJson)561     private NetworkRequest buildNetworkRequestFromJson(JSONObject configJson)
562             throws JSONException {
563         NetworkRequest.Builder builder = new NetworkRequest.Builder();
564 
565         if (configJson.has("TransportType")) {
566             Log.d("build TransportType" + configJson.getInt("TransportType"));
567             builder.addTransportType(configJson.getInt("TransportType"));
568         }
569         if (configJson.has("SignalStrength")) {
570             Log.d("build SignalStrength" + configJson.getInt("SignalStrength"));
571             builder.setSignalStrength(configJson.getInt("SignalStrength"));
572         }
573         if (configJson.has("Capability")) {
574             JSONArray capabilities = configJson.getJSONArray("Capability");
575             for (int i = 0; i < capabilities.length(); i++) {
576                 Log.d("build Capability" + capabilities.getInt(i));
577                 builder.addCapability(capabilities.getInt(i));
578             }
579         }
580         if (configJson.has("LinkUpstreamBandwidthKbps")) {
581             Log.d("build LinkUpstreamBandwidthKbps" + configJson.getInt(
582                     "LinkUpstreamBandwidthKbps"));
583             builder.setLinkUpstreamBandwidthKbps(configJson.getInt(
584                     "LinkUpstreamBandwidthKbps"));
585         }
586         if (configJson.has("LinkDownstreamBandwidthKbps")) {
587             Log.d("build LinkDownstreamBandwidthKbps" + configJson.getInt(
588                     "LinkDownstreamBandwidthKbps"));
589             builder.setLinkDownstreamBandwidthKbps(configJson.getInt(
590                     "LinkDownstreamBandwidthKbps"));
591         }
592         if (configJson.has("NetworkSpecifier")) {
593             Log.d("build NetworkSpecifier" + configJson.getString("NetworkSpecifier"));
594             builder.setNetworkSpecifier(configJson.getString(
595                     "NetworkSpecifier"));
596         }
597         NetworkRequest networkRequest = builder.build();
598         return networkRequest;
599     }
600 
601     @Rpc(description = "register a network callback")
connectivityRegisterNetworkCallback(@pcParametername = "configJson") JSONObject configJson)602     public String connectivityRegisterNetworkCallback(@RpcParameter(name = "configJson")
603     JSONObject configJson) throws JSONException {
604         NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson);
605         mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL);
606         mManager.registerNetworkCallback(networkRequest, mNetworkCallback);
607         String key = mNetworkCallback.mId;
608         mNetworkCallbackMap.put(key, mNetworkCallback);
609         return key;
610     }
611 
612     @Rpc(description = "unregister a network callback")
connectivityUnregisterNetworkCallback(@pcParametername = "key") String key)613     public Boolean connectivityUnregisterNetworkCallback(@RpcParameter(name = "key")
614     String key) {
615         mNetworkCallback = mNetworkCallbackMap.get(key);
616         if (mNetworkCallback != null) {
617             mNetworkCallbackMap.remove(key);
618             mManager.unregisterNetworkCallback(mNetworkCallback);
619             return true;
620         } else {
621             return false;
622         }
623     }
624 
625     @Rpc(description = "request a network")
connectivityRequestNetwork(@pcParametername = "configJson") JSONObject configJson)626     public String connectivityRequestNetwork(@RpcParameter(name = "configJson")
627     JSONObject configJson) throws JSONException {
628         NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson);
629         mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL);
630         mManager.requestNetwork(networkRequest, mNetworkCallback);
631         String key = mNetworkCallback.mId;
632         mNetworkCallbackMap.put(key, mNetworkCallback);
633         return key;
634     }
635 
636     @Rpc(description = "Stop listening for connectivity changes")
connectivityStopTrackingConnectivityStateChange()637     public void connectivityStopTrackingConnectivityStateChange() {
638         if (mTrackingConnectivityStateChange) {
639             mTrackingConnectivityStateChange = false;
640             mContext.unregisterReceiver(mConnectivityReceiver);
641         }
642     }
643 
644     @Rpc(description = "Get the extra information about the network state provided by lower network layers.")
connectivityNetworkGetActiveConnectionExtraInfo()645     public String connectivityNetworkGetActiveConnectionExtraInfo() {
646         NetworkInfo current = mManager.getActiveNetworkInfo();
647         if (current == null) {
648             Log.d("No network is active at the moment.");
649             return null;
650         }
651         return current.getExtraInfo();
652     }
653 
654     @Rpc(description = "Return the subtype name of the current network, null if not connected")
connectivityNetworkGetActiveConnectionSubtypeName()655     public String connectivityNetworkGetActiveConnectionSubtypeName() {
656         NetworkInfo current = mManager.getActiveNetworkInfo();
657         if (current == null) {
658             Log.d("No network is active at the moment.");
659             return null;
660         }
661         return current.getSubtypeName();
662     }
663 
664     @Rpc(description = "Return a human-readable name describe the type of the network, e.g. WIFI")
connectivityNetworkGetActiveConnectionTypeName()665     public String connectivityNetworkGetActiveConnectionTypeName() {
666         NetworkInfo current = mManager.getActiveNetworkInfo();
667         if (current == null) {
668             Log.d("No network is active at the moment.");
669             return null;
670         }
671         return current.getTypeName();
672     }
673 
674     @Rpc(description = "Get connection status information about all network types supported by the device.")
connectivityNetworkGetAllInfo()675     public NetworkInfo[] connectivityNetworkGetAllInfo() {
676         return mManager.getAllNetworkInfo();
677     }
678 
679     @Rpc(description = "Check whether the active network is connected to the Internet.")
connectivityNetworkIsConnected()680     public Boolean connectivityNetworkIsConnected() {
681         NetworkInfo current = mManager.getActiveNetworkInfo();
682         if (current == null) {
683             Log.d("No network is active at the moment.");
684             return false;
685         }
686         return current.isConnected();
687     }
688 
689     @Rpc(description = "Checks the airplane mode setting.",
690             returns = "True if airplane mode is enabled.")
connectivityCheckAirplaneMode()691     public Boolean connectivityCheckAirplaneMode() {
692         try {
693             return android.provider.Settings.System.getInt(mService.getContentResolver(),
694                     android.provider.Settings.Global.AIRPLANE_MODE_ON) == AIRPLANE_MODE_ON;
695         } catch (SettingNotFoundException e) {
696             return false;
697         }
698     }
699 
700     @Rpc(description = "Toggles airplane mode on and off.",
701             returns = "True if airplane mode is enabled.")
connectivityToggleAirplaneMode(@pcParametername = "enabled") @pcOptional Boolean enabled)702     public void connectivityToggleAirplaneMode(@RpcParameter(name = "enabled")
703     @RpcOptional
704     Boolean enabled) {
705         if (enabled == null) {
706             enabled = !connectivityCheckAirplaneMode();
707         }
708         mManager.setAirplaneMode(enabled);
709     }
710 
711     @Rpc(description = "Check if tethering supported or not.",
712             returns = "True if tethering is supported.")
connectivityIsTetheringSupported()713     public boolean connectivityIsTetheringSupported() {
714         return mManager.isTetheringSupported();
715     }
716 
717     @Override
shutdown()718     public void shutdown() {
719         connectivityStopTrackingConnectivityStateChange();
720     }
721 }
722