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