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