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