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