• 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 static android.net.NetworkCapabilities.TRANSPORT_WIFI;
20 
21 import android.app.Service;
22 import android.content.BroadcastReceiver;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.net.ConnectivityManager;
28 import android.net.ConnectivityManager.NetworkCallback;
29 import android.net.DhcpInfo;
30 import android.net.MacAddress;
31 import android.net.Network;
32 import android.net.NetworkInfo;
33 import android.net.NetworkInfo.DetailedState;
34 import android.net.NetworkRequest;
35 import android.net.NetworkSpecifier;
36 import android.net.Uri;
37 import android.net.wifi.EasyConnectStatusCallback;
38 import android.net.wifi.ScanResult;
39 import android.net.wifi.WifiActivityEnergyInfo;
40 import android.net.wifi.WifiConfiguration;
41 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
42 import android.net.wifi.WifiConfiguration.KeyMgmt;
43 import android.net.wifi.WifiEnterpriseConfig;
44 import android.net.wifi.WifiInfo;
45 import android.net.wifi.WifiManager;
46 import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
47 import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
48 import android.net.wifi.WifiManager.WifiLock;
49 import android.net.wifi.WifiNetworkSpecifier;
50 import android.net.wifi.WifiNetworkSuggestion;
51 import android.net.wifi.WifiSsid;
52 import android.net.wifi.WpsInfo;
53 import android.net.wifi.hotspot2.ConfigParser;
54 import android.net.wifi.hotspot2.OsuProvider;
55 import android.net.wifi.hotspot2.PasspointConfiguration;
56 import android.net.wifi.hotspot2.ProvisioningCallback;
57 import android.os.Bundle;
58 import android.os.Handler;
59 import android.os.HandlerThread;
60 import android.os.PatternMatcher;
61 import android.provider.Settings.Global;
62 import android.provider.Settings.SettingNotFoundException;
63 import android.text.TextUtils;
64 import android.util.Base64;
65 import android.util.SparseArray;
66 
67 import com.android.internal.annotations.GuardedBy;
68 
69 import com.googlecode.android_scripting.Log;
70 import com.googlecode.android_scripting.facade.EventFacade;
71 import com.googlecode.android_scripting.facade.FacadeManager;
72 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
73 import com.googlecode.android_scripting.rpc.Rpc;
74 import com.googlecode.android_scripting.rpc.RpcOptional;
75 import com.googlecode.android_scripting.rpc.RpcParameter;
76 
77 import org.json.JSONArray;
78 import org.json.JSONException;
79 import org.json.JSONObject;
80 
81 import java.io.ByteArrayInputStream;
82 import java.io.ByteArrayOutputStream;
83 import java.io.IOException;
84 import java.io.InputStream;
85 import java.io.ObjectOutput;
86 import java.io.ObjectOutputStream;
87 import java.nio.charset.StandardCharsets;
88 import java.security.GeneralSecurityException;
89 import java.security.KeyFactory;
90 import java.security.NoSuchAlgorithmException;
91 import java.security.PrivateKey;
92 import java.security.PublicKey;
93 import java.security.cert.CertificateException;
94 import java.security.cert.CertificateFactory;
95 import java.security.cert.X509Certificate;
96 import java.security.spec.InvalidKeySpecException;
97 import java.security.spec.PKCS8EncodedKeySpec;
98 import java.security.spec.X509EncodedKeySpec;
99 import java.util.ArrayList;
100 import java.util.Arrays;
101 import java.util.HashMap;
102 import java.util.Iterator;
103 import java.util.List;
104 import java.util.Map;
105 
106 /**
107  * WifiManager functions.
108  */
109 // TODO: make methods handle various wifi states properly
110 // e.g. wifi connection result will be null when flight mode is on
111 public class WifiManagerFacade extends RpcReceiver {
112     private final static String mEventType = "WifiManager";
113     // MIME type for passpoint config.
114     private final static String TYPE_WIFICONFIG = "application/x-wifi-config";
115     private final Service mService;
116     private final WifiManager mWifi;
117     private final ConnectivityManager mCm;
118     private final EventFacade mEventFacade;
119 
120     private final IntentFilter mScanFilter;
121     private final IntentFilter mStateChangeFilter;
122     private final IntentFilter mTetherFilter;
123     private final IntentFilter mNetworkSuggestionStateChangeFilter;
124     private final WifiScanReceiver mScanResultsAvailableReceiver;
125     private final WifiStateChangeReceiver mStateChangeReceiver;
126     private final WifiNetworkSuggestionStateChangeReceiver mNetworkSuggestionStateChangeReceiver;
127     private final HandlerThread mCallbackHandlerThread;
128     private final Object mCallbackLock = new Object();
129     private final Map<NetworkSpecifier, NetworkCallback> mNetworkCallbacks = new HashMap<>();
130     private boolean mTrackingWifiStateChange;
131     private boolean mTrackingTetherStateChange;
132     private boolean mTrackingNetworkSuggestionStateChange;
133     @GuardedBy("mCallbackLock")
134     private NetworkRequestUserSelectionCallback mNetworkRequestUserSelectionCallback;
135     private final SparseArray<SoftApCallbackImp> mSoftapCallbacks;
136 
137     private final BroadcastReceiver mTetherStateReceiver = new BroadcastReceiver() {
138         @Override
139         public void onReceive(Context context, Intent intent) {
140             String action = intent.getAction();
141             if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
142                 Log.d("Wifi AP state changed.");
143                 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
144                         WifiManager.WIFI_AP_STATE_FAILED);
145                 if (state == WifiManager.WIFI_AP_STATE_ENABLED) {
146                     mEventFacade.postEvent("WifiManagerApEnabled", null);
147                 } else if (state == WifiManager.WIFI_AP_STATE_DISABLED) {
148                     mEventFacade.postEvent("WifiManagerApDisabled", null);
149                 }
150             } else if (ConnectivityManager.ACTION_TETHER_STATE_CHANGED.equals(action)) {
151                 Log.d("Tether state changed.");
152                 ArrayList<String> available = intent.getStringArrayListExtra(
153                         ConnectivityManager.EXTRA_AVAILABLE_TETHER);
154                 ArrayList<String> active = intent.getStringArrayListExtra(
155                         ConnectivityManager.EXTRA_ACTIVE_TETHER);
156                 ArrayList<String> errored = intent.getStringArrayListExtra(
157                         ConnectivityManager.EXTRA_ERRORED_TETHER);
158                 Bundle msg = new Bundle();
159                 msg.putStringArrayList("AVAILABLE_TETHER", available);
160                 msg.putStringArrayList("ACTIVE_TETHER", active);
161                 msg.putStringArrayList("ERRORED_TETHER", errored);
162                 mEventFacade.postEvent("TetherStateChanged", msg);
163             }
164         }
165     };
166 
167     private final NetworkRequestMatchCallback mNetworkRequestMatchCallback =
168             new NetworkRequestMatchCallback() {
169                 private static final String EVENT_TAG = mEventType + "NetworkRequestMatchCallback";
170 
171                 @Override
172                 public void onUserSelectionCallbackRegistration(
173                         NetworkRequestUserSelectionCallback userSelectionCallback) {
174                     synchronized (mCallbackLock) {
175                         mNetworkRequestUserSelectionCallback = userSelectionCallback;
176                     }
177                 }
178 
179                 @Override
180                 public void onAbort() {
181                     mEventFacade.postEvent(EVENT_TAG + "OnAbort", null);
182                 }
183 
184                 @Override
185                 public void onMatch(List<ScanResult> scanResults) {
186                     mEventFacade.postEvent(EVENT_TAG + "OnMatch", scanResults);
187                 }
188 
189                 @Override
190                 public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
191                     mEventFacade.postEvent(EVENT_TAG + "OnUserSelectionConnectSuccess",
192                             wifiConfiguration);
193                 }
194 
195                 @Override
196                 public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
197                     mEventFacade.postEvent(EVENT_TAG + "OnUserSelectionConnectFailure",
198                             wifiConfiguration);
199                 }
200             };
201 
202     private final class NetworkCallbackImpl extends NetworkCallback {
203         private static final String EVENT_TAG = mEventType + "NetworkCallback";
204 
205         @Override
onAvailable(Network network)206         public void onAvailable(Network network) {
207             mEventFacade.postEvent(EVENT_TAG + "OnAvailable", mWifi.getConnectionInfo());
208         }
209 
210         @Override
onUnavailable()211         public void onUnavailable() {
212             mEventFacade.postEvent(EVENT_TAG + "OnUnavailable", null);
213         }
214 
215         @Override
onLost(Network network)216         public void onLost(Network network) {
217             mEventFacade.postEvent(EVENT_TAG + "OnLost", null);
218         }
219     };
220 
221     private static class SoftApCallbackImp implements WifiManager.SoftApCallback {
222         // A monotonic increasing counter for softap callback ids.
223         private static int sCount = 0;
224 
225         private final int mId;
226         private final EventFacade mEventFacade;
227         private final String mEventStr;
228 
SoftApCallbackImp(EventFacade eventFacade)229         SoftApCallbackImp(EventFacade eventFacade) {
230             sCount++;
231             mId = sCount;
232             mEventFacade = eventFacade;
233             mEventStr = mEventType + "SoftApCallback-" + mId + "-";
234         }
235 
236         @Override
onStateChanged(int state, int failureReason)237         public void onStateChanged(int state, int failureReason) {
238             Bundle msg = new Bundle();
239             msg.putInt("State", state);
240             msg.putInt("FailureReason", failureReason);
241             mEventFacade.postEvent(mEventStr + "OnStateChanged", msg);
242         }
243 
244         @Override
onNumClientsChanged(int numClients)245         public void onNumClientsChanged(int numClients) {
246             Bundle msg = new Bundle();
247             msg.putInt("NumClients", numClients);
248             mEventFacade.postEvent(mEventStr + "OnNumClientsChanged", msg);
249         }
250     };
251 
252     private WifiLock mLock = null;
253     private boolean mIsConnected = false;
254 
WifiManagerFacade(FacadeManager manager)255     public WifiManagerFacade(FacadeManager manager) {
256         super(manager);
257         mService = manager.getService();
258         mWifi = (WifiManager) mService.getSystemService(Context.WIFI_SERVICE);
259         mCm = (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE);
260         mEventFacade = manager.getReceiver(EventFacade.class);
261         mCallbackHandlerThread = new HandlerThread("WifiManagerFacade");
262 
263         mScanFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
264         mStateChangeFilter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
265         mStateChangeFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
266         mStateChangeFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
267         mStateChangeFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
268         mStateChangeFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1);
269 
270         mTetherFilter = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
271         mTetherFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
272 
273         mNetworkSuggestionStateChangeFilter = new IntentFilter(
274                 WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);
275 
276         mScanResultsAvailableReceiver = new WifiScanReceiver(mEventFacade);
277         mStateChangeReceiver = new WifiStateChangeReceiver();
278         mNetworkSuggestionStateChangeReceiver = new WifiNetworkSuggestionStateChangeReceiver();
279         mTrackingWifiStateChange = false;
280         mTrackingTetherStateChange = false;
281         mTrackingNetworkSuggestionStateChange = false;
282         mCallbackHandlerThread.start();
283         mSoftapCallbacks = new SparseArray<>();
284     }
285 
makeLock(int wifiMode)286     private void makeLock(int wifiMode) {
287         if (mLock == null) {
288             mLock = mWifi.createWifiLock(wifiMode, "sl4a");
289             mLock.acquire();
290         }
291     }
292 
293     /**
294      * Handle Broadcast receiver for Scan Result
295      *
296      * @parm eventFacade Object of EventFacade
297      */
298     class WifiScanReceiver extends BroadcastReceiver {
299         private final EventFacade mEventFacade;
300 
WifiScanReceiver(EventFacade eventFacade)301         WifiScanReceiver(EventFacade eventFacade) {
302             mEventFacade = eventFacade;
303         }
304 
305         @Override
onReceive(Context c, Intent intent)306         public void onReceive(Context c, Intent intent) {
307             String action = intent.getAction();
308             if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
309                 if (!intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) {
310                     Log.w("Wifi connection scan failed, ignoring.");
311                     mEventFacade.postEvent(mEventType + "ScanFailure", null);
312                 } else {
313                     Bundle mResults = new Bundle();
314                     Log.d("Wifi connection scan finished, results available.");
315                     mResults.putLong("Timestamp", System.currentTimeMillis() / 1000);
316                     mEventFacade.postEvent(mEventType + "ScanResultsAvailable", mResults);
317                 }
318                 mService.unregisterReceiver(mScanResultsAvailableReceiver);
319             }
320         }
321     }
322 
323     class WifiActionListener implements WifiManager.ActionListener {
324         private final EventFacade mEventFacade;
325         private final String TAG;
326 
WifiActionListener(EventFacade eventFacade, String tag)327         public WifiActionListener(EventFacade eventFacade, String tag) {
328             mEventFacade = eventFacade;
329             this.TAG = tag;
330         }
331 
332         @Override
onSuccess()333         public void onSuccess() {
334             Log.d("WifiActionListener  onSuccess called for " + mEventType + TAG + "OnSuccess");
335             mEventFacade.postEvent(mEventType + TAG + "OnSuccess", null);
336         }
337 
338         @Override
onFailure(int reason)339         public void onFailure(int reason) {
340             Log.d("WifiActionListener  onFailure called for" + mEventType);
341             Bundle msg = new Bundle();
342             msg.putInt("reason", reason);
343             mEventFacade.postEvent(mEventType + TAG + "OnFailure", msg);
344         }
345     }
346 
347     public class WifiStateChangeReceiver extends BroadcastReceiver {
348         String mCachedWifiInfo = "";
349 
350         @Override
onReceive(Context context, Intent intent)351         public void onReceive(Context context, Intent intent) {
352             String action = intent.getAction();
353             if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
354                 Log.d("Wifi network state changed.");
355                 NetworkInfo nInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
356                 Log.d("NetworkInfo " + nInfo);
357                 // If network info is of type wifi, send wifi events.
358                 if (nInfo.getType() == ConnectivityManager.TYPE_WIFI) {
359                     if (nInfo.getDetailedState().equals(DetailedState.CONNECTED)) {
360                         WifiInfo wInfo = mWifi.getConnectionInfo();
361                         String bssid = wInfo.getBSSID();
362                         if (bssid != null && !mCachedWifiInfo.equals(wInfo.toString())) {
363                             Log.d("WifiNetworkConnected");
364                             mEventFacade.postEvent("WifiNetworkConnected", wInfo);
365                         }
366                         mCachedWifiInfo = wInfo.toString();
367                     } else {
368                         if (nInfo.getDetailedState().equals(DetailedState.DISCONNECTED)) {
369                             if (!mCachedWifiInfo.equals("")) {
370                                 mCachedWifiInfo = "";
371                                 mEventFacade.postEvent("WifiNetworkDisconnected", null);
372                             }
373                         }
374                     }
375                 }
376             } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
377                 Log.d("Supplicant connection state changed.");
378                 mIsConnected = intent
379                         .getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false);
380                 Bundle msg = new Bundle();
381                 msg.putBoolean("Connected", mIsConnected);
382                 mEventFacade.postEvent("SupplicantConnectionChanged", msg);
383             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
384                 int state = intent.getIntExtra(
385                         WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
386                 Log.d("Wifi state changed to " + state);
387                 boolean enabled;
388                 if (state == WifiManager.WIFI_STATE_DISABLED) {
389                     enabled = false;
390                 } else if (state == WifiManager.WIFI_STATE_ENABLED) {
391                     enabled = true;
392                 } else {
393                     // we only care about enabled/disabled.
394                     Log.v("Ignoring intermediate wifi state change event...");
395                     return;
396                 }
397                 Bundle msg = new Bundle();
398                 msg.putBoolean("enabled", enabled);
399                 mEventFacade.postEvent("WifiStateChanged", msg);
400             }
401         }
402     }
403 
404     public class WifiNetworkSuggestionStateChangeReceiver extends BroadcastReceiver {
405         @Override
onReceive(Context context, Intent intent)406         public void onReceive(Context context, Intent intent) {
407             String action = intent.getAction();
408             if (action.equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
409                 WifiNetworkSuggestion networkSuggestion =
410                         intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_SUGGESTION);
411                 mEventFacade.postEvent(
412                         "WifiNetworkSuggestionPostConnection",
413                         networkSuggestion.wifiConfiguration.SSID);
414             }
415         }
416     }
417 
418     public class WifiWpsCallback extends WifiManager.WpsCallback {
419         private static final String tag = "WifiWps";
420 
421         @Override
onStarted(String pin)422         public void onStarted(String pin) {
423             Bundle msg = new Bundle();
424             msg.putString("pin", pin);
425             mEventFacade.postEvent(tag + "OnStarted", msg);
426         }
427 
428         @Override
onSucceeded()429         public void onSucceeded() {
430             Log.d("Wps op succeeded");
431             mEventFacade.postEvent(tag + "OnSucceeded", null);
432         }
433 
434         @Override
onFailed(int reason)435         public void onFailed(int reason) {
436             Bundle msg = new Bundle();
437             msg.putInt("reason", reason);
438             mEventFacade.postEvent(tag + "OnFailed", msg);
439         }
440     }
441 
applyingkeyMgmt(WifiConfiguration config, ScanResult result)442     private void applyingkeyMgmt(WifiConfiguration config, ScanResult result) {
443         if (result.capabilities.contains("WEP")) {
444             config.allowedKeyManagement.set(KeyMgmt.NONE);
445             config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
446             config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
447         } else if (result.capabilities.contains("PSK")) {
448             config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
449         } else if (result.capabilities.contains("EAP")) {
450             // this is probably wrong, as we don't have a way to enter the enterprise config
451             config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
452             config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
453         } else {
454             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
455         }
456     }
457 
genWifiConfig(JSONObject j)458     private WifiConfiguration genWifiConfig(JSONObject j) throws JSONException {
459         if (j == null) {
460             return null;
461         }
462         WifiConfiguration config = new WifiConfiguration();
463         if (j.has("SSID")) {
464             config.SSID = "\"" + j.getString("SSID") + "\"";
465         } else if (j.has("ssid")) {
466             config.SSID = "\"" + j.getString("ssid") + "\"";
467         }
468         if (j.has("password")) {
469             String security;
470 
471             // Check if new security type SAE (WPA3) is present. Default to PSK
472             if (j.has("security")) {
473                 if (TextUtils.equals(j.getString("security"), "SAE")) {
474                     config.allowedKeyManagement.set(KeyMgmt.SAE);
475                     config.requirePMF = true;
476                 } else {
477                     config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
478                 }
479             } else {
480                 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
481             }
482             config.preSharedKey = "\"" + j.getString("password") + "\"";
483         } else if (j.has("preSharedKey")) {
484             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
485             config.preSharedKey = j.getString("preSharedKey");
486         } else {
487             if (j.has("security")) {
488                 if (TextUtils.equals(j.getString("security"), "OWE")) {
489                     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
490                     config.requirePMF = true;
491                 } else {
492                     config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
493                 }
494             } else {
495                 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
496             }
497         }
498         if (j.has("BSSID")) {
499             config.BSSID = j.getString("BSSID");
500         }
501         if (j.has("hiddenSSID")) {
502             config.hiddenSSID = j.getBoolean("hiddenSSID");
503         }
504         if (j.has("priority")) {
505             config.priority = j.getInt("priority");
506         }
507         if (j.has("apBand")) {
508             config.apBand = j.getInt("apBand");
509         }
510         if (j.has("wepKeys")) {
511             // Looks like we only support static WEP.
512             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
513             config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
514             config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
515             JSONArray keys = j.getJSONArray("wepKeys");
516             String[] wepKeys = new String[keys.length()];
517             for (int i = 0; i < keys.length(); i++) {
518                 wepKeys[i] = keys.getString(i);
519             }
520             config.wepKeys = wepKeys;
521         }
522         if (j.has("wepTxKeyIndex")) {
523             config.wepTxKeyIndex = j.getInt("wepTxKeyIndex");
524         }
525         if (j.has("meteredOverride")) {
526             config.meteredOverride = j.getInt("meteredOverride");
527         }
528         if (j.has("macRand")) {
529             config.macRandomizationSetting = j.getInt("macRand");
530         }
531         return config;
532     }
533 
genWifiEnterpriseConfig(JSONObject j)534     private WifiEnterpriseConfig genWifiEnterpriseConfig(JSONObject j) throws JSONException,
535             GeneralSecurityException {
536         WifiEnterpriseConfig eConfig = new WifiEnterpriseConfig();
537         if (j.has(WifiEnterpriseConfig.EAP_KEY)) {
538             int eap = j.getInt(WifiEnterpriseConfig.EAP_KEY);
539             eConfig.setEapMethod(eap);
540         }
541         if (j.has(WifiEnterpriseConfig.PHASE2_KEY)) {
542             int p2Method = j.getInt(WifiEnterpriseConfig.PHASE2_KEY);
543             eConfig.setPhase2Method(p2Method);
544         }
545         if (j.has(WifiEnterpriseConfig.CA_CERT_KEY)) {
546             String certStr = j.getString(WifiEnterpriseConfig.CA_CERT_KEY);
547             Log.v("CA Cert String is " + certStr);
548             eConfig.setCaCertificate(strToX509Cert(certStr));
549         }
550         if (j.has(WifiEnterpriseConfig.CLIENT_CERT_KEY)
551                 && j.has(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY)) {
552             String certStr = j.getString(WifiEnterpriseConfig.CLIENT_CERT_KEY);
553             String keyStr = j.getString(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY);
554             Log.v("Client Cert String is " + certStr);
555             Log.v("Client Key String is " + keyStr);
556             X509Certificate cert = strToX509Cert(certStr);
557             PrivateKey privKey = strToPrivateKey(keyStr);
558             Log.v("Cert is " + cert);
559             Log.v("Private Key is " + privKey);
560             eConfig.setClientKeyEntry(privKey, cert);
561         }
562         if (j.has(WifiEnterpriseConfig.IDENTITY_KEY)) {
563             String identity = j.getString(WifiEnterpriseConfig.IDENTITY_KEY);
564             Log.v("Setting identity to " + identity);
565             eConfig.setIdentity(identity);
566         }
567         if (j.has(WifiEnterpriseConfig.PASSWORD_KEY)) {
568             String pwd = j.getString(WifiEnterpriseConfig.PASSWORD_KEY);
569             Log.v("Setting password to " + pwd);
570             eConfig.setPassword(pwd);
571         }
572         if (j.has(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY)) {
573             String altSub = j.getString(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY);
574             Log.v("Setting Alt Subject to " + altSub);
575             eConfig.setAltSubjectMatch(altSub);
576         }
577         if (j.has(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY)) {
578             String domSuffix = j.getString(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY);
579             Log.v("Setting Domain Suffix Match to " + domSuffix);
580             eConfig.setDomainSuffixMatch(domSuffix);
581         }
582         if (j.has(WifiEnterpriseConfig.REALM_KEY)) {
583             String realm = j.getString(WifiEnterpriseConfig.REALM_KEY);
584             Log.v("Setting Domain Suffix Match to " + realm);
585             eConfig.setRealm(realm);
586         }
587         return eConfig;
588     }
589 
genWifiConfigWithEnterpriseConfig(JSONObject j)590     private WifiConfiguration genWifiConfigWithEnterpriseConfig(JSONObject j) throws JSONException,
591             GeneralSecurityException {
592         if (j == null) {
593             return null;
594         }
595         WifiConfiguration config = new WifiConfiguration();
596         config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
597         config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
598 
599         if (j.has("security")) {
600             if (TextUtils.equals(j.getString("security"), "SUITE_B_192")) {
601                 config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
602                 config.requirePMF = true;
603             }
604         }
605 
606         if (j.has("SSID")) {
607             config.SSID = "\"" + j.getString("SSID") + "\"";
608         } else if (j.has("ssid")) {
609             config.SSID = "\"" + j.getString("ssid") + "\"";
610         }
611         if (j.has("FQDN")) {
612             config.FQDN = j.getString("FQDN");
613         }
614         if (j.has("providerFriendlyName")) {
615             config.providerFriendlyName = j.getString("providerFriendlyName");
616         }
617         if (j.has("roamingConsortiumIds")) {
618             JSONArray ids = j.getJSONArray("roamingConsortiumIds");
619             long[] rIds = new long[ids.length()];
620             for (int i = 0; i < ids.length(); i++) {
621                 rIds[i] = ids.getLong(i);
622             }
623             config.roamingConsortiumIds = rIds;
624         }
625         config.enterpriseConfig = genWifiEnterpriseConfig(j);
626         return config;
627     }
628 
genWifiNetworkSpecifier(JSONObject j)629     private NetworkSpecifier genWifiNetworkSpecifier(JSONObject j) throws JSONException,
630             GeneralSecurityException {
631         if (j == null) {
632             return null;
633         }
634         WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder();
635         if (j.has("SSID")) {
636             builder = builder.setSsid(j.getString("SSID"));
637         } else if (j.has("ssidPattern")) {
638             builder = builder.setSsidPattern(
639                     new PatternMatcher(j.getString("ssidPattern"),
640                             PatternMatcher.PATTERN_ADVANCED_GLOB));
641         }
642         if (j.has("BSSID")) {
643             builder = builder.setBssid(MacAddress.fromString(j.getString("BSSID")));
644         } else if (j.has("bssidPattern")) {
645             builder = builder.setBssidPattern(
646                     MacAddress.fromString(j.getJSONArray("bssidPattern").getString(0)),
647                     MacAddress.fromString(j.getJSONArray("bssidPattern").getString(1)));
648         }
649         if (j.has("hiddenSSID")) {
650             builder = builder.setIsHiddenSsid(j.getBoolean("hiddenSSID"));
651         }
652         if (j.has("isEnhancedOpen")) {
653             builder = builder.setIsEnhancedOpen(j.getBoolean("isEnhancedOpen"));
654         }
655         boolean isWpa3 = false;
656         if (j.has("isWpa3") && j.getBoolean("isWpa3")) {
657             isWpa3 = true;
658         }
659         if (j.has("password")) {
660             if (!isWpa3) {
661                 builder = builder.setWpa2Passphrase(j.getString("password"));
662             } else {
663                 builder = builder.setWpa3Passphrase(j.getString("password"));
664             }
665         }
666         if (j.has(WifiEnterpriseConfig.EAP_KEY)) {
667             if (!isWpa3) {
668                 builder = builder.setWpa2EnterpriseConfig(genWifiEnterpriseConfig(j));
669             } else {
670                 builder = builder.setWpa3EnterpriseConfig(genWifiEnterpriseConfig(j));
671             }
672         }
673         return builder.build();
674     }
675 
genWifiNetworkSuggestion(JSONObject j)676     private WifiNetworkSuggestion genWifiNetworkSuggestion(JSONObject j) throws JSONException,
677             GeneralSecurityException {
678         if (j == null) {
679             return null;
680         }
681         WifiNetworkSuggestion.Builder builder = new WifiNetworkSuggestion.Builder();
682         if (j.has("SSID")) {
683             builder = builder.setSsid(j.getString("SSID"));
684         }
685         if (j.has("BSSID")) {
686             builder = builder.setBssid(MacAddress.fromString(j.getString("BSSID")));
687         }
688         if (j.has("hiddenSSID")) {
689             builder = builder.setIsHiddenSsid(j.getBoolean("hiddenSSID"));
690         }
691         if (j.has("isEnhancedOpen")) {
692             builder = builder.setIsEnhancedOpen(j.getBoolean("isEnhancedOpen"));
693         }
694         boolean isWpa3 = false;
695         if (j.has("isWpa3") && j.getBoolean("isWpa3")) {
696             isWpa3 = true;
697         }
698         if (j.has("password")) {
699             if (!isWpa3) {
700                 builder = builder.setWpa2Passphrase(j.getString("password"));
701             } else {
702                 builder = builder.setWpa3Passphrase(j.getString("password"));
703             }
704         }
705         if (j.has(WifiEnterpriseConfig.EAP_KEY)) {
706             if (!isWpa3) {
707                 builder = builder.setWpa2EnterpriseConfig(genWifiEnterpriseConfig(j));
708             } else {
709                 builder = builder.setWpa3EnterpriseConfig(genWifiEnterpriseConfig(j));
710             }
711         }
712         if (j.has("isAppInteractionRequired")) {
713             builder = builder.setIsAppInteractionRequired(j.getBoolean("isAppInteractionRequired"));
714         }
715         if (j.has("isUserInteractionRequired")) {
716             builder = builder.setIsUserInteractionRequired(
717                     j.getBoolean("isUserInteractionRequired"));
718         }
719         if (j.has("isMetered")) {
720             builder = builder.setIsMetered(j.getBoolean("isMetered"));
721         }
722         if (j.has("priority")) {
723             builder = builder.setPriority(j.getInt("priority"));
724         }
725         return builder.build();
726     }
727 
genWifiNetworkSuggestions( JSONArray jsonNetworkSuggestionsArray)728     private List<WifiNetworkSuggestion> genWifiNetworkSuggestions(
729             JSONArray jsonNetworkSuggestionsArray) throws JSONException, GeneralSecurityException {
730         if (jsonNetworkSuggestionsArray == null) {
731             return null;
732         }
733         List<WifiNetworkSuggestion> networkSuggestions = new ArrayList<>();
734         for (int i = 0; i < jsonNetworkSuggestionsArray.length(); i++) {
735             networkSuggestions.add(
736                     genWifiNetworkSuggestion(jsonNetworkSuggestionsArray.getJSONObject(i)));
737         }
738         return networkSuggestions;
739     }
740 
matchScanResult(ScanResult result, String id)741     private boolean matchScanResult(ScanResult result, String id) {
742         if (result.BSSID.equals(id) || result.SSID.equals(id)) {
743             return true;
744         }
745         return false;
746     }
747 
parseWpsInfo(String infoStr)748     private WpsInfo parseWpsInfo(String infoStr) throws JSONException {
749         if (infoStr == null) {
750             return null;
751         }
752         JSONObject j = new JSONObject(infoStr);
753         WpsInfo info = new WpsInfo();
754         if (j.has("setup")) {
755             info.setup = j.getInt("setup");
756         }
757         if (j.has("BSSID")) {
758             info.BSSID = j.getString("BSSID");
759         }
760         if (j.has("pin")) {
761             info.pin = j.getString("pin");
762         }
763         return info;
764     }
765 
base64StrToBytes(String input)766     private byte[] base64StrToBytes(String input) {
767         return Base64.decode(input, Base64.DEFAULT);
768     }
769 
strToX509Cert(String certStr)770     private X509Certificate strToX509Cert(String certStr) throws CertificateException {
771         byte[] certBytes = base64StrToBytes(certStr);
772         InputStream certStream = new ByteArrayInputStream(certBytes);
773         CertificateFactory cf = CertificateFactory.getInstance("X509");
774         return (X509Certificate) cf.generateCertificate(certStream);
775     }
776 
strToPrivateKey(String key)777     private PrivateKey strToPrivateKey(String key) throws NoSuchAlgorithmException,
778             InvalidKeySpecException {
779         byte[] keyBytes = base64StrToBytes(key);
780         PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
781         KeyFactory fact = KeyFactory.getInstance("RSA");
782         PrivateKey priv = fact.generatePrivate(keySpec);
783         return priv;
784     }
785 
strToPublicKey(String key)786     private PublicKey strToPublicKey(String key) throws NoSuchAlgorithmException,
787             InvalidKeySpecException {
788         byte[] keyBytes = base64StrToBytes(key);
789         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
790         KeyFactory fact = KeyFactory.getInstance("RSA");
791         PublicKey pub = fact.generatePublic(keySpec);
792         return pub;
793     }
794 
wifiConfigurationFromScanResult(ScanResult result)795     private WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) {
796         if (result == null)
797             return null;
798         WifiConfiguration config = new WifiConfiguration();
799         config.SSID = "\"" + result.SSID + "\"";
800         applyingkeyMgmt(config, result);
801         config.BSSID = result.BSSID;
802         return config;
803     }
804 
805     @Rpc(description = "test.")
wifiTest( @pcParametername = "certString") String certString)806     public String wifiTest(
807             @RpcParameter(name = "certString") String certString) throws CertificateException, IOException {
808         // TODO(angli): Make this work. Convert a X509Certificate back to a string.
809         X509Certificate caCert = strToX509Cert(certString);
810         caCert.getEncoded();
811         ByteArrayOutputStream bos = new ByteArrayOutputStream();
812         ObjectOutput out = new ObjectOutputStream(bos);
813         out.writeObject(caCert);
814         byte[] data = bos.toByteArray();
815         bos.close();
816         return Base64.encodeToString(data, Base64.DEFAULT);
817     }
818 
819     @Rpc(description = "Add a network.")
820     @Deprecated
wifiAddNetwork(@pcParametername = "wifiConfig") JSONObject wifiConfig)821     public Integer wifiAddNetwork(@RpcParameter(name = "wifiConfig") JSONObject wifiConfig)
822             throws JSONException {
823         return wifiaddOrUpdateNetwork(wifiConfig);
824     }
825 
826     @Rpc(description = "Add or update a network.")
wifiaddOrUpdateNetwork(@pcParametername = "wifiConfig") JSONObject wifiConfig)827     public Integer wifiaddOrUpdateNetwork(@RpcParameter(name = "wifiConfig") JSONObject wifiConfig)
828             throws JSONException {
829         return mWifi.addNetwork(genWifiConfig(wifiConfig));
830     }
831 
832     @Rpc(description = "Cancel Wi-fi Protected Setup.")
wifiCancelWps()833     public void wifiCancelWps() throws JSONException {
834         WifiWpsCallback listener = new WifiWpsCallback();
835         mWifi.cancelWps(listener);
836     }
837 
838     @Rpc(description = "Checks Wifi state.", returns = "True if Wifi is enabled.")
wifiCheckState()839     public Boolean wifiCheckState() {
840         return mWifi.getWifiState() == WifiManager.WIFI_STATE_ENABLED;
841     }
842 
843     /**
844     * @deprecated Use {@link #wifiConnectByConfig(config)} instead.
845     */
846     @Rpc(description = "Connects to the network with the given configuration")
847     @Deprecated
wifiConnect(@pcParametername = "config") JSONObject config)848     public Boolean wifiConnect(@RpcParameter(name = "config") JSONObject config)
849             throws JSONException {
850         try {
851             wifiConnectByConfig(config);
852         } catch (GeneralSecurityException e) {
853             String msg = "Caught GeneralSecurityException with the provided"
854                          + "configuration";
855             throw new RuntimeException(msg);
856         }
857         return true;
858     }
859 
860     /**
861     * @deprecated Use {@link #wifiConnectByConfig(config)} instead.
862     */
863     @Rpc(description = "Connects to the network with the given configuration")
864     @Deprecated
wifiEnterpriseConnect(@pcParametername = "config") JSONObject config)865     public Boolean wifiEnterpriseConnect(@RpcParameter(name = "config")
866             JSONObject config) throws JSONException, GeneralSecurityException {
867         try {
868             wifiConnectByConfig(config);
869         } catch (GeneralSecurityException e) {
870             throw e;
871         }
872         return true;
873     }
874 
875     /**
876      * Connects to a wifi network using configuration.
877      * @param config JSONObject Dictionary of wifi connection parameters
878      * @throws JSONException
879      * @throws GeneralSecurityException
880      */
881     @Rpc(description = "Connects to the network with the given configuration")
wifiConnectByConfig(@pcParametername = "config") JSONObject config)882     public void wifiConnectByConfig(@RpcParameter(name = "config") JSONObject config)
883             throws JSONException, GeneralSecurityException {
884         WifiConfiguration wifiConfig;
885         WifiActionListener listener;
886         // Check if this is 802.1x or 802.11x config.
887         if (config.has(WifiEnterpriseConfig.EAP_KEY)) {
888             wifiConfig = genWifiConfigWithEnterpriseConfig(config);
889         } else {
890             wifiConfig = genWifiConfig(config);
891         }
892         listener = new WifiActionListener(mEventFacade,
893                 WifiConstants.WIFI_CONNECT_BY_CONFIG_CALLBACK);
894         mWifi.connect(wifiConfig, listener);
895     }
896 
897     /**
898     * Gets the Wi-Fi factory MAC addresses.
899     * @return An array of String represnting Wi-Fi MAC addresses,
900     *         Or an empty Srting if failed.
901     */
902     @Rpc(description = "Gets the Wi-Fi factory MAC addresses", returns = "An array of String, representing the MAC address")
wifigetFactorymacAddresses()903     public String[] wifigetFactorymacAddresses(){
904         return mWifi.getFactoryMacAddresses();
905     }
906 
907     @Rpc(description = "Gets the randomized MAC address", returns = "A MAC address or null")
wifigetRandomizedMacAddress(@pcParametername = "config") JSONObject config)908     public MacAddress wifigetRandomizedMacAddress(@RpcParameter(name = "config") JSONObject config)
909             throws JSONException{
910         List<WifiConfiguration> configList = mWifi.getConfiguredNetworks();
911         for(WifiConfiguration WifiConfig : configList){
912             String ssid = WifiConfig.SSID;
913             ssid = ssid.replace("\"", "");
914             if (ssid.equals(config.getString("SSID"))){
915                 return WifiConfig.getRandomizedMacAddress();
916             }
917         }
918         Log.d("Did not find a matching object in wifiManager.");
919         return null;
920     }
921    /**
922      * Generate a Passpoint configuration from JSON config.
923      * @param config JSON config containing base64 encoded Passpoint profile
924      */
925     @Rpc(description = "Generate Passpoint configuration", returns = "PasspointConfiguration object")
genWifiPasspointConfig(@pcParameter name = "config") JSONObject config)926     public PasspointConfiguration genWifiPasspointConfig(@RpcParameter(
927             name = "config") JSONObject config)
928             throws JSONException,CertificateException, IOException {
929         String profileStr = "";
930         if (config == null) {
931             return null;
932         }
933         if (config.has("profile")) {
934             profileStr =  config.getString("profile");
935         }
936         return ConfigParser.parsePasspointConfig(TYPE_WIFICONFIG,
937                 profileStr.getBytes());
938     }
939 
940    /**
941      * Add or update a Passpoint configuration.
942      * @param config base64 encoded message containing Passpoint profile
943      * @throws JSONException
944      */
945     @Rpc(description = "Add or update a Passpoint configuration")
addUpdatePasspointConfig(@pcParameter name = "config") JSONObject config)946     public void addUpdatePasspointConfig(@RpcParameter(
947             name = "config") JSONObject config)
948             throws JSONException,CertificateException, IOException {
949         PasspointConfiguration passpointConfig = genWifiPasspointConfig(config);
950         mWifi.addOrUpdatePasspointConfiguration(passpointConfig);
951     }
952 
953     /**
954      * Remove a Passpoint configuration.
955      * @param fqdn The FQDN of the passpoint configuration to be removed
956      * @return true on success; false otherwise
957      */
958     @Rpc(description = "Remove a Passpoint configuration")
removePasspointConfig( @pcParametername = "fqdn") String fqdn)959     public void removePasspointConfig(
960             @RpcParameter(name = "fqdn") String fqdn) {
961         mWifi.removePasspointConfiguration(fqdn);
962     }
963 
964     /**
965      * Get list of Passpoint configurations.
966      * @return A list of FQDNs of the Passpoint configurations
967      */
968     @Rpc(description = "Return the list of installed Passpoint configurations", returns = "A list of Passpoint configurations")
getPasspointConfigs()969     public List<String> getPasspointConfigs() {
970         List<String> fqdnList = new ArrayList<String>();
971         for(PasspointConfiguration passpoint :
972             mWifi.getPasspointConfigurations()) {
973             fqdnList.add(passpoint.getHomeSp().getFqdn());
974         }
975         return fqdnList;
976     }
977 
978     private class ProvisioningCallbackFacade extends ProvisioningCallback {
979         private final EventFacade mEventFacade;
980 
ProvisioningCallbackFacade(EventFacade eventFacade)981         ProvisioningCallbackFacade(EventFacade eventFacade) {
982             mEventFacade = eventFacade;
983         }
984 
985         @Override
onProvisioningFailure(int status)986         public void onProvisioningFailure(int status) {
987             Log.v("Provisioning Failure " + status);
988             Bundle msg = new Bundle();
989             msg.putString("tag", "failure");
990             msg.putInt("reason", status);
991             mEventFacade.postEvent("onProvisioningCallback", msg);
992         }
993 
994         @Override
onProvisioningStatus(int status)995         public void onProvisioningStatus(int status) {
996             Log.v("Provisioning status " + status);
997             Bundle msg = new Bundle();
998             msg.putString("tag", "status");
999             msg.putInt("status", status);
1000             mEventFacade.postEvent("onProvisioningCallback", msg);
1001         }
1002 
1003         @Override
onProvisioningComplete()1004         public void onProvisioningComplete() {
1005             Log.v("Provisioning Complete");
1006             Bundle msg = new Bundle();
1007             msg.putString("tag", "success");
1008             mEventFacade.postEvent("onProvisioningCallback", msg);
1009         }
1010     }
1011 
buildTestOsuProvider(JSONObject config)1012     private OsuProvider buildTestOsuProvider(JSONObject config) {
1013         String osuServiceDescription = "Google Passpoint Test Service";
1014         List<Integer> osuMethodList =
1015                 Arrays.asList(OsuProvider.METHOD_SOAP_XML_SPP);
1016 
1017         try {
1018             if (!config.has("osuSSID")) {
1019                 Log.e("missing osuSSID from the config");
1020                 return null;
1021             }
1022             WifiSsid osuSsid = WifiSsid.createFromByteArray(
1023                     config.getString("osuSSID").getBytes(StandardCharsets.UTF_8));
1024 
1025             if (!config.has("osuUri")) {
1026                 Log.e("missing osuUri from the config");
1027                 return null;
1028             }
1029             Uri osuServerUri = Uri.parse(config.getString("osuUri"));
1030 
1031             Log.v("OSU Server URI " + osuServerUri.toString());
1032             if (!config.has("osuFriendlyName")) {
1033                 Log.e("missing osuFriendlyName from the config");
1034                 return null;
1035             }
1036             String osuFriendlyName = config.getString("osuFriendlyName");
1037 
1038             if (config.has("description")) {
1039                 osuServiceDescription = config.getString("description");
1040             }
1041             Map<String, String> osuFriendlyNames = new HashMap<>();
1042             osuFriendlyNames.put("en", osuFriendlyName);
1043             return new OsuProvider(osuSsid, osuFriendlyNames, osuServiceDescription,
1044                     osuServerUri, null, osuMethodList, null);
1045         } catch (JSONException e) {
1046             Log.e("JSON Parsing error: " + e);
1047             return null;
1048         }
1049     }
1050 
1051     /**
1052      * Start subscription provisioning
1053      */
1054     @Rpc(description = "Starts subscription provisioning flow")
startSubscriptionProvisioning( @pcParametername = "configJson") JSONObject configJson)1055     public void startSubscriptionProvisioning(
1056             @RpcParameter(name = "configJson") JSONObject configJson) {
1057         ProvisioningCallback callback = new ProvisioningCallbackFacade(mEventFacade);
1058         mWifi.startSubscriptionProvisioning(buildTestOsuProvider(configJson),
1059                 mService.getMainExecutor(), callback);
1060     }
1061 
1062     /**
1063      * Connects to a wifi network using networkId.
1064      * @param networkId the network identity for the network in the supplicant
1065      */
1066     @Rpc(description = "Connects to the network with the given networkId")
wifiConnectByNetworkId( @pcParametername = "networkId") Integer networkId)1067     public void wifiConnectByNetworkId(
1068             @RpcParameter(name = "networkId") Integer networkId) {
1069         WifiActionListener listener;
1070         listener = new WifiActionListener(mEventFacade,
1071                 WifiConstants.WIFI_CONNECT_BY_NETID_CALLBACK);
1072         mWifi.connect(networkId, listener);
1073     }
1074 
1075     @Rpc(description = "Disconnects from the currently active access point.", returns = "True if the operation succeeded.")
wifiDisconnect()1076     public Boolean wifiDisconnect() {
1077         return mWifi.disconnect();
1078     }
1079 
1080     @Rpc(description = "Enable/disable autojoin scan and switch network when connected.")
wifiSetEnableAutoJoinWhenAssociated(@pcParametername = "enable") Boolean enable)1081     public Boolean wifiSetEnableAutoJoinWhenAssociated(@RpcParameter(name = "enable") Boolean enable) {
1082         return mWifi.setEnableAutoJoinWhenAssociated(enable);
1083     }
1084 
1085     @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)1086     public Boolean wifiEnableNetwork(@RpcParameter(name = "netId") Integer netId,
1087             @RpcParameter(name = "disableOthers") Boolean disableOthers) {
1088         return mWifi.enableNetwork(netId, disableOthers);
1089     }
1090 
1091     @Rpc(description = "Enable WiFi verbose logging.")
wifiEnableVerboseLogging(@pcParametername = "level") Integer level)1092     public void wifiEnableVerboseLogging(@RpcParameter(name = "level") Integer level) {
1093         mWifi.enableVerboseLogging(level);
1094     }
1095 
1096     @Rpc(description = "Resets all WifiManager settings.")
wifiFactoryReset()1097     public void wifiFactoryReset() {
1098         mWifi.factoryReset();
1099     }
1100 
1101     /**
1102      * Forget a wifi network by networkId.
1103      *
1104      * @param networkId Id of wifi network
1105      */
1106     @Rpc(description = "Forget a wifi network by networkId")
wifiForgetNetwork(@pcParametername = "wifiSSID") Integer networkId)1107     public void wifiForgetNetwork(@RpcParameter(name = "wifiSSID") Integer networkId) {
1108         WifiActionListener listener = new WifiActionListener(mEventFacade,
1109                 WifiConstants.WIFI_FORGET_NETWORK_CALLBACK);
1110         mWifi.forget(networkId, listener);
1111     }
1112 
1113     /**
1114      * Disable ephemeral network.
1115      *
1116      * @param ssid SSID of wifi network
1117      */
1118     @Rpc(description = "Forget a wifi network by networkId")
wifiDisableEphemeralNetwork(@pcParametername = "ssid") String ssid)1119     public void wifiDisableEphemeralNetwork(@RpcParameter(name = "ssid") String ssid) {
1120         mWifi.disableEphemeralNetwork("\"" + ssid + "\"");
1121     }
1122 
1123     @Rpc(description = "Gets the Wi-Fi AP Configuration.")
wifiGetApConfiguration()1124     public WifiConfiguration wifiGetApConfiguration() {
1125         return mWifi.getWifiApConfiguration();
1126     }
1127 
1128     @Rpc(description = "Return a list of all the configured wifi networks.")
wifiGetConfiguredNetworks()1129     public List<WifiConfiguration> wifiGetConfiguredNetworks() {
1130         return mWifi.getConfiguredNetworks();
1131     }
1132 
1133     @Rpc(description = "Returns information about the currently active access point.")
wifiGetConnectionInfo()1134     public WifiInfo wifiGetConnectionInfo() {
1135         return mWifi.getConnectionInfo();
1136     }
1137 
1138     @Rpc(description = "Returns wifi activity and energy usage info.")
wifiGetControllerActivityEnergyInfo()1139     public WifiActivityEnergyInfo wifiGetControllerActivityEnergyInfo() {
1140         return mWifi.getControllerActivityEnergyInfo();
1141     }
1142 
1143     @Rpc(description = "Get the country code used by WiFi.")
wifiGetCountryCode()1144     public String wifiGetCountryCode() {
1145         return mWifi.getCountryCode();
1146     }
1147 
1148     @Rpc(description = "Get the current network.")
wifiGetCurrentNetwork()1149     public Network wifiGetCurrentNetwork() {
1150         return mWifi.getCurrentNetwork();
1151     }
1152 
1153     @Rpc(description = "Get the info from last successful DHCP request.")
wifiGetDhcpInfo()1154     public DhcpInfo wifiGetDhcpInfo() {
1155         return mWifi.getDhcpInfo();
1156     }
1157 
1158     @Rpc(description = "Get setting for Framework layer autojoin enable status.")
wifiGetEnableAutoJoinWhenAssociated()1159     public Boolean wifiGetEnableAutoJoinWhenAssociated() {
1160         return mWifi.getEnableAutoJoinWhenAssociated();
1161     }
1162 
1163     @Rpc(description = "Get privileged configured networks.")
wifiGetPrivilegedConfiguredNetworks()1164     public List<WifiConfiguration> wifiGetPrivilegedConfiguredNetworks() {
1165         return mWifi.getPrivilegedConfiguredNetworks();
1166     }
1167 
1168     @Rpc(description = "Returns the list of access points found during the most recent Wifi scan.")
wifiGetScanResults()1169     public List<ScanResult> wifiGetScanResults() {
1170         return mWifi.getScanResults();
1171     }
1172 
1173     @Rpc(description = "Get the current level of WiFi verbose logging.")
wifiGetVerboseLoggingLevel()1174     public Integer wifiGetVerboseLoggingLevel() {
1175         return mWifi.getVerboseLoggingLevel();
1176     }
1177 
1178     @Rpc(description = "true if this adapter supports 5 GHz band.")
wifiIs5GHzBandSupported()1179     public Boolean wifiIs5GHzBandSupported() {
1180         return mWifi.is5GHzBandSupported();
1181     }
1182 
1183     @Rpc(description = "true if this adapter supports multiple simultaneous connections.")
wifiIsAdditionalStaSupported()1184     public Boolean wifiIsAdditionalStaSupported() {
1185         return mWifi.isAdditionalStaSupported();
1186     }
1187 
1188     @Rpc(description = "Return true if WiFi is enabled.")
wifiGetisWifiEnabled()1189     public Boolean wifiGetisWifiEnabled() {
1190         return mWifi.isWifiEnabled();
1191     }
1192 
1193     @Rpc(description = "Return whether Wi-Fi AP is enabled or disabled.")
wifiIsApEnabled()1194     public Boolean wifiIsApEnabled() {
1195         return mWifi.isWifiApEnabled();
1196     }
1197 
1198     @Rpc(description = "Check if Device-to-AP RTT is supported.")
wifiIsDeviceToApRttSupported()1199     public Boolean wifiIsDeviceToApRttSupported() {
1200         return mWifi.isDeviceToApRttSupported();
1201     }
1202 
1203     @Rpc(description = "Check if Device-to-device RTT is supported.")
wifiIsDeviceToDeviceRttSupported()1204     public Boolean wifiIsDeviceToDeviceRttSupported() {
1205         return mWifi.isDeviceToDeviceRttSupported();
1206     }
1207 
1208     @Rpc(description = "Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz).")
wifiIsDualBandSupported()1209     public Boolean wifiIsDualBandSupported() {
1210         return mWifi.isDualBandSupported();
1211     }
1212 
1213     @Rpc(description = "Check if this adapter supports advanced power/performance counters.")
wifiIsEnhancedPowerReportingSupported()1214     public Boolean wifiIsEnhancedPowerReportingSupported() {
1215         return mWifi.isEnhancedPowerReportingSupported();
1216     }
1217 
1218     @Rpc(description = "Check if multicast is enabled.")
wifiIsMulticastEnabled()1219     public Boolean wifiIsMulticastEnabled() {
1220         return mWifi.isMulticastEnabled();
1221     }
1222 
1223     @Rpc(description = "true if this adapter supports Wi-Fi Aware APIs.")
wifiIsAwareSupported()1224     public Boolean wifiIsAwareSupported() {
1225         return mWifi.isWifiAwareSupported();
1226     }
1227 
1228     @Rpc(description = "true if this adapter supports Off Channel Tunnel Directed Link Setup.")
wifiIsOffChannelTdlsSupported()1229     public Boolean wifiIsOffChannelTdlsSupported() {
1230         return mWifi.isOffChannelTdlsSupported();
1231     }
1232 
1233     @Rpc(description = "true if this adapter supports WifiP2pManager (Wi-Fi Direct).")
wifiIsP2pSupported()1234     public Boolean wifiIsP2pSupported() {
1235         return mWifi.isP2pSupported();
1236     }
1237 
1238     @Rpc(description = "true if this adapter supports passpoint.")
wifiIsPasspointSupported()1239     public Boolean wifiIsPasspointSupported() {
1240         return mWifi.isPasspointSupported();
1241     }
1242 
1243     @Rpc(description = "true if this adapter supports portable Wi-Fi hotspot.")
wifiIsPortableHotspotSupported()1244     public Boolean wifiIsPortableHotspotSupported() {
1245         return mWifi.isPortableHotspotSupported();
1246     }
1247 
1248     @Rpc(description = "true if this adapter supports offloaded connectivity scan.")
wifiIsPreferredNetworkOffloadSupported()1249     public Boolean wifiIsPreferredNetworkOffloadSupported() {
1250         return mWifi.isPreferredNetworkOffloadSupported();
1251     }
1252 
1253     @Rpc(description = "Check if wifi scanner is supported on this device.")
wifiIsScannerSupported()1254     public Boolean wifiIsScannerSupported() {
1255         return mWifi.isWifiScannerSupported();
1256     }
1257 
1258     @Rpc(description = "Check if tdls is supported on this device.")
wifiIsTdlsSupported()1259     public Boolean wifiIsTdlsSupported() {
1260         return mWifi.isTdlsSupported();
1261     }
1262 
1263     /**
1264      * @return true if this device supports WPA3-Personal SAE
1265      */
1266     @Rpc(description = "Check if WPA3-Personal SAE is supported on this device.")
wifiIsWpa3SaeSupported()1267     public Boolean wifiIsWpa3SaeSupported() {
1268         return mWifi.isWpa3SaeSupported();
1269     }
1270     /**
1271      * @return true if this device supports WPA3-Enterprise Suite-B-192
1272      */
1273     @Rpc(description = "Check if WPA3-Enterprise Suite-B-192 is supported on this device.")
wifiIsWpa3SuiteBSupported()1274     public Boolean wifiIsWpa3SuiteBSupported() {
1275         return mWifi.isWpa3SuiteBSupported();
1276     }
1277     /**
1278      * @return true if this device supports Wi-Fi Enhanced Open (OWE)
1279      */
1280     @Rpc(description = "Check if Enhanced Open (OWE) is supported on this device.")
wifiIsEnhancedOpenSupported()1281     public Boolean wifiIsEnhancedOpenSupported() {
1282         return mWifi.isEnhancedOpenSupported();
1283     }
1284     /**
1285      * @return true if this device supports Wi-Fi Device Provisioning Protocol (Easy-connect)
1286      */
1287     @Rpc(description = "Check if Easy Connect (DPP) is supported on this device.")
wifiIsEasyConnectSupported()1288     public Boolean wifiIsEasyConnectSupported() {
1289         return mWifi.isEasyConnectSupported();
1290     }
1291 
1292     @Rpc(description = "Acquires a full Wifi lock.")
wifiLockAcquireFull()1293     public void wifiLockAcquireFull() {
1294         makeLock(WifiManager.WIFI_MODE_FULL);
1295     }
1296 
1297     @Rpc(description = "Acquires a scan only Wifi lock.")
wifiLockAcquireScanOnly()1298     public void wifiLockAcquireScanOnly() {
1299         makeLock(WifiManager.WIFI_MODE_SCAN_ONLY);
1300     }
1301 
1302     @Rpc(description = "Releases a previously acquired Wifi lock.")
wifiLockRelease()1303     public void wifiLockRelease() {
1304         if (mLock != null) {
1305             mLock.release();
1306             mLock = null;
1307         }
1308     }
1309 
1310     @Rpc(description = "Reassociates with the currently active access point.", returns = "True if the operation succeeded.")
wifiReassociate()1311     public Boolean wifiReassociate() {
1312         return mWifi.reassociate();
1313     }
1314 
1315     @Rpc(description = "Reconnects to the currently active access point.", returns = "True if the operation succeeded.")
wifiReconnect()1316     public Boolean wifiReconnect() {
1317         return mWifi.reconnect();
1318     }
1319 
1320     @Rpc(description = "Remove a configured network.", returns = "True if the operation succeeded.")
wifiRemoveNetwork(@pcParametername = "netId") Integer netId)1321     public Boolean wifiRemoveNetwork(@RpcParameter(name = "netId") Integer netId) {
1322         return mWifi.removeNetwork(netId);
1323     }
1324 
createSoftApWifiConfiguration(JSONObject configJson)1325     private WifiConfiguration createSoftApWifiConfiguration(JSONObject configJson)
1326             throws JSONException {
1327         WifiConfiguration config = genWifiConfig(configJson);
1328         // Need to strip of extra quotation marks for SSID and password.
1329         String ssid = config.SSID;
1330         if (ssid != null) {
1331             config.SSID = ssid.substring(1, ssid.length() - 1);
1332         }
1333 
1334         config.allowedKeyManagement.clear();
1335         String pwd = config.preSharedKey;
1336         if (pwd != null) {
1337             config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
1338             config.preSharedKey = pwd.substring(1, pwd.length() - 1);
1339         } else {
1340             config.allowedKeyManagement.set(KeyMgmt.NONE);
1341         }
1342         return config;
1343     }
1344 
1345     @Rpc(description = "Set configuration for soft AP.")
wifiSetWifiApConfiguration( @pcParametername = "configJson") JSONObject configJson)1346     public Boolean wifiSetWifiApConfiguration(
1347             @RpcParameter(name = "configJson") JSONObject configJson) throws JSONException {
1348         WifiConfiguration config = createSoftApWifiConfiguration(configJson);
1349         return mWifi.setWifiApConfiguration(config);
1350     }
1351 
1352     /**
1353      * Register softap callback.
1354      *
1355      * @return the id associated with the {@link SoftApCallbackImp}
1356      * used for registering callback.
1357      */
1358     @Rpc(description = "Register softap callback function.",
1359             returns = "Id of the callback associated with registering.")
registerSoftApCallback()1360     public Integer registerSoftApCallback() {
1361         SoftApCallbackImp softApCallback = new SoftApCallbackImp(mEventFacade);
1362         mSoftapCallbacks.put(softApCallback.mId, softApCallback);
1363         mWifi.registerSoftApCallback(softApCallback,
1364                 new Handler(mCallbackHandlerThread.getLooper()));
1365         return softApCallback.mId;
1366     }
1367 
1368     /**
1369      * Unregister softap callback role for the {@link SoftApCallbackImp} identified by the given
1370      * {@code callbackId}.
1371      *
1372      * @param callbackId the id associated with the {@link SoftApCallbackImp}
1373      * used for registering callback.
1374      *
1375      */
1376     @Rpc(description = "Unregister softap callback function.")
unregisterSoftApCallback(@pcParametername = "callbackId") Integer callbackId)1377     public void unregisterSoftApCallback(@RpcParameter(name = "callbackId") Integer callbackId) {
1378         mWifi.unregisterSoftApCallback(mSoftapCallbacks.get(callbackId));
1379         mSoftapCallbacks.delete(callbackId);
1380     }
1381 
1382     @Rpc(description = "Set the country code used by WiFi.")
wifiSetCountryCode( @pcParametername = "country") String country)1383     public void wifiSetCountryCode(
1384             @RpcParameter(name = "country") String country) {
1385         mWifi.setCountryCode(country);
1386     }
1387 
1388     @Rpc(description = "Enable/disable tdls with a mac address.")
wifiSetTdlsEnabledWithMacAddress( @pcParametername = "remoteMacAddress") String remoteMacAddress, @RpcParameter(name = "enable") Boolean enable)1389     public void wifiSetTdlsEnabledWithMacAddress(
1390             @RpcParameter(name = "remoteMacAddress") String remoteMacAddress,
1391             @RpcParameter(name = "enable") Boolean enable) {
1392         mWifi.setTdlsEnabledWithMacAddress(remoteMacAddress, enable);
1393     }
1394 
1395     @Rpc(description = "Starts a scan for Wifi access points.", returns = "True if the scan was initiated successfully.")
wifiStartScan()1396     public Boolean wifiStartScan() {
1397         mService.registerReceiver(mScanResultsAvailableReceiver, mScanFilter);
1398         return mWifi.startScan();
1399     }
1400 
1401     @Rpc(description = "Start Wi-fi Protected Setup.")
wifiStartWps( @pcParametername = "config", description = "A json string with fields \\"setup\\", \\"BSSID\\", and \\"pin\\"") String config)1402     public void wifiStartWps(
1403             @RpcParameter(name = "config", description = "A json string with fields \"setup\", \"BSSID\", and \"pin\"") String config)
1404                     throws JSONException {
1405         WpsInfo info = parseWpsInfo(config);
1406         WifiWpsCallback listener = new WifiWpsCallback();
1407         Log.d("Starting wps with: " + info);
1408         mWifi.startWps(info, listener);
1409     }
1410 
1411     @Rpc(description = "Start listening for wifi state change related broadcasts.")
wifiStartTrackingStateChange()1412     public void wifiStartTrackingStateChange() {
1413         mService.registerReceiver(mStateChangeReceiver, mStateChangeFilter);
1414         mTrackingWifiStateChange = true;
1415     }
1416 
1417     @Rpc(description = "Stop listening for wifi state change related broadcasts.")
wifiStopTrackingStateChange()1418     public void wifiStopTrackingStateChange() {
1419         if (mTrackingWifiStateChange == true) {
1420             mService.unregisterReceiver(mStateChangeReceiver);
1421             mTrackingWifiStateChange = false;
1422         }
1423     }
1424 
1425     @Rpc(description = "Start listening for tether state change related broadcasts.")
wifiStartTrackingTetherStateChange()1426     public void wifiStartTrackingTetherStateChange() {
1427         mService.registerReceiver(mTetherStateReceiver, mTetherFilter);
1428         mTrackingTetherStateChange = true;
1429     }
1430 
1431     @Rpc(description = "Stop listening for wifi state change related broadcasts.")
wifiStopTrackingTetherStateChange()1432     public void wifiStopTrackingTetherStateChange() {
1433         if (mTrackingTetherStateChange == true) {
1434             mService.unregisterReceiver(mTetherStateReceiver);
1435             mTrackingTetherStateChange = false;
1436         }
1437     }
1438 
1439     @Rpc(description = "Start listening for network suggestion change related broadcasts.")
wifiStartTrackingNetworkSuggestionStateChange()1440     public void wifiStartTrackingNetworkSuggestionStateChange() {
1441         mService.registerReceiver(
1442                 mNetworkSuggestionStateChangeReceiver, mNetworkSuggestionStateChangeFilter);
1443         mTrackingNetworkSuggestionStateChange = true;
1444     }
1445 
1446     @Rpc(description = "Stop listening for network suggestion change related broadcasts.")
wifiStopTrackingNetworkSuggestionStateChange()1447     public void wifiStopTrackingNetworkSuggestionStateChange() {
1448         if (mTrackingNetworkSuggestionStateChange) {
1449             mService.unregisterReceiver(mNetworkSuggestionStateChangeReceiver);
1450             mTrackingNetworkSuggestionStateChange = false;
1451         }
1452     }
1453 
1454     @Rpc(description = "Toggle Wifi on and off.", returns = "True if Wifi is enabled.")
wifiToggleState(@pcParametername = "enabled") @pcOptional Boolean enabled)1455     public Boolean wifiToggleState(@RpcParameter(name = "enabled") @RpcOptional Boolean enabled) {
1456         if (enabled == null) {
1457             enabled = !wifiCheckState();
1458         }
1459         mWifi.setWifiEnabled(enabled);
1460         return enabled;
1461     }
1462 
1463     @Rpc(description = "Toggle Wifi scan always available on and off.", returns = "True if Wifi scan is always available.")
wifiToggleScanAlwaysAvailable( @pcParametername = "enabled") @pcOptional Boolean enabled)1464     public Boolean wifiToggleScanAlwaysAvailable(
1465             @RpcParameter(name = "enabled") @RpcOptional Boolean enabled)
1466                     throws SettingNotFoundException {
1467         ContentResolver cr = mService.getContentResolver();
1468         int isSet = 0;
1469         if (enabled == null) {
1470             isSet = Global.getInt(cr, Global.WIFI_SCAN_ALWAYS_AVAILABLE);
1471             isSet ^= 1;
1472         } else if (enabled == true) {
1473             isSet = 1;
1474         }
1475         Global.putInt(cr, Global.WIFI_SCAN_ALWAYS_AVAILABLE, isSet);
1476         if (isSet == 1) {
1477             return true;
1478         }
1479         return false;
1480     }
1481 
1482     @Rpc(description = "Enable/disable WifiConnectivityManager.")
wifiEnableWifiConnectivityManager( @pcParametername = "enable") Boolean enable)1483     public void wifiEnableWifiConnectivityManager(
1484             @RpcParameter(name = "enable") Boolean enable) {
1485         mWifi.enableWifiConnectivityManager(enable);
1486     }
1487 
wifiRequestNetworkWithSpecifierInternal(NetworkSpecifier wns, int timeoutInMs)1488     private void wifiRequestNetworkWithSpecifierInternal(NetworkSpecifier wns, int timeoutInMs)
1489             throws GeneralSecurityException {
1490         NetworkRequest networkRequest = new NetworkRequest.Builder()
1491                 .addTransportType(TRANSPORT_WIFI)
1492                 .setNetworkSpecifier(wns)
1493                 .build();
1494         NetworkCallback networkCallback = new NetworkCallbackImpl();
1495         if (timeoutInMs != 0) {
1496             mCm.requestNetwork(networkRequest, networkCallback,
1497                     new Handler(mCallbackHandlerThread.getLooper()), timeoutInMs);
1498         } else {
1499             mCm.requestNetwork(networkRequest, networkCallback,
1500                     new Handler(mCallbackHandlerThread.getLooper()));
1501         }
1502         // Store the callback for release later.
1503         mNetworkCallbacks.put(wns, networkCallback);
1504     }
1505 
1506     /**
1507      * Initiates a network request {@link NetworkRequest} using {@link WifiNetworkSpecifier}.
1508      *
1509      * @param wifiNetworkSpecifier JSONObject Dictionary of wifi network specifier parameters
1510      * @throws JSONException
1511      * @throws GeneralSecurityException
1512      */
1513     @Rpc(description = "Initiates a network request using the provided network specifier")
wifiRequestNetworkWithSpecifier( @pcParametername = "wifiNetworkSpecifier") JSONObject wifiNetworkSpecifier)1514     public void wifiRequestNetworkWithSpecifier(
1515             @RpcParameter(name = "wifiNetworkSpecifier") JSONObject wifiNetworkSpecifier)
1516             throws JSONException, GeneralSecurityException {
1517         wifiRequestNetworkWithSpecifierInternal(genWifiNetworkSpecifier(wifiNetworkSpecifier), 0);
1518     }
1519 
1520     /**
1521      * Initiates a network request {@link NetworkRequest} using {@link WifiNetworkSpecifier}.
1522      *
1523      * @param wifiNetworkSpecifier JSONObject Dictionary of wifi network specifier parameters
1524      * @param timeoutInMs Timeout for the request.
1525      * @throws JSONException
1526      * @throws GeneralSecurityException
1527      */
1528     @Rpc(description = "Initiates a network request using the provided network specifier")
wifiRequestNetworkWithSpecifierWithTimeout( @pcParametername = "wifiNetworkSpecifier") JSONObject wifiNetworkSpecifier, @RpcParameter(name = "timeout") Integer timeoutInMs)1529     public void wifiRequestNetworkWithSpecifierWithTimeout(
1530             @RpcParameter(name = "wifiNetworkSpecifier") JSONObject wifiNetworkSpecifier,
1531             @RpcParameter(name = "timeout") Integer timeoutInMs)
1532             throws JSONException, GeneralSecurityException {
1533         wifiRequestNetworkWithSpecifierInternal(
1534                 genWifiNetworkSpecifier(wifiNetworkSpecifier), timeoutInMs);
1535     }
1536 
1537     /**
1538      * Releases network request using {@link WifiNetworkSpecifier}.
1539      *
1540      * @throws JSONException
1541      * @throws GeneralSecurityException
1542      */
1543     @Rpc(description = "Releases network request corresponding to the network specifier")
wifiReleaseNetwork( @pcParametername = "wifiNetworkSpecifier") JSONObject wifiNetworkSpecifier)1544     public void wifiReleaseNetwork(
1545             @RpcParameter(name = "wifiNetworkSpecifier") JSONObject wifiNetworkSpecifier)
1546             throws JSONException, GeneralSecurityException {
1547         NetworkSpecifier wns = genWifiNetworkSpecifier(wifiNetworkSpecifier);
1548         NetworkCallback networkCallback = mNetworkCallbacks.remove(wns);
1549         if (networkCallback == null) {
1550             throw new IllegalArgumentException("network callback is null");
1551         }
1552         mCm.unregisterNetworkCallback(networkCallback);
1553     }
1554 
1555     /**
1556      * Releases all pending network requests.
1557      *
1558      * @throws JSONException
1559      * @throws GeneralSecurityException
1560      */
1561     @Rpc(description = "Releases all pending network requests")
wifiReleaseNetworkAll()1562     public void wifiReleaseNetworkAll() {
1563         Iterator<Map.Entry<NetworkSpecifier, NetworkCallback>> it =
1564                 mNetworkCallbacks.entrySet().iterator();
1565         while (it.hasNext()) {
1566             Map.Entry<NetworkSpecifier, NetworkCallback> entry = it.next();
1567             NetworkCallback networkCallback = entry.getValue();
1568             it.remove();
1569             mCm.unregisterNetworkCallback(networkCallback);
1570         }
1571     }
1572 
1573     /**
1574      * Register network request match callback to simulate the UI flow.
1575      *
1576      * @throws JSONException
1577      * @throws GeneralSecurityException
1578      */
1579     @Rpc(description = "Register network request match callback")
wifiRegisterNetworkRequestMatchCallback()1580     public void wifiRegisterNetworkRequestMatchCallback()
1581             throws JSONException, GeneralSecurityException {
1582         // Listen for UI interaction callbacks
1583         mWifi.registerNetworkRequestMatchCallback(
1584                 mNetworkRequestMatchCallback, new Handler(mCallbackHandlerThread.getLooper()));
1585     }
1586 
1587     /**
1588      * Triggers connect to a specific wifi network.
1589      *
1590      * @param jsonConfig JSONObject Dictionary of wifi connection parameters
1591      * @throws JSONException
1592      * @throws GeneralSecurityException
1593      */
1594     @Rpc(description = "Connects to the specified network for the ongoing network request")
wifiSendUserSelectionForNetworkRequestMatch( @pcParametername = "jsonConfig") JSONObject jsonConfig)1595     public void wifiSendUserSelectionForNetworkRequestMatch(
1596             @RpcParameter(name = "jsonConfig") JSONObject jsonConfig)
1597             throws JSONException, GeneralSecurityException {
1598         synchronized (mCallbackLock) {
1599             if (mNetworkRequestUserSelectionCallback == null) {
1600                 throw new IllegalStateException("user callback is null");
1601             }
1602             // Copy the SSID for user selection.
1603             WifiConfiguration config = new WifiConfiguration();
1604             if (jsonConfig.has("SSID")) {
1605                 config.SSID = "\"" + jsonConfig.getString("SSID") + "\"";
1606             }
1607             mNetworkRequestUserSelectionCallback.select(config);
1608         }
1609     }
1610 
1611     /**
1612      * Rejects network request.
1613      *
1614      * @throws JSONException
1615      * @throws GeneralSecurityException
1616      */
1617     @Rpc(description = "Rejects ongoing network request")
wifiSendUserRejectionForNetworkRequestMatch()1618     public void wifiSendUserRejectionForNetworkRequestMatch()
1619             throws JSONException, GeneralSecurityException {
1620         synchronized (mCallbackLock) {
1621             if (mNetworkRequestUserSelectionCallback == null) {
1622                 throw new IllegalStateException("user callback is null");
1623             }
1624             mNetworkRequestUserSelectionCallback.reject();
1625         }
1626     }
1627 
1628     /**
1629      * Add network suggestions.
1630 
1631      * @param wifiNetworkSuggestions Array of JSONObject Dictionary of wifi network suggestion
1632      *                               parameters
1633      * @throws JSONException
1634      * @throws GeneralSecurityException
1635      */
1636     @Rpc(description = "Add network suggestions to the platform")
wifiAddNetworkSuggestions( @pcParametername = "wifiNetworkSuggestions") JSONArray wifiNetworkSuggestions)1637     public boolean wifiAddNetworkSuggestions(
1638             @RpcParameter(name = "wifiNetworkSuggestions") JSONArray wifiNetworkSuggestions)
1639             throws JSONException, GeneralSecurityException {
1640         return mWifi.addNetworkSuggestions(genWifiNetworkSuggestions(wifiNetworkSuggestions))
1641                 == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS;
1642     }
1643 
1644     /**
1645      * Remove network suggestions.
1646 
1647      * @param wifiNetworkSuggestions Array of JSONObject Dictionary of wifi network suggestion
1648      *                               parameters
1649      * @throws JSONException
1650      * @throws GeneralSecurityException
1651      */
1652     @Rpc(description = "Remove network suggestions from the platform")
wifiRemoveNetworkSuggestions( @pcParametername = "wifiNetworkSuggestions") JSONArray wifiNetworkSuggestions)1653     public boolean wifiRemoveNetworkSuggestions(
1654             @RpcParameter(name = "wifiNetworkSuggestions") JSONArray wifiNetworkSuggestions)
1655             throws JSONException, GeneralSecurityException {
1656         return mWifi.removeNetworkSuggestions(genWifiNetworkSuggestions(wifiNetworkSuggestions))
1657                 == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS;
1658     }
1659 
1660     @Override
shutdown()1661     public void shutdown() {
1662         wifiReleaseNetworkAll();
1663         wifiLockRelease();
1664         if (mTrackingWifiStateChange == true) {
1665             wifiStopTrackingStateChange();
1666         }
1667         if (mTrackingTetherStateChange == true) {
1668             wifiStopTrackingTetherStateChange();
1669         }
1670     }
1671 
1672     private class EasyConnectCallback extends EasyConnectStatusCallback {
1673         private static final String EASY_CONNECT_CALLBACK_TAG = "onDppCallback";
1674 
1675         @Override
onEnrolleeSuccess(int newWifiConfigurationId)1676         public void onEnrolleeSuccess(int newWifiConfigurationId) {
1677             Bundle msg = new Bundle();
1678             msg.putString("Type", "onEnrolleeSuccess");
1679             msg.putInt("NetworkId", newWifiConfigurationId);
1680             Log.d("Posting event: onEnrolleeSuccess");
1681             mEventFacade.postEvent(EASY_CONNECT_CALLBACK_TAG, msg);
1682         }
1683 
1684         @Override
onConfiguratorSuccess(int code)1685         public void onConfiguratorSuccess(int code) {
1686             Bundle msg = new Bundle();
1687             msg.putString("Type", "onConfiguratorSuccess");
1688             msg.putInt("Status", code);
1689             Log.d("Posting event: onConfiguratorSuccess");
1690             mEventFacade.postEvent(EASY_CONNECT_CALLBACK_TAG, msg);
1691         }
1692 
1693         @Override
onFailure(int code)1694         public void onFailure(int code) {
1695             Bundle msg = new Bundle();
1696             msg.putString("Type", "onFailure");
1697             msg.putInt("Status", code);
1698             Log.d("Posting event: onFailure");
1699             mEventFacade.postEvent(EASY_CONNECT_CALLBACK_TAG, msg);
1700         }
1701 
1702         @Override
onProgress(int code)1703         public void onProgress(int code) {
1704             Bundle msg = new Bundle();
1705             msg.putString("Type", "onProgress");
1706             msg.putInt("Status", code);
1707             Log.d("Posting event: onProgress");
1708             mEventFacade.postEvent(EASY_CONNECT_CALLBACK_TAG, msg);
1709         }
1710     }
1711 
1712     /**
1713      * Start Easy Connect (DPP) in Initiator-Configurator role: Send Wi-Fi configuration to a peer
1714      *
1715      * @param enrolleeUri Peer URI
1716      * @param selectedNetworkId Wi-Fi configuration ID
1717      */
1718     @Rpc(description = "Easy Connect Initiator-Configurator: Send Wi-Fi configuration to peer")
startEasyConnectAsConfiguratorInitiator(@pcParametername = "enrolleeUri") String enrolleeUri, @RpcParameter(name = "selectedNetworkId") Integer selectedNetworkId, @RpcParameter(name = "netRole") String netRole)1719     public void startEasyConnectAsConfiguratorInitiator(@RpcParameter(name = "enrolleeUri") String
1720             enrolleeUri, @RpcParameter(name = "selectedNetworkId") Integer selectedNetworkId,
1721             @RpcParameter(name = "netRole") String netRole)
1722             throws JSONException {
1723         EasyConnectCallback dppStatusCallback = new EasyConnectCallback();
1724         int netRoleInternal;
1725 
1726         if (netRole.equals("ap")) {
1727             netRoleInternal = WifiManager.EASY_CONNECT_NETWORK_ROLE_AP;
1728         } else {
1729             netRoleInternal = WifiManager.EASY_CONNECT_NETWORK_ROLE_STA;
1730         }
1731 
1732         // Start Easy Connect
1733         mWifi.startEasyConnectAsConfiguratorInitiator(enrolleeUri, selectedNetworkId,
1734                 netRoleInternal, mService.getMainExecutor(), dppStatusCallback);
1735     }
1736 
1737     /**
1738      * Start Easy Connect (DPP) in Initiator-Enrollee role: Receive Wi-Fi configuration from a peer
1739      *
1740      * @param configuratorUri
1741      */
1742     @Rpc(description = "Easy Connect Initiator-Enrollee: Receive Wi-Fi configuration from peer")
startEasyConnectAsEnrolleeInitiator(@pcParametername = "configuratorUri") String configuratorUri)1743     public void startEasyConnectAsEnrolleeInitiator(@RpcParameter(name = "configuratorUri") String
1744             configuratorUri) {
1745         EasyConnectCallback dppStatusCallback = new EasyConnectCallback();
1746 
1747         // Start Easy Connect
1748         mWifi.startEasyConnectAsEnrolleeInitiator(configuratorUri, mService.getMainExecutor(),
1749                 dppStatusCallback);
1750     }
1751 
1752     /**
1753      * Stop Easy Connect (DPP) session
1754      *
1755      */
1756     @Rpc(description = "Stop Easy Connect session")
stopEasyConnectSession()1757     public void stopEasyConnectSession() {
1758         // Stop Easy Connect
1759         mWifi.stopEasyConnectSession();
1760     }
1761 }
1762