Home | History | Annotate | Download | only in wifi
      1 
      2 package com.googlecode.android_scripting.facade.wifi;
      3 
      4 import android.app.Service;
      5 import android.content.BroadcastReceiver;
      6 import android.content.ContentResolver;
      7 import android.content.Context;
      8 import android.content.Intent;
      9 import android.content.IntentFilter;
     10 import android.net.ConnectivityManager;
     11 import android.net.DhcpInfo;
     12 import android.net.Network;
     13 import android.net.NetworkInfo;
     14 import android.net.NetworkInfo.DetailedState;
     15 import android.net.wifi.ScanResult;
     16 import android.net.wifi.WifiActivityEnergyInfo;
     17 import android.net.wifi.WifiConfiguration;
     18 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
     19 import android.net.wifi.WifiConfiguration.KeyMgmt;
     20 import android.net.wifi.WifiEnterpriseConfig;
     21 import android.net.wifi.WifiInfo;
     22 import android.net.wifi.WifiManager;
     23 import android.net.wifi.WifiManager.WifiLock;
     24 import android.net.wifi.WpsInfo;
     25 import android.os.Bundle;
     26 import android.provider.Settings.Global;
     27 import android.provider.Settings.SettingNotFoundException;
     28 import android.util.Base64;
     29 
     30 import com.googlecode.android_scripting.Log;
     31 import com.googlecode.android_scripting.facade.EventFacade;
     32 import com.googlecode.android_scripting.facade.FacadeManager;
     33 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
     34 import com.googlecode.android_scripting.rpc.Rpc;
     35 import com.googlecode.android_scripting.rpc.RpcOptional;
     36 import com.googlecode.android_scripting.rpc.RpcParameter;
     37 
     38 import org.json.JSONArray;
     39 import org.json.JSONException;
     40 import org.json.JSONObject;
     41 
     42 import java.io.ByteArrayInputStream;
     43 import java.io.ByteArrayOutputStream;
     44 import java.io.IOException;
     45 import java.io.InputStream;
     46 import java.io.ObjectOutput;
     47 import java.io.ObjectOutputStream;
     48 import java.net.ConnectException;
     49 import java.security.GeneralSecurityException;
     50 import java.security.KeyFactory;
     51 import java.security.NoSuchAlgorithmException;
     52 import java.security.PrivateKey;
     53 import java.security.PublicKey;
     54 import java.security.cert.CertificateException;
     55 import java.security.cert.CertificateFactory;
     56 import java.security.cert.X509Certificate;
     57 import java.security.spec.InvalidKeySpecException;
     58 import java.security.spec.PKCS8EncodedKeySpec;
     59 import java.security.spec.X509EncodedKeySpec;
     60 import java.util.ArrayList;
     61 import java.util.List;
     62 
     63 
     64 /**
     65  * WifiManager functions.
     66  */
     67 // TODO: make methods handle various wifi states properly
     68 // e.g. wifi connection result will be null when flight mode is on
     69 public class WifiManagerFacade extends RpcReceiver {
     70     private final static String mEventType = "WifiManager";
     71     private final Service mService;
     72     private final WifiManager mWifi;
     73     private final EventFacade mEventFacade;
     74 
     75     private final IntentFilter mScanFilter;
     76     private final IntentFilter mStateChangeFilter;
     77     private final IntentFilter mTetherFilter;
     78     private final WifiScanReceiver mScanResultsAvailableReceiver;
     79     private final WifiStateChangeReceiver mStateChangeReceiver;
     80     private boolean mTrackingWifiStateChange;
     81     private boolean mTrackingTetherStateChange;
     82 
     83     private final BroadcastReceiver mTetherStateReceiver = new BroadcastReceiver() {
     84         @Override
     85         public void onReceive(Context context, Intent intent) {
     86             String action = intent.getAction();
     87             if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
     88                 Log.d("Wifi AP state changed.");
     89                 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
     90                         WifiManager.WIFI_AP_STATE_FAILED);
     91                 if (state == WifiManager.WIFI_AP_STATE_ENABLED) {
     92                     mEventFacade.postEvent("WifiManagerApEnabled", null);
     93                 } else if (state == WifiManager.WIFI_AP_STATE_DISABLED) {
     94                     mEventFacade.postEvent("WifiManagerApDisabled", null);
     95                 }
     96             } else if (ConnectivityManager.ACTION_TETHER_STATE_CHANGED.equals(action)) {
     97                 Log.d("Tether state changed.");
     98                 ArrayList<String> available = intent.getStringArrayListExtra(
     99                         ConnectivityManager.EXTRA_AVAILABLE_TETHER);
    100                 ArrayList<String> active = intent.getStringArrayListExtra(
    101                         ConnectivityManager.EXTRA_ACTIVE_TETHER);
    102                 ArrayList<String> errored = intent.getStringArrayListExtra(
    103                         ConnectivityManager.EXTRA_ERRORED_TETHER);
    104                 Bundle msg = new Bundle();
    105                 msg.putStringArrayList("AVAILABLE_TETHER", available);
    106                 msg.putStringArrayList("ACTIVE_TETHER", active);
    107                 msg.putStringArrayList("ERRORED_TETHER", errored);
    108                 mEventFacade.postEvent("TetherStateChanged", msg);
    109             }
    110         }
    111     };
    112 
    113     private WifiLock mLock = null;
    114     private boolean mIsConnected = false;
    115 
    116     public WifiManagerFacade(FacadeManager manager) {
    117         super(manager);
    118         mService = manager.getService();
    119         mWifi = (WifiManager) mService.getSystemService(Context.WIFI_SERVICE);
    120         mEventFacade = manager.getReceiver(EventFacade.class);
    121 
    122         mScanFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
    123         mStateChangeFilter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    124         mStateChangeFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
    125         mStateChangeFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
    126         mStateChangeFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1);
    127 
    128         mTetherFilter = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
    129         mTetherFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
    130 
    131         mScanResultsAvailableReceiver = new WifiScanReceiver(mEventFacade);
    132         mStateChangeReceiver = new WifiStateChangeReceiver();
    133         mTrackingWifiStateChange = false;
    134         mTrackingTetherStateChange = false;
    135     }
    136 
    137     private void makeLock(int wifiMode) {
    138         if (mLock == null) {
    139             mLock = mWifi.createWifiLock(wifiMode, "sl4a");
    140             mLock.acquire();
    141         }
    142     }
    143 
    144     /**
    145      * Handle Broadcast receiver for Scan Result
    146      *
    147      * @parm eventFacade Object of EventFacade
    148      */
    149     class WifiScanReceiver extends BroadcastReceiver {
    150         private final EventFacade mEventFacade;
    151 
    152         WifiScanReceiver(EventFacade eventFacade) {
    153             mEventFacade = eventFacade;
    154         }
    155 
    156         @Override
    157         public void onReceive(Context c, Intent intent) {
    158             String action = intent.getAction();
    159             if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
    160                 Bundle mResults = new Bundle();
    161                 Log.d("Wifi connection scan finished, results available.");
    162                 mResults.putLong("Timestamp", System.currentTimeMillis() / 1000);
    163                 mEventFacade.postEvent(mEventType + "ScanResultsAvailable", mResults);
    164                 mService.unregisterReceiver(mScanResultsAvailableReceiver);
    165             }
    166         }
    167     }
    168 
    169     class WifiActionListener implements WifiManager.ActionListener {
    170         private final EventFacade mEventFacade;
    171         private final String TAG;
    172 
    173         public WifiActionListener(EventFacade eventFacade, String tag) {
    174             mEventFacade = eventFacade;
    175             this.TAG = tag;
    176         }
    177 
    178         @Override
    179         public void onSuccess() {
    180             Log.d("WifiActionListener  onSuccess called for " + mEventType + TAG + "OnSuccess");
    181             mEventFacade.postEvent(mEventType + TAG + "OnSuccess", null);
    182         }
    183 
    184         @Override
    185         public void onFailure(int reason) {
    186             Log.d("WifiActionListener  onFailure called for" + mEventType);
    187             Bundle msg = new Bundle();
    188             msg.putInt("reason", reason);
    189             mEventFacade.postEvent(mEventType + TAG + "OnFailure", msg);
    190         }
    191     }
    192 
    193     public class WifiStateChangeReceiver extends BroadcastReceiver {
    194         String mCachedWifiInfo = "";
    195 
    196         @Override
    197         public void onReceive(Context context, Intent intent) {
    198             String action = intent.getAction();
    199             if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
    200                 Log.d("Wifi network state changed.");
    201                 NetworkInfo nInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    202                 WifiInfo wInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
    203                 Log.d("NetworkInfo " + nInfo);
    204                 Log.d("WifiInfo " + wInfo);
    205                 // If network info is of type wifi, send wifi events.
    206                 if (nInfo.getType() == ConnectivityManager.TYPE_WIFI) {
    207                     if (wInfo != null && nInfo.getDetailedState().equals(DetailedState.CONNECTED)) {
    208                         String bssid = wInfo.getBSSID();
    209                         if (bssid != null && !mCachedWifiInfo.equals(wInfo.toString())) {
    210                             Log.d("WifiNetworkConnected");
    211                             mEventFacade.postEvent("WifiNetworkConnected", wInfo);
    212                         }
    213                         mCachedWifiInfo = wInfo.toString();
    214                     } else {
    215                         if (nInfo.getDetailedState().equals(DetailedState.DISCONNECTED)) {
    216                             if (!mCachedWifiInfo.equals("")) {
    217                                 mCachedWifiInfo = "";
    218                                 mEventFacade.postEvent("WifiNetworkDisconnected", null);
    219                             }
    220                         }
    221                     }
    222                 }
    223             } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
    224                 Log.d("Supplicant connection state changed.");
    225                 mIsConnected = intent
    226                         .getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false);
    227                 Bundle msg = new Bundle();
    228                 msg.putBoolean("Connected", mIsConnected);
    229                 mEventFacade.postEvent("SupplicantConnectionChanged", msg);
    230             }
    231         }
    232     }
    233 
    234     public class WifiWpsCallback extends WifiManager.WpsCallback {
    235         private static final String tag = "WifiWps";
    236 
    237         @Override
    238         public void onStarted(String pin) {
    239             Bundle msg = new Bundle();
    240             msg.putString("pin", pin);
    241             mEventFacade.postEvent(tag + "OnStarted", msg);
    242         }
    243 
    244         @Override
    245         public void onSucceeded() {
    246             Log.d("Wps op succeeded");
    247             mEventFacade.postEvent(tag + "OnSucceeded", null);
    248         }
    249 
    250         @Override
    251         public void onFailed(int reason) {
    252             Bundle msg = new Bundle();
    253             msg.putInt("reason", reason);
    254             mEventFacade.postEvent(tag + "OnFailed", msg);
    255         }
    256     }
    257 
    258     private void applyingkeyMgmt(WifiConfiguration config, ScanResult result) {
    259         if (result.capabilities.contains("WEP")) {
    260             config.allowedKeyManagement.set(KeyMgmt.NONE);
    261             config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
    262             config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
    263         } else if (result.capabilities.contains("PSK")) {
    264             config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
    265         } else if (result.capabilities.contains("EAP")) {
    266             // this is probably wrong, as we don't have a way to enter the enterprise config
    267             config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
    268             config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
    269         } else {
    270             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    271         }
    272     }
    273 
    274     private WifiConfiguration genWifiConfig(JSONObject j) throws JSONException {
    275         if (j == null) {
    276             return null;
    277         }
    278         WifiConfiguration config = new WifiConfiguration();
    279         if (j.has("SSID")) {
    280             config.SSID = "\"" + j.getString("SSID") + "\"";
    281         } else if (j.has("ssid")) {
    282             config.SSID = "\"" + j.getString("ssid") + "\"";
    283         }
    284         if (j.has("password")) {
    285             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
    286             config.preSharedKey = "\"" + j.getString("password") + "\"";
    287         } else {
    288             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    289         }
    290         if (j.has("BSSID")) {
    291             config.BSSID = j.getString("BSSID");
    292         }
    293         if (j.has("hiddenSSID")) {
    294             config.hiddenSSID = j.getBoolean("hiddenSSID");
    295         }
    296         if (j.has("priority")) {
    297             config.priority = j.getInt("priority");
    298         }
    299         if (j.has("apBand")) {
    300             config.apBand = j.getInt("apBand");
    301         }
    302         if (j.has("preSharedKey")) {
    303             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
    304             config.preSharedKey = j.getString("preSharedKey");
    305         }
    306         if (j.has("wepKeys")) {
    307             // Looks like we only support static WEP.
    308             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    309             config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
    310             config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
    311             JSONArray keys = j.getJSONArray("wepKeys");
    312             String[] wepKeys = new String[keys.length()];
    313             for (int i = 0; i < keys.length(); i++) {
    314                 wepKeys[i] = keys.getString(i);
    315             }
    316             config.wepKeys = wepKeys;
    317         }
    318         if (j.has("wepTxKeyIndex")) {
    319             config.wepTxKeyIndex = j.getInt("wepTxKeyIndex");
    320         }
    321         return config;
    322     }
    323 
    324     private WifiConfiguration genWifiEnterpriseConfig(JSONObject j) throws JSONException,
    325             GeneralSecurityException {
    326         if (j == null) {
    327             return null;
    328         }
    329         WifiConfiguration config = new WifiConfiguration();
    330         config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
    331         config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
    332         if (j.has("SSID")) {
    333             config.SSID = j.getString("SSID");
    334         }
    335         if (j.has("FQDN")) {
    336             config.FQDN = j.getString("FQDN");
    337         }
    338         if (j.has("providerFriendlyName")) {
    339             config.providerFriendlyName = j.getString("providerFriendlyName");
    340         }
    341         if (j.has("roamingConsortiumIds")) {
    342             JSONArray ids = j.getJSONArray("roamingConsortiumIds");
    343             long[] rIds = new long[ids.length()];
    344             for (int i = 0; i < ids.length(); i++) {
    345                 rIds[i] = ids.getLong(i);
    346             }
    347             config.roamingConsortiumIds = rIds;
    348         }
    349         WifiEnterpriseConfig eConfig = new WifiEnterpriseConfig();
    350         if (j.has(WifiEnterpriseConfig.EAP_KEY)) {
    351             int eap = j.getInt(WifiEnterpriseConfig.EAP_KEY);
    352             eConfig.setEapMethod(eap);
    353         }
    354         if (j.has(WifiEnterpriseConfig.PHASE2_KEY)) {
    355             int p2Method = j.getInt(WifiEnterpriseConfig.PHASE2_KEY);
    356             eConfig.setPhase2Method(p2Method);
    357         }
    358         if (j.has(WifiEnterpriseConfig.CA_CERT_KEY)) {
    359             String certStr = j.getString(WifiEnterpriseConfig.CA_CERT_KEY);
    360             Log.v("CA Cert String is " + certStr);
    361             eConfig.setCaCertificate(strToX509Cert(certStr));
    362         }
    363         if (j.has(WifiEnterpriseConfig.CLIENT_CERT_KEY)
    364                 && j.has(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY)) {
    365             String certStr = j.getString(WifiEnterpriseConfig.CLIENT_CERT_KEY);
    366             String keyStr = j.getString(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY);
    367             Log.v("Client Cert String is " + certStr);
    368             Log.v("Client Key String is " + keyStr);
    369             X509Certificate cert = strToX509Cert(certStr);
    370             PrivateKey privKey = strToPrivateKey(keyStr);
    371             Log.v("Cert is " + cert);
    372             Log.v("Private Key is " + privKey);
    373             eConfig.setClientKeyEntry(privKey, cert);
    374         }
    375         if (j.has(WifiEnterpriseConfig.IDENTITY_KEY)) {
    376             String identity = j.getString(WifiEnterpriseConfig.IDENTITY_KEY);
    377             Log.v("Setting identity to " + identity);
    378             eConfig.setIdentity(identity);
    379         }
    380         if (j.has(WifiEnterpriseConfig.PASSWORD_KEY)) {
    381             String pwd = j.getString(WifiEnterpriseConfig.PASSWORD_KEY);
    382             Log.v("Setting password to " + pwd);
    383             eConfig.setPassword(pwd);
    384         }
    385         if (j.has(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY)) {
    386             String altSub = j.getString(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY);
    387             Log.v("Setting Alt Subject to " + altSub);
    388             eConfig.setAltSubjectMatch(altSub);
    389         }
    390         if (j.has(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY)) {
    391             String domSuffix = j.getString(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY);
    392             Log.v("Setting Domain Suffix Match to " + domSuffix);
    393             eConfig.setDomainSuffixMatch(domSuffix);
    394         }
    395         if (j.has(WifiEnterpriseConfig.REALM_KEY)) {
    396             String realm = j.getString(WifiEnterpriseConfig.REALM_KEY);
    397             Log.v("Setting Domain Suffix Match to " + realm);
    398             eConfig.setRealm(realm);
    399         }
    400         config.enterpriseConfig = eConfig;
    401         return config;
    402     }
    403 
    404     private boolean matchScanResult(ScanResult result, String id) {
    405         if (result.BSSID.equals(id) || result.SSID.equals(id)) {
    406             return true;
    407         }
    408         return false;
    409     }
    410 
    411     private WpsInfo parseWpsInfo(String infoStr) throws JSONException {
    412         if (infoStr == null) {
    413             return null;
    414         }
    415         JSONObject j = new JSONObject(infoStr);
    416         WpsInfo info = new WpsInfo();
    417         if (j.has("setup")) {
    418             info.setup = j.getInt("setup");
    419         }
    420         if (j.has("BSSID")) {
    421             info.BSSID = j.getString("BSSID");
    422         }
    423         if (j.has("pin")) {
    424             info.pin = j.getString("pin");
    425         }
    426         return info;
    427     }
    428 
    429     private byte[] base64StrToBytes(String input) {
    430         return Base64.decode(input, Base64.DEFAULT);
    431     }
    432 
    433     private X509Certificate strToX509Cert(String certStr) throws CertificateException {
    434         byte[] certBytes = base64StrToBytes(certStr);
    435         InputStream certStream = new ByteArrayInputStream(certBytes);
    436         CertificateFactory cf = CertificateFactory.getInstance("X509");
    437         return (X509Certificate) cf.generateCertificate(certStream);
    438     }
    439 
    440     private PrivateKey strToPrivateKey(String key) throws NoSuchAlgorithmException,
    441             InvalidKeySpecException {
    442         byte[] keyBytes = base64StrToBytes(key);
    443         PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
    444         KeyFactory fact = KeyFactory.getInstance("RSA");
    445         PrivateKey priv = fact.generatePrivate(keySpec);
    446         return priv;
    447     }
    448 
    449     private PublicKey strToPublicKey(String key) throws NoSuchAlgorithmException,
    450             InvalidKeySpecException {
    451         byte[] keyBytes = base64StrToBytes(key);
    452         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
    453         KeyFactory fact = KeyFactory.getInstance("RSA");
    454         PublicKey pub = fact.generatePublic(keySpec);
    455         return pub;
    456     }
    457 
    458     private WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) {
    459         if (result == null)
    460             return null;
    461         WifiConfiguration config = new WifiConfiguration();
    462         config.SSID = "\"" + result.SSID + "\"";
    463         applyingkeyMgmt(config, result);
    464         config.BSSID = result.BSSID;
    465         return config;
    466     }
    467 
    468     @Rpc(description = "test.")
    469     public String wifiTest(
    470             @RpcParameter(name = "certString") String certString) throws CertificateException, IOException {
    471         // TODO(angli): Make this work. Convert a X509Certificate back to a string.
    472         X509Certificate caCert = strToX509Cert(certString);
    473         caCert.getEncoded();
    474         ByteArrayOutputStream bos = new ByteArrayOutputStream();
    475         ObjectOutput out = new ObjectOutputStream(bos);
    476         out.writeObject(caCert);
    477         byte[] data = bos.toByteArray();
    478         bos.close();
    479         return Base64.encodeToString(data, Base64.DEFAULT);
    480     }
    481 
    482     @Rpc(description = "Add a network.")
    483     public Integer wifiAddNetwork(@RpcParameter(name = "wifiConfig") JSONObject wifiConfig)
    484             throws JSONException {
    485         return mWifi.addNetwork(genWifiConfig(wifiConfig));
    486     }
    487 
    488     @Rpc(description = "Builds a WifiConfiguration from Hotspot 2.0 MIME file.")
    489     public WifiConfiguration wifiBuildConfig(
    490             @RpcParameter(name = "uriString") String uriString,
    491             @RpcParameter(name = "mimeType") String mimeType,
    492             String dataString)
    493                     throws JSONException {
    494         byte[] data = base64StrToBytes(dataString);
    495         return mWifi.buildWifiConfig(uriString, mimeType, data);
    496     }
    497 
    498     @Rpc(description = "Cancel Wi-fi Protected Setup.")
    499     public void wifiCancelWps() throws JSONException {
    500         WifiWpsCallback listener = new WifiWpsCallback();
    501         mWifi.cancelWps(listener);
    502     }
    503 
    504     @Rpc(description = "Checks Wifi state.", returns = "True if Wifi is enabled.")
    505     public Boolean wifiCheckState() {
    506         return mWifi.getWifiState() == WifiManager.WIFI_STATE_ENABLED;
    507     }
    508 
    509     /**
    510      * Connects to a WPA protected wifi network
    511      *
    512      * @param wifiSSID SSID of the wifi network
    513      * @param wifiPassword password for the wifi network
    514      * @return true on success
    515      * @throws ConnectException
    516      * @throws JSONException
    517      */
    518     @Rpc(description = "Connects a wifi network by ssid", returns = "True if the operation succeeded.")
    519     public Boolean wifiConnect(@RpcParameter(name = "config") JSONObject config)
    520             throws ConnectException, JSONException {
    521         WifiConfiguration wifiConfig = genWifiConfig(config);
    522         int nId = mWifi.addNetwork(wifiConfig);
    523         if (nId < 0) {
    524             Log.e("Got negative network Id.");
    525             return false;
    526         }
    527         if (!mWifi.enableNetwork(nId, true)) {
    528             Log.e("Failed to enable wifi network.");
    529             return false;
    530         }
    531         return mWifi.reconnect();
    532     }
    533 
    534     @Rpc(description = "Disconnects from the currently active access point.", returns = "True if the operation succeeded.")
    535     public Boolean wifiDisconnect() {
    536         return mWifi.disconnect();
    537     }
    538 
    539     @Rpc(description = "Enable/disable autojoin scan and switch network when connected.")
    540     public Boolean wifiSetEnableAutoJoinWhenAssociated(@RpcParameter(name = "enable") Boolean enable) {
    541         return mWifi.setEnableAutoJoinWhenAssociated(enable);
    542     }
    543 
    544     @Rpc(description = "Enable a configured network. Initiate a connection if disableOthers is true", returns = "True if the operation succeeded.")
    545     public Boolean wifiEnableNetwork(@RpcParameter(name = "netId") Integer netId,
    546             @RpcParameter(name = "disableOthers") Boolean disableOthers) {
    547         return mWifi.enableNetwork(netId, disableOthers);
    548     }
    549 
    550     @Rpc(description = "Enable WiFi verbose logging.")
    551     public void wifiEnableVerboseLogging(@RpcParameter(name = "level") Integer level) {
    552         mWifi.enableVerboseLogging(level);
    553     }
    554 
    555     @Rpc(description = "Connect to a wifi network that uses Enterprise authentication methods.")
    556     public Boolean wifiEnterpriseConnect(@RpcParameter(name = "config") JSONObject config)
    557             throws JSONException, GeneralSecurityException {
    558         // Create Certificate
    559         WifiActionListener listener = new WifiActionListener(mEventFacade, "EnterpriseConnect");
    560         WifiConfiguration wifiConfig = genWifiEnterpriseConfig(config);
    561         if (wifiConfig.isPasspoint()) {
    562             Log.d("Got a passpoint config, add it and save config.");
    563             if (mWifi.addNetwork(wifiConfig) == -1) {
    564                 Log.e("Failed to add a wifi network");
    565                 return false;
    566             }
    567             return mWifi.saveConfiguration();
    568         } else {
    569             Log.d("Got a non-passpoint enterprise config, connect directly.");
    570             mWifi.connect(wifiConfig, listener);
    571             return true;
    572         }
    573     }
    574 
    575     @Rpc(description = "Resets all WifiManager settings.")
    576     public void wifiFactoryReset() {
    577         mWifi.factoryReset();
    578     }
    579 
    580     /**
    581      * Forget a wifi network with priority
    582      *
    583      * @param networkID Id of wifi network
    584      */
    585     @Rpc(description = "Forget a wifi network with priority")
    586     public void wifiForgetNetwork(@RpcParameter(name = "wifiSSID") Integer newtorkId) {
    587         WifiActionListener listener = new WifiActionListener(mEventFacade, "ForgetNetwork");
    588         mWifi.forget(newtorkId, listener);
    589     }
    590 
    591     @Rpc(description = "Gets the Wi-Fi AP Configuration.")
    592     public WifiConfiguration wifiGetApConfiguration() {
    593         return mWifi.getWifiApConfiguration();
    594     }
    595 
    596     @Rpc(description = "Returns the file in which IP and proxy configuration data is stored.")
    597     public String wifiGetConfigFile() {
    598         return mWifi.getConfigFile();
    599     }
    600 
    601     @Rpc(description = "Return a list of all the configured wifi networks.")
    602     public List<WifiConfiguration> wifiGetConfiguredNetworks() {
    603         return mWifi.getConfiguredNetworks();
    604     }
    605 
    606     @Rpc(description = "Returns information about the currently active access point.")
    607     public WifiInfo wifiGetConnectionInfo() {
    608         return mWifi.getConnectionInfo();
    609     }
    610 
    611     @Rpc(description = "Returns wifi activity and energy usage info.")
    612     public WifiActivityEnergyInfo wifiGetControllerActivityEnergyInfo() {
    613         return mWifi.getControllerActivityEnergyInfo(0);
    614     }
    615 
    616     @Rpc(description = "Get the country code used by WiFi.")
    617     public String wifiGetCountryCode() {
    618         return mWifi.getCountryCode();
    619     }
    620 
    621     @Rpc(description = "Get the current network.")
    622     public Network wifiGetCurrentNetwork() {
    623         return mWifi.getCurrentNetwork();
    624     }
    625 
    626     @Rpc(description = "Get the info from last successful DHCP request.")
    627     public DhcpInfo wifiGetDhcpInfo() {
    628         return mWifi.getDhcpInfo();
    629     }
    630 
    631     @Rpc(description = "Get setting for Framework layer autojoin enable status.")
    632     public Boolean wifiGetEnableAutoJoinWhenAssociated() {
    633         return mWifi.getEnableAutoJoinWhenAssociated();
    634     }
    635 
    636     @Rpc(description = "Get privileged configured networks.")
    637     public List<WifiConfiguration> wifiGetPrivilegedConfiguredNetworks() {
    638         return mWifi.getPrivilegedConfiguredNetworks();
    639     }
    640 
    641     @Rpc(description = "Returns the list of access points found during the most recent Wifi scan.")
    642     public List<ScanResult> wifiGetScanResults() {
    643         return mWifi.getScanResults();
    644     }
    645 
    646     @Rpc(description = "Get the current level of WiFi verbose logging.")
    647     public Integer wifiGetVerboseLoggingLevel() {
    648         return mWifi.getVerboseLoggingLevel();
    649     }
    650 
    651     @Rpc(description = "true if this adapter supports 5 GHz band.")
    652     public Boolean wifiIs5GHzBandSupported() {
    653         return mWifi.is5GHzBandSupported();
    654     }
    655 
    656     @Rpc(description = "true if this adapter supports multiple simultaneous connections.")
    657     public Boolean wifiIsAdditionalStaSupported() {
    658         return mWifi.isAdditionalStaSupported();
    659     }
    660 
    661     @Rpc(description = "Return whether Wi-Fi AP is enabled or disabled.")
    662     public Boolean wifiIsApEnabled() {
    663         return mWifi.isWifiApEnabled();
    664     }
    665 
    666     @Rpc(description = "Check if Device-to-AP RTT is supported.")
    667     public Boolean wifiIsDeviceToApRttSupported() {
    668         return mWifi.isDeviceToApRttSupported();
    669     }
    670 
    671     @Rpc(description = "Check if Device-to-device RTT is supported.")
    672     public Boolean wifiIsDeviceToDeviceRttSupported() {
    673         return mWifi.isDeviceToDeviceRttSupported();
    674     }
    675 
    676     @Rpc(description = "Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz).")
    677     public Boolean wifiIsDualBandSupported() {
    678         return mWifi.isDualBandSupported();
    679     }
    680 
    681     @Rpc(description = "Check if this adapter supports advanced power/performance counters.")
    682     public Boolean wifiIsEnhancedPowerReportingSupported() {
    683         return mWifi.isEnhancedPowerReportingSupported();
    684     }
    685 
    686     @Rpc(description = "Check if multicast is enabled.")
    687     public Boolean wifiIsMulticastEnabled() {
    688         return mWifi.isMulticastEnabled();
    689     }
    690 
    691     @Rpc(description = "true if this adapter supports Neighbour Awareness Network APIs.")
    692     public Boolean wifiIsNanSupported() {
    693         return mWifi.isNanSupported();
    694     }
    695 
    696     @Rpc(description = "true if this adapter supports Off Channel Tunnel Directed Link Setup.")
    697     public Boolean wifiIsOffChannelTdlsSupported() {
    698         return mWifi.isOffChannelTdlsSupported();
    699     }
    700 
    701     @Rpc(description = "true if this adapter supports WifiP2pManager (Wi-Fi Direct).")
    702     public Boolean wifiIsP2pSupported() {
    703         return mWifi.isP2pSupported();
    704     }
    705 
    706     @Rpc(description = "true if this adapter supports passpoint.")
    707     public Boolean wifiIsPasspointSupported() {
    708         return mWifi.isPasspointSupported();
    709     }
    710 
    711     @Rpc(description = "true if this adapter supports portable Wi-Fi hotspot.")
    712     public Boolean wifiIsPortableHotspotSupported() {
    713         return mWifi.isPortableHotspotSupported();
    714     }
    715 
    716     @Rpc(description = "true if this adapter supports offloaded connectivity scan.")
    717     public Boolean wifiIsPreferredNetworkOffloadSupported() {
    718         return mWifi.isPreferredNetworkOffloadSupported();
    719     }
    720 
    721     @Rpc(description = "Check if wifi scanner is supported on this device.")
    722     public Boolean wifiIsScannerSupported() {
    723         return mWifi.isWifiScannerSupported();
    724     }
    725 
    726     @Rpc(description = "Check if tdls is supported on this device.")
    727     public Boolean wifiIsTdlsSupported() {
    728         return mWifi.isTdlsSupported();
    729     }
    730 
    731     @Rpc(description = "Acquires a full Wifi lock.")
    732     public void wifiLockAcquireFull() {
    733         makeLock(WifiManager.WIFI_MODE_FULL);
    734     }
    735 
    736     @Rpc(description = "Acquires a scan only Wifi lock.")
    737     public void wifiLockAcquireScanOnly() {
    738         makeLock(WifiManager.WIFI_MODE_SCAN_ONLY);
    739     }
    740 
    741     @Rpc(description = "Releases a previously acquired Wifi lock.")
    742     public void wifiLockRelease() {
    743         if (mLock != null) {
    744             mLock.release();
    745             mLock = null;
    746         }
    747     }
    748 
    749     /**
    750      * Connects to a wifi network with priority
    751      *
    752      * @param wifiSSID SSID of the wifi network
    753      * @param wifiPassword password for the wifi network
    754      * @throws JSONException
    755      */
    756     @Rpc(description = "Connects a wifi network as priority by pasing ssid")
    757     public void wifiPriorityConnect(@RpcParameter(name = "config") JSONObject config)
    758             throws JSONException {
    759         WifiConfiguration wifiConfig = genWifiConfig(config);
    760         WifiActionListener listener = new WifiActionListener(mEventFacade, "PriorityConnect");
    761         mWifi.connect(wifiConfig, listener);
    762     }
    763 
    764     @Rpc(description = "Reassociates with the currently active access point.", returns = "True if the operation succeeded.")
    765     public Boolean wifiReassociate() {
    766         return mWifi.reassociate();
    767     }
    768 
    769     @Rpc(description = "Reconnects to the currently active access point.", returns = "True if the operation succeeded.")
    770     public Boolean wifiReconnect() {
    771         return mWifi.reconnect();
    772     }
    773 
    774     @Rpc(description = "Remove a configured network.", returns = "True if the operation succeeded.")
    775     public Boolean wifiRemoveNetwork(@RpcParameter(name = "netId") Integer netId) {
    776         return mWifi.removeNetwork(netId);
    777     }
    778 
    779     private WifiConfiguration createSoftApWifiConfiguration(JSONObject configJson)
    780             throws JSONException {
    781         WifiConfiguration config = genWifiConfig(configJson);
    782         // Need to strip of extra quotation marks for SSID and password.
    783         String ssid = config.SSID;
    784         if (ssid != null) {
    785             config.SSID = ssid.substring(1, ssid.length() - 1);
    786         }
    787         String pwd = config.preSharedKey;
    788         if (pwd != null) {
    789             config.preSharedKey = pwd.substring(1, pwd.length() - 1);
    790         }
    791         return config;
    792     }
    793 
    794     @Rpc(description = "Set configuration for soft AP.")
    795     public Boolean wifiSetWifiApConfiguration(
    796             @RpcParameter(name = "configJson") JSONObject configJson) throws JSONException {
    797         WifiConfiguration config = createSoftApWifiConfiguration(configJson);
    798         return mWifi.setWifiApConfiguration(config);
    799     }
    800 
    801     @Rpc(description = "Start/stop wifi soft AP.")
    802     public Boolean wifiSetApEnabled(
    803             @RpcParameter(name = "enable") Boolean enable,
    804             @RpcParameter(name = "configJson") JSONObject configJson) throws JSONException {
    805         int wifiState = mWifi.getWifiState();
    806         if (enable) {
    807             WifiConfiguration config = createSoftApWifiConfiguration(configJson);
    808             return mWifi.setWifiApEnabled(config, enable);
    809         } else {
    810             return mWifi.setWifiApEnabled(null, false);
    811         }
    812     }
    813 
    814     @Rpc(description = "Set the country code used by WiFi.")
    815     public void wifiSetCountryCode(
    816             @RpcParameter(name = "country") String country,
    817             @RpcParameter(name = "persist") Boolean persist) {
    818         mWifi.setCountryCode(country, persist);
    819     }
    820 
    821     @Rpc(description = "Enable/disable tdls with a mac address.")
    822     public void wifiSetTdlsEnabledWithMacAddress(
    823             @RpcParameter(name = "remoteMacAddress") String remoteMacAddress,
    824             @RpcParameter(name = "enable") Boolean enable) {
    825         mWifi.setTdlsEnabledWithMacAddress(remoteMacAddress, enable);
    826     }
    827 
    828     @Rpc(description = "Starts a scan for Wifi access points.", returns = "True if the scan was initiated successfully.")
    829     public Boolean wifiStartScan() {
    830         mService.registerReceiver(mScanResultsAvailableReceiver, mScanFilter);
    831         return mWifi.startScan();
    832     }
    833 
    834     @Rpc(description = "Start Wi-fi Protected Setup.")
    835     public void wifiStartWps(
    836             @RpcParameter(name = "config", description = "A json string with fields \"setup\", \"BSSID\", and \"pin\"") String config)
    837                     throws JSONException {
    838         WpsInfo info = parseWpsInfo(config);
    839         WifiWpsCallback listener = new WifiWpsCallback();
    840         Log.d("Starting wps with: " + info);
    841         mWifi.startWps(info, listener);
    842     }
    843 
    844     @Rpc(description = "Start listening for wifi state change related broadcasts.")
    845     public void wifiStartTrackingStateChange() {
    846         mService.registerReceiver(mStateChangeReceiver, mStateChangeFilter);
    847         mTrackingWifiStateChange = true;
    848     }
    849 
    850     @Rpc(description = "Stop listening for wifi state change related broadcasts.")
    851     public void wifiStopTrackingStateChange() {
    852         if (mTrackingWifiStateChange == true) {
    853             mService.unregisterReceiver(mStateChangeReceiver);
    854             mTrackingWifiStateChange = false;
    855         }
    856     }
    857 
    858     @Rpc(description = "Start listening for tether state change related broadcasts.")
    859     public void wifiStartTrackingTetherStateChange() {
    860         mService.registerReceiver(mTetherStateReceiver, mTetherFilter);
    861         mTrackingTetherStateChange = true;
    862     }
    863 
    864     @Rpc(description = "Stop listening for wifi state change related broadcasts.")
    865     public void wifiStopTrackingTetherStateChange() {
    866         if (mTrackingTetherStateChange == true) {
    867             mService.unregisterReceiver(mTetherStateReceiver);
    868             mTrackingTetherStateChange = false;
    869         }
    870     }
    871 
    872     @Rpc(description = "Toggle Wifi on and off.", returns = "True if Wifi is enabled.")
    873     public Boolean wifiToggleState(@RpcParameter(name = "enabled") @RpcOptional Boolean enabled) {
    874         if (enabled == null) {
    875             enabled = !wifiCheckState();
    876         }
    877         mWifi.setWifiEnabled(enabled);
    878         return enabled;
    879     }
    880 
    881     @Rpc(description = "Toggle Wifi scan always available on and off.", returns = "True if Wifi scan is always available.")
    882     public Boolean wifiToggleScanAlwaysAvailable(
    883             @RpcParameter(name = "enabled") @RpcOptional Boolean enabled)
    884                     throws SettingNotFoundException {
    885         ContentResolver cr = mService.getContentResolver();
    886         int isSet = 0;
    887         if (enabled == null) {
    888             isSet = Global.getInt(cr, Global.WIFI_SCAN_ALWAYS_AVAILABLE);
    889             isSet ^= 1;
    890         } else if (enabled == true) {
    891             isSet = 1;
    892         }
    893         Global.putInt(cr, Global.WIFI_SCAN_ALWAYS_AVAILABLE, isSet);
    894         if (isSet == 1) {
    895             return true;
    896         }
    897         return false;
    898     }
    899 
    900     @Rpc(description = "Enable/disable WifiConnectivityManager.")
    901     public void wifiEnableWifiConnectivityManager(
    902             @RpcParameter(name = "enable") Boolean enable) {
    903         mWifi.enableWifiConnectivityManager(enable);
    904     }
    905 
    906     @Override
    907     public void shutdown() {
    908         wifiLockRelease();
    909         if (mTrackingWifiStateChange == true) {
    910             wifiStopTrackingStateChange();
    911         }
    912         if (mTrackingTetherStateChange == true) {
    913             wifiStopTrackingTetherStateChange();
    914         }
    915     }
    916 }
    917