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