1
2package com.googlecode.android_scripting.facade.wifi;
3
4import android.app.Service;
5import android.content.BroadcastReceiver;
6import android.content.ContentResolver;
7import android.content.Context;
8import android.content.Intent;
9import android.content.IntentFilter;
10import android.net.ConnectivityManager;
11import android.net.DhcpInfo;
12import android.net.Network;
13import android.net.NetworkInfo;
14import android.net.NetworkInfo.DetailedState;
15import android.net.wifi.ScanResult;
16import android.net.wifi.WifiActivityEnergyInfo;
17import android.net.wifi.WifiConfiguration;
18import android.net.wifi.WifiConfiguration.AuthAlgorithm;
19import android.net.wifi.WifiConfiguration.KeyMgmt;
20import android.net.wifi.WifiEnterpriseConfig;
21import android.net.wifi.WifiInfo;
22import android.net.wifi.WifiManager;
23import android.net.wifi.WifiManager.WifiLock;
24import android.net.wifi.WpsInfo;
25import android.os.Bundle;
26import android.provider.Settings.Global;
27import android.provider.Settings.SettingNotFoundException;
28import android.util.Base64;
29
30import com.googlecode.android_scripting.Log;
31import com.googlecode.android_scripting.facade.EventFacade;
32import com.googlecode.android_scripting.facade.FacadeManager;
33import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
34import com.googlecode.android_scripting.rpc.Rpc;
35import com.googlecode.android_scripting.rpc.RpcOptional;
36import com.googlecode.android_scripting.rpc.RpcParameter;
37
38import org.json.JSONArray;
39import org.json.JSONException;
40import org.json.JSONObject;
41
42import java.io.ByteArrayInputStream;
43import java.io.ByteArrayOutputStream;
44import java.io.IOException;
45import java.io.InputStream;
46import java.io.ObjectOutput;
47import java.io.ObjectOutputStream;
48import java.net.ConnectException;
49import java.security.GeneralSecurityException;
50import java.security.KeyFactory;
51import java.security.NoSuchAlgorithmException;
52import java.security.PrivateKey;
53import java.security.PublicKey;
54import java.security.cert.CertificateException;
55import java.security.cert.CertificateFactory;
56import java.security.cert.X509Certificate;
57import java.security.spec.InvalidKeySpecException;
58import java.security.spec.PKCS8EncodedKeySpec;
59import java.security.spec.X509EncodedKeySpec;
60import java.util.ArrayList;
61import 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
69public 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