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