1 /* 2 * Copyright (C) 2008 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 android.net.wifi; 18 19 import android.annotation.SdkConstant; 20 import android.annotation.SdkConstant.SdkConstantType; 21 import android.content.Context; 22 import android.net.DhcpInfo; 23 import android.os.Binder; 24 import android.os.IBinder; 25 import android.os.Handler; 26 import android.os.HandlerThread; 27 import android.os.Looper; 28 import android.os.Message; 29 import android.os.RemoteException; 30 import android.os.WorkSource; 31 import android.os.Messenger; 32 import android.util.Log; 33 import android.util.SparseArray; 34 35 import java.util.concurrent.CountDownLatch; 36 37 import com.android.internal.util.AsyncChannel; 38 import com.android.internal.util.Protocol; 39 40 import java.util.List; 41 42 /** 43 * This class provides the primary API for managing all aspects of Wi-Fi 44 * connectivity. Get an instance of this class by calling 45 * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}. 46 47 * It deals with several categories of items: 48 * <ul> 49 * <li>The list of configured networks. The list can be viewed and updated, 50 * and attributes of individual entries can be modified.</li> 51 * <li>The currently active Wi-Fi network, if any. Connectivity can be 52 * established or torn down, and dynamic information about the state of 53 * the network can be queried.</li> 54 * <li>Results of access point scans, containing enough information to 55 * make decisions about what access point to connect to.</li> 56 * <li>It defines the names of various Intent actions that are broadcast 57 * upon any sort of change in Wi-Fi state. 58 * </ul> 59 * This is the API to use when performing Wi-Fi specific operations. To 60 * perform operations that pertain to network connectivity at an abstract 61 * level, use {@link android.net.ConnectivityManager}. 62 */ 63 public class WifiManager { 64 65 private static final String TAG = "WifiManager"; 66 // Supplicant error codes: 67 /** 68 * The error code if there was a problem authenticating. 69 */ 70 public static final int ERROR_AUTHENTICATING = 1; 71 72 /** 73 * Broadcast intent action indicating whether Wi-Fi scanning is allowed currently 74 * @hide 75 */ 76 public static final String WIFI_SCAN_AVAILABLE = "wifi_scan_available"; 77 78 /** 79 * Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED 80 * @hide 81 */ 82 public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled"; 83 84 /** 85 * Broadcast intent action indicating that Wi-Fi has been enabled, disabled, 86 * enabling, disabling, or unknown. One extra provides this state as an int. 87 * Another extra provides the previous state, if available. 88 * 89 * @see #EXTRA_WIFI_STATE 90 * @see #EXTRA_PREVIOUS_WIFI_STATE 91 */ 92 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 93 public static final String WIFI_STATE_CHANGED_ACTION = 94 "android.net.wifi.WIFI_STATE_CHANGED"; 95 /** 96 * The lookup key for an int that indicates whether Wi-Fi is enabled, 97 * disabled, enabling, disabling, or unknown. Retrieve it with 98 * {@link android.content.Intent#getIntExtra(String,int)}. 99 * 100 * @see #WIFI_STATE_DISABLED 101 * @see #WIFI_STATE_DISABLING 102 * @see #WIFI_STATE_ENABLED 103 * @see #WIFI_STATE_ENABLING 104 * @see #WIFI_STATE_UNKNOWN 105 */ 106 public static final String EXTRA_WIFI_STATE = "wifi_state"; 107 /** 108 * The previous Wi-Fi state. 109 * 110 * @see #EXTRA_WIFI_STATE 111 */ 112 public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state"; 113 114 /** 115 * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if 116 * it finishes successfully. 117 * 118 * @see #WIFI_STATE_CHANGED_ACTION 119 * @see #getWifiState() 120 */ 121 public static final int WIFI_STATE_DISABLING = 0; 122 /** 123 * Wi-Fi is disabled. 124 * 125 * @see #WIFI_STATE_CHANGED_ACTION 126 * @see #getWifiState() 127 */ 128 public static final int WIFI_STATE_DISABLED = 1; 129 /** 130 * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if 131 * it finishes successfully. 132 * 133 * @see #WIFI_STATE_CHANGED_ACTION 134 * @see #getWifiState() 135 */ 136 public static final int WIFI_STATE_ENABLING = 2; 137 /** 138 * Wi-Fi is enabled. 139 * 140 * @see #WIFI_STATE_CHANGED_ACTION 141 * @see #getWifiState() 142 */ 143 public static final int WIFI_STATE_ENABLED = 3; 144 /** 145 * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling 146 * or disabling. 147 * 148 * @see #WIFI_STATE_CHANGED_ACTION 149 * @see #getWifiState() 150 */ 151 public static final int WIFI_STATE_UNKNOWN = 4; 152 153 /** 154 * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled, 155 * enabling, disabling, or failed. 156 * 157 * @hide 158 */ 159 public static final String WIFI_AP_STATE_CHANGED_ACTION = 160 "android.net.wifi.WIFI_AP_STATE_CHANGED"; 161 162 /** 163 * The lookup key for an int that indicates whether Wi-Fi AP is enabled, 164 * disabled, enabling, disabling, or failed. Retrieve it with 165 * {@link android.content.Intent#getIntExtra(String,int)}. 166 * 167 * @see #WIFI_AP_STATE_DISABLED 168 * @see #WIFI_AP_STATE_DISABLING 169 * @see #WIFI_AP_STATE_ENABLED 170 * @see #WIFI_AP_STATE_ENABLING 171 * @see #WIFI_AP_STATE_FAILED 172 * 173 * @hide 174 */ 175 public static final String EXTRA_WIFI_AP_STATE = "wifi_state"; 176 /** 177 * The previous Wi-Fi state. 178 * 179 * @see #EXTRA_WIFI_AP_STATE 180 * 181 * @hide 182 */ 183 public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state"; 184 /** 185 * Wi-Fi AP is currently being disabled. The state will change to 186 * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully. 187 * 188 * @see #WIFI_AP_STATE_CHANGED_ACTION 189 * @see #getWifiApState() 190 * 191 * @hide 192 */ 193 public static final int WIFI_AP_STATE_DISABLING = 10; 194 /** 195 * Wi-Fi AP is disabled. 196 * 197 * @see #WIFI_AP_STATE_CHANGED_ACTION 198 * @see #getWifiState() 199 * 200 * @hide 201 */ 202 public static final int WIFI_AP_STATE_DISABLED = 11; 203 /** 204 * Wi-Fi AP is currently being enabled. The state will change to 205 * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully. 206 * 207 * @see #WIFI_AP_STATE_CHANGED_ACTION 208 * @see #getWifiApState() 209 * 210 * @hide 211 */ 212 public static final int WIFI_AP_STATE_ENABLING = 12; 213 /** 214 * Wi-Fi AP is enabled. 215 * 216 * @see #WIFI_AP_STATE_CHANGED_ACTION 217 * @see #getWifiApState() 218 * 219 * @hide 220 */ 221 public static final int WIFI_AP_STATE_ENABLED = 13; 222 /** 223 * Wi-Fi AP is in a failed state. This state will occur when an error occurs during 224 * enabling or disabling 225 * 226 * @see #WIFI_AP_STATE_CHANGED_ACTION 227 * @see #getWifiApState() 228 * 229 * @hide 230 */ 231 public static final int WIFI_AP_STATE_FAILED = 14; 232 233 /** 234 * Broadcast intent action indicating that a connection to the supplicant has 235 * been established (and it is now possible 236 * to perform Wi-Fi operations) or the connection to the supplicant has been 237 * lost. One extra provides the connection state as a boolean, where {@code true} 238 * means CONNECTED. 239 * @see #EXTRA_SUPPLICANT_CONNECTED 240 */ 241 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 242 public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION = 243 "android.net.wifi.supplicant.CONNECTION_CHANGE"; 244 /** 245 * The lookup key for a boolean that indicates whether a connection to 246 * the supplicant daemon has been gained or lost. {@code true} means 247 * a connection now exists. 248 * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. 249 */ 250 public static final String EXTRA_SUPPLICANT_CONNECTED = "connected"; 251 /** 252 * Broadcast intent action indicating that the state of Wi-Fi connectivity 253 * has changed. One extra provides the new state 254 * in the form of a {@link android.net.NetworkInfo} object. If the new 255 * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of 256 * the access point. 257 * as a {@code String}. 258 * @see #EXTRA_NETWORK_INFO 259 * @see #EXTRA_BSSID 260 * @see #EXTRA_WIFI_INFO 261 */ 262 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 263 public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"; 264 /** 265 * The lookup key for a {@link android.net.NetworkInfo} object associated with the 266 * Wi-Fi network. Retrieve with 267 * {@link android.content.Intent#getParcelableExtra(String)}. 268 */ 269 public static final String EXTRA_NETWORK_INFO = "networkInfo"; 270 /** 271 * The lookup key for a String giving the BSSID of the access point to which 272 * we are connected. Only present when the new state is CONNECTED. 273 * Retrieve with 274 * {@link android.content.Intent#getStringExtra(String)}. 275 */ 276 public static final String EXTRA_BSSID = "bssid"; 277 /** 278 * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the 279 * information about the access point to which we are connected. Only present 280 * when the new state is CONNECTED. Retrieve with 281 * {@link android.content.Intent#getParcelableExtra(String)}. 282 */ 283 public static final String EXTRA_WIFI_INFO = "wifiInfo"; 284 /** 285 * Broadcast intent action indicating that the state of establishing a connection to 286 * an access point has changed.One extra provides the new 287 * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and 288 * is not generally the most useful thing to look at if you are just interested in 289 * the overall state of connectivity. 290 * @see #EXTRA_NEW_STATE 291 * @see #EXTRA_SUPPLICANT_ERROR 292 */ 293 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 294 public static final String SUPPLICANT_STATE_CHANGED_ACTION = 295 "android.net.wifi.supplicant.STATE_CHANGE"; 296 /** 297 * The lookup key for a {@link SupplicantState} describing the new state 298 * Retrieve with 299 * {@link android.content.Intent#getParcelableExtra(String)}. 300 */ 301 public static final String EXTRA_NEW_STATE = "newState"; 302 303 /** 304 * The lookup key for a {@link SupplicantState} describing the supplicant 305 * error code if any 306 * Retrieve with 307 * {@link android.content.Intent#getIntExtra(String, int)}. 308 * @see #ERROR_AUTHENTICATING 309 */ 310 public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError"; 311 312 /** 313 * Broadcast intent action indicating that the configured networks changed. 314 * This can be as a result of adding/updating/deleting a network. If 315 * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set to true the new configuration 316 * can be retreived with the {@link #EXTRA_WIFI_CONFIGURATION} extra. If multiple 317 * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present. 318 * @hide 319 */ 320 public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = 321 "android.net.wifi.CONFIGURED_NETWORKS_CHANGE"; 322 /** 323 * The lookup key for a (@link android.net.wifi.WifiConfiguration} object representing 324 * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION} 325 * broadcast is sent. 326 * @hide 327 */ 328 public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration"; 329 /** 330 * Multiple network configurations have changed. 331 * @see #CONFIGURED_NETWORKS_CHANGED_ACTION 332 * 333 * @hide 334 */ 335 public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges"; 336 /** 337 * The lookup key for an integer indicating the reason a Wi-Fi network configuration 338 * has changed. Only present if {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is {@code false} 339 * @see #CONFIGURED_NETWORKS_CHANGED_ACTION 340 * @hide 341 */ 342 public static final String EXTRA_CHANGE_REASON = "changeReason"; 343 /** 344 * The configuration is new and was added. 345 * @hide 346 */ 347 public static final int CHANGE_REASON_ADDED = 0; 348 /** 349 * The configuration was removed and is no longer present in the system's list of 350 * configured networks. 351 * @hide 352 */ 353 public static final int CHANGE_REASON_REMOVED = 1; 354 /** 355 * The configuration has changed as a result of explicit action or because the system 356 * took an automated action such as disabling a malfunctioning configuration. 357 * @hide 358 */ 359 public static final int CHANGE_REASON_CONFIG_CHANGE = 2; 360 /** 361 * An access point scan has completed, and results are available from the supplicant. 362 * Call {@link #getScanResults()} to obtain the results. 363 */ 364 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 365 public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS"; 366 /** 367 * The RSSI (signal strength) has changed. 368 * @see #EXTRA_NEW_RSSI 369 */ 370 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 371 public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED"; 372 /** 373 * The lookup key for an {@code int} giving the new RSSI in dBm. 374 */ 375 public static final String EXTRA_NEW_RSSI = "newRssi"; 376 377 /** 378 * Broadcast intent action indicating that the link configuration 379 * changed on wifi. 380 * @hide 381 */ 382 public static final String LINK_CONFIGURATION_CHANGED_ACTION = 383 "android.net.wifi.LINK_CONFIGURATION_CHANGED"; 384 385 /** 386 * The lookup key for a {@link android.net.LinkProperties} object associated with the 387 * Wi-Fi network. Retrieve with 388 * {@link android.content.Intent#getParcelableExtra(String)}. 389 * @hide 390 */ 391 public static final String EXTRA_LINK_PROPERTIES = "linkProperties"; 392 393 /** 394 * The lookup key for a {@link android.net.LinkCapabilities} object associated with the 395 * Wi-Fi network. Retrieve with 396 * {@link android.content.Intent#getParcelableExtra(String)}. 397 * @hide 398 */ 399 public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities"; 400 401 /** 402 * The network IDs of the configured networks could have changed. 403 */ 404 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 405 public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED"; 406 407 /** 408 * Activity Action: Show a system activity that allows the user to enable 409 * scans to be available even with Wi-Fi turned off. 410 * 411 * <p>Notification of the result of this activity is posted using the 412 * {@link android.app.Activity#onActivityResult} callback. The 413 * <code>resultCode</code> 414 * will be {@link android.app.Activity#RESULT_OK} if scan always mode has 415 * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user 416 * has rejected the request or an error has occurred. 417 */ 418 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 419 public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = 420 "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE"; 421 422 /** 423 * Activity Action: Pick a Wi-Fi network to connect to. 424 * <p>Input: Nothing. 425 * <p>Output: Nothing. 426 */ 427 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 428 public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; 429 430 /** 431 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 432 * and will behave normally, i.e., it will attempt to automatically 433 * establish a connection to a remembered access point that is 434 * within range, and will do periodic scans if there are remembered 435 * access points but none are in range. 436 */ 437 public static final int WIFI_MODE_FULL = 1; 438 /** 439 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 440 * but the only operation that will be supported is initiation of 441 * scans, and the subsequent reporting of scan results. No attempts 442 * will be made to automatically connect to remembered access points, 443 * nor will periodic scans be automatically performed looking for 444 * remembered access points. Scans must be explicitly requested by 445 * an application in this mode. 446 */ 447 public static final int WIFI_MODE_SCAN_ONLY = 2; 448 /** 449 * In this Wi-Fi lock mode, Wi-Fi will be kept active as in mode 450 * {@link #WIFI_MODE_FULL} but it operates at high performance 451 * with minimum packet loss and low packet latency even when 452 * the device screen is off. This mode will consume more power 453 * and hence should be used only when there is a need for such 454 * an active connection. 455 * <p> 456 * An example use case is when a voice connection needs to be 457 * kept active even after the device screen goes off. Holding the 458 * regular {@link #WIFI_MODE_FULL} lock will keep the wifi 459 * connection active, but the connection can be lossy. 460 * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the 461 * duration of the voice call will improve the call quality. 462 * <p> 463 * When there is no support from the hardware, this lock mode 464 * will have the same behavior as {@link #WIFI_MODE_FULL} 465 */ 466 public static final int WIFI_MODE_FULL_HIGH_PERF = 3; 467 468 /** Anything worse than or equal to this will show 0 bars. */ 469 private static final int MIN_RSSI = -100; 470 471 /** Anything better than or equal to this will show the max bars. */ 472 private static final int MAX_RSSI = -55; 473 474 /** 475 * Number of RSSI levels used in the framework to initiate 476 * {@link #RSSI_CHANGED_ACTION} broadcast 477 * @hide 478 */ 479 public static final int RSSI_LEVELS = 5; 480 481 /** 482 * Auto settings in the driver. The driver could choose to operate on both 483 * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band. 484 * @hide 485 */ 486 public static final int WIFI_FREQUENCY_BAND_AUTO = 0; 487 488 /** 489 * Operation on 5 GHz alone 490 * @hide 491 */ 492 public static final int WIFI_FREQUENCY_BAND_5GHZ = 1; 493 494 /** 495 * Operation on 2.4 GHz alone 496 * @hide 497 */ 498 public static final int WIFI_FREQUENCY_BAND_2GHZ = 2; 499 500 /** List of asyncronous notifications 501 * @hide 502 */ 503 public static final int DATA_ACTIVITY_NOTIFICATION = 1; 504 505 //Lowest bit indicates data reception and the second lowest 506 //bit indicates data transmitted 507 /** @hide */ 508 public static final int DATA_ACTIVITY_NONE = 0x00; 509 /** @hide */ 510 public static final int DATA_ACTIVITY_IN = 0x01; 511 /** @hide */ 512 public static final int DATA_ACTIVITY_OUT = 0x02; 513 /** @hide */ 514 public static final int DATA_ACTIVITY_INOUT = 0x03; 515 516 /* Maximum number of active locks we allow. 517 * This limit was added to prevent apps from creating a ridiculous number 518 * of locks and crashing the system by overflowing the global ref table. 519 */ 520 private static final int MAX_ACTIVE_LOCKS = 50; 521 522 /* Number of currently active WifiLocks and MulticastLocks */ 523 private int mActiveLockCount; 524 525 private Context mContext; 526 IWifiManager mService; 527 528 private static final int INVALID_KEY = 0; 529 private static int sListenerKey = 1; 530 private static final SparseArray sListenerMap = new SparseArray(); 531 private static final Object sListenerMapLock = new Object(); 532 533 private static AsyncChannel sAsyncChannel; 534 private static CountDownLatch sConnected; 535 536 private static final Object sThreadRefLock = new Object(); 537 private static int sThreadRefCount; 538 private static HandlerThread sHandlerThread; 539 540 /** 541 * Create a new WifiManager instance. 542 * Applications will almost always want to use 543 * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve 544 * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. 545 * @param context the application context 546 * @param service the Binder interface 547 * @hide - hide this because it takes in a parameter of type IWifiManager, which 548 * is a system private class. 549 */ 550 public WifiManager(Context context, IWifiManager service) { 551 mContext = context; 552 mService = service; 553 init(); 554 } 555 556 /** 557 * Return a list of all the networks configured in the supplicant. 558 * Not all fields of WifiConfiguration are returned. Only the following 559 * fields are filled in: 560 * <ul> 561 * <li>networkId</li> 562 * <li>SSID</li> 563 * <li>BSSID</li> 564 * <li>priority</li> 565 * <li>allowedProtocols</li> 566 * <li>allowedKeyManagement</li> 567 * <li>allowedAuthAlgorithms</li> 568 * <li>allowedPairwiseCiphers</li> 569 * <li>allowedGroupCiphers</li> 570 * </ul> 571 * @return a list of network configurations in the form of a list 572 * of {@link WifiConfiguration} objects. Upon failure to fetch or 573 * when when Wi-Fi is turned off, it can be null. 574 */ 575 public List<WifiConfiguration> getConfiguredNetworks() { 576 try { 577 return mService.getConfiguredNetworks(); 578 } catch (RemoteException e) { 579 return null; 580 } 581 } 582 583 /** 584 * Add a new network description to the set of configured networks. 585 * The {@code networkId} field of the supplied configuration object 586 * is ignored. 587 * <p/> 588 * The new network will be marked DISABLED by default. To enable it, 589 * called {@link #enableNetwork}. 590 * 591 * @param config the set of variables that describe the configuration, 592 * contained in a {@link WifiConfiguration} object. 593 * @return the ID of the newly created network description. This is used in 594 * other operations to specified the network to be acted upon. 595 * Returns {@code -1} on failure. 596 */ 597 public int addNetwork(WifiConfiguration config) { 598 if (config == null) { 599 return -1; 600 } 601 config.networkId = -1; 602 return addOrUpdateNetwork(config); 603 } 604 605 /** 606 * Update the network description of an existing configured network. 607 * 608 * @param config the set of variables that describe the configuration, 609 * contained in a {@link WifiConfiguration} object. It may 610 * be sparse, so that only the items that are being changed 611 * are non-<code>null</code>. The {@code networkId} field 612 * must be set to the ID of the existing network being updated. 613 * @return Returns the {@code networkId} of the supplied 614 * {@code WifiConfiguration} on success. 615 * <br/> 616 * Returns {@code -1} on failure, including when the {@code networkId} 617 * field of the {@code WifiConfiguration} does not refer to an 618 * existing network. 619 */ 620 public int updateNetwork(WifiConfiguration config) { 621 if (config == null || config.networkId < 0) { 622 return -1; 623 } 624 return addOrUpdateNetwork(config); 625 } 626 627 /** 628 * Internal method for doing the RPC that creates a new network description 629 * or updates an existing one. 630 * 631 * @param config The possibly sparse object containing the variables that 632 * are to set or updated in the network description. 633 * @return the ID of the network on success, {@code -1} on failure. 634 */ 635 private int addOrUpdateNetwork(WifiConfiguration config) { 636 try { 637 return mService.addOrUpdateNetwork(config); 638 } catch (RemoteException e) { 639 return -1; 640 } 641 } 642 643 /** 644 * Remove the specified network from the list of configured networks. 645 * This may result in the asynchronous delivery of state change 646 * events. 647 * @param netId the integer that identifies the network configuration 648 * to the supplicant 649 * @return {@code true} if the operation succeeded 650 */ 651 public boolean removeNetwork(int netId) { 652 try { 653 return mService.removeNetwork(netId); 654 } catch (RemoteException e) { 655 return false; 656 } 657 } 658 659 /** 660 * Allow a previously configured network to be associated with. If 661 * <code>disableOthers</code> is true, then all other configured 662 * networks are disabled, and an attempt to connect to the selected 663 * network is initiated. This may result in the asynchronous delivery 664 * of state change events. 665 * @param netId the ID of the network in the list of configured networks 666 * @param disableOthers if true, disable all other networks. The way to 667 * select a particular network to connect to is specify {@code true} 668 * for this parameter. 669 * @return {@code true} if the operation succeeded 670 */ 671 public boolean enableNetwork(int netId, boolean disableOthers) { 672 try { 673 return mService.enableNetwork(netId, disableOthers); 674 } catch (RemoteException e) { 675 return false; 676 } 677 } 678 679 /** 680 * Disable a configured network. The specified network will not be 681 * a candidate for associating. This may result in the asynchronous 682 * delivery of state change events. 683 * @param netId the ID of the network as returned by {@link #addNetwork}. 684 * @return {@code true} if the operation succeeded 685 */ 686 public boolean disableNetwork(int netId) { 687 try { 688 return mService.disableNetwork(netId); 689 } catch (RemoteException e) { 690 return false; 691 } 692 } 693 694 /** 695 * Disassociate from the currently active access point. This may result 696 * in the asynchronous delivery of state change events. 697 * @return {@code true} if the operation succeeded 698 */ 699 public boolean disconnect() { 700 try { 701 mService.disconnect(); 702 return true; 703 } catch (RemoteException e) { 704 return false; 705 } 706 } 707 708 /** 709 * Reconnect to the currently active access point, if we are currently 710 * disconnected. This may result in the asynchronous delivery of state 711 * change events. 712 * @return {@code true} if the operation succeeded 713 */ 714 public boolean reconnect() { 715 try { 716 mService.reconnect(); 717 return true; 718 } catch (RemoteException e) { 719 return false; 720 } 721 } 722 723 /** 724 * Reconnect to the currently active access point, even if we are already 725 * connected. This may result in the asynchronous delivery of state 726 * change events. 727 * @return {@code true} if the operation succeeded 728 */ 729 public boolean reassociate() { 730 try { 731 mService.reassociate(); 732 return true; 733 } catch (RemoteException e) { 734 return false; 735 } 736 } 737 738 /** 739 * Check that the supplicant daemon is responding to requests. 740 * @return {@code true} if we were able to communicate with the supplicant and 741 * it returned the expected response to the PING message. 742 */ 743 public boolean pingSupplicant() { 744 if (mService == null) 745 return false; 746 try { 747 return mService.pingSupplicant(); 748 } catch (RemoteException e) { 749 return false; 750 } 751 } 752 753 /** 754 * Request a scan for access points. Returns immediately. The availability 755 * of the results is made known later by means of an asynchronous event sent 756 * on completion of the scan. 757 * @return {@code true} if the operation succeeded, i.e., the scan was initiated 758 */ 759 public boolean startScan() { 760 try { 761 mService.startScan(); 762 return true; 763 } catch (RemoteException e) { 764 return false; 765 } 766 } 767 768 /** 769 * Return dynamic information about the current Wi-Fi connection, if any is active. 770 * @return the Wi-Fi information, contained in {@link WifiInfo}. 771 */ 772 public WifiInfo getConnectionInfo() { 773 try { 774 return mService.getConnectionInfo(); 775 } catch (RemoteException e) { 776 return null; 777 } 778 } 779 780 /** 781 * Return the results of the latest access point scan. 782 * @return the list of access points found in the most recent scan. 783 */ 784 public List<ScanResult> getScanResults() { 785 try { 786 return mService.getScanResults(mContext.getBasePackageName()); 787 } catch (RemoteException e) { 788 return null; 789 } 790 } 791 792 /** 793 * Check if scanning is always available. 794 * 795 * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results 796 * even when Wi-Fi is turned off. 797 * 798 * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}. 799 */ 800 public boolean isScanAlwaysAvailable() { 801 try { 802 return mService.isScanAlwaysAvailable(); 803 } catch (RemoteException e) { 804 return false; 805 } 806 } 807 808 /** 809 * Tell the supplicant to persist the current list of configured networks. 810 * <p> 811 * Note: It is possible for this method to change the network IDs of 812 * existing networks. You should assume the network IDs can be different 813 * after calling this method. 814 * 815 * @return {@code true} if the operation succeeded 816 */ 817 public boolean saveConfiguration() { 818 try { 819 return mService.saveConfiguration(); 820 } catch (RemoteException e) { 821 return false; 822 } 823 } 824 825 /** 826 * Set the country code. 827 * @param countryCode country code in ISO 3166 format. 828 * @param persist {@code true} if this needs to be remembered 829 * 830 * @hide 831 */ 832 public void setCountryCode(String country, boolean persist) { 833 try { 834 mService.setCountryCode(country, persist); 835 } catch (RemoteException e) { } 836 } 837 838 /** 839 * Set the operational frequency band. 840 * @param band One of 841 * {@link #WIFI_FREQUENCY_BAND_AUTO}, 842 * {@link #WIFI_FREQUENCY_BAND_5GHZ}, 843 * {@link #WIFI_FREQUENCY_BAND_2GHZ}, 844 * @param persist {@code true} if this needs to be remembered 845 * @hide 846 */ 847 public void setFrequencyBand(int band, boolean persist) { 848 try { 849 mService.setFrequencyBand(band, persist); 850 } catch (RemoteException e) { } 851 } 852 853 /** 854 * Get the operational frequency band. 855 * @return One of 856 * {@link #WIFI_FREQUENCY_BAND_AUTO}, 857 * {@link #WIFI_FREQUENCY_BAND_5GHZ}, 858 * {@link #WIFI_FREQUENCY_BAND_2GHZ} or 859 * {@code -1} on failure. 860 * @hide 861 */ 862 public int getFrequencyBand() { 863 try { 864 return mService.getFrequencyBand(); 865 } catch (RemoteException e) { 866 return -1; 867 } 868 } 869 870 /** 871 * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz) 872 * @return {@code true} if supported, {@code false} otherwise. 873 * @hide 874 */ 875 public boolean isDualBandSupported() { 876 try { 877 return mService.isDualBandSupported(); 878 } catch (RemoteException e) { 879 return false; 880 } 881 } 882 883 /** 884 * Return the DHCP-assigned addresses from the last successful DHCP request, 885 * if any. 886 * @return the DHCP information 887 * @deprecated - use ConnectivityManager.getLinkProperties instead. TODO - remove 11/2013 888 */ 889 public DhcpInfo getDhcpInfo() { 890 try { 891 return mService.getDhcpInfo(); 892 } catch (RemoteException e) { 893 return null; 894 } 895 } 896 897 /** 898 * Enable or disable Wi-Fi. 899 * @param enabled {@code true} to enable, {@code false} to disable. 900 * @return {@code true} if the operation succeeds (or if the existing state 901 * is the same as the requested state). 902 */ 903 public boolean setWifiEnabled(boolean enabled) { 904 try { 905 return mService.setWifiEnabled(enabled); 906 } catch (RemoteException e) { 907 return false; 908 } 909 } 910 911 /** 912 * Gets the Wi-Fi enabled state. 913 * @return One of {@link #WIFI_STATE_DISABLED}, 914 * {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED}, 915 * {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN} 916 * @see #isWifiEnabled() 917 */ 918 public int getWifiState() { 919 try { 920 return mService.getWifiEnabledState(); 921 } catch (RemoteException e) { 922 return WIFI_STATE_UNKNOWN; 923 } 924 } 925 926 /** 927 * Return whether Wi-Fi is enabled or disabled. 928 * @return {@code true} if Wi-Fi is enabled 929 * @see #getWifiState() 930 */ 931 public boolean isWifiEnabled() { 932 return getWifiState() == WIFI_STATE_ENABLED; 933 } 934 935 /** 936 * Return TX packet counter, for CTS test of WiFi watchdog. 937 * @param listener is the interface to receive result 938 * 939 * @hide for CTS test only 940 */ 941 public void getTxPacketCount(TxPacketCountListener listener) { 942 validateChannel(); 943 sAsyncChannel.sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener)); 944 } 945 946 /** 947 * Calculates the level of the signal. This should be used any time a signal 948 * is being shown. 949 * 950 * @param rssi The power of the signal measured in RSSI. 951 * @param numLevels The number of levels to consider in the calculated 952 * level. 953 * @return A level of the signal, given in the range of 0 to numLevels-1 954 * (both inclusive). 955 */ 956 public static int calculateSignalLevel(int rssi, int numLevels) { 957 if (rssi <= MIN_RSSI) { 958 return 0; 959 } else if (rssi >= MAX_RSSI) { 960 return numLevels - 1; 961 } else { 962 float inputRange = (MAX_RSSI - MIN_RSSI); 963 float outputRange = (numLevels - 1); 964 return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange); 965 } 966 } 967 968 /** 969 * Compares two signal strengths. 970 * 971 * @param rssiA The power of the first signal measured in RSSI. 972 * @param rssiB The power of the second signal measured in RSSI. 973 * @return Returns <0 if the first signal is weaker than the second signal, 974 * 0 if the two signals have the same strength, and >0 if the first 975 * signal is stronger than the second signal. 976 */ 977 public static int compareSignalLevel(int rssiA, int rssiB) { 978 return rssiA - rssiB; 979 } 980 981 /** 982 * Start AccessPoint mode with the specified 983 * configuration. If the radio is already running in 984 * AP mode, update the new configuration 985 * Note that starting in access point mode disables station 986 * mode operation 987 * @param wifiConfig SSID, security and channel details as 988 * part of WifiConfiguration 989 * @return {@code true} if the operation succeeds, {@code false} otherwise 990 * 991 * @hide Dont open up yet 992 */ 993 public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { 994 try { 995 mService.setWifiApEnabled(wifiConfig, enabled); 996 return true; 997 } catch (RemoteException e) { 998 return false; 999 } 1000 } 1001 1002 /** 1003 * Gets the Wi-Fi enabled state. 1004 * @return One of {@link #WIFI_AP_STATE_DISABLED}, 1005 * {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED}, 1006 * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} 1007 * @see #isWifiApEnabled() 1008 * 1009 * @hide Dont open yet 1010 */ 1011 public int getWifiApState() { 1012 try { 1013 return mService.getWifiApEnabledState(); 1014 } catch (RemoteException e) { 1015 return WIFI_AP_STATE_FAILED; 1016 } 1017 } 1018 1019 /** 1020 * Return whether Wi-Fi AP is enabled or disabled. 1021 * @return {@code true} if Wi-Fi AP is enabled 1022 * @see #getWifiApState() 1023 * 1024 * @hide Dont open yet 1025 */ 1026 public boolean isWifiApEnabled() { 1027 return getWifiApState() == WIFI_AP_STATE_ENABLED; 1028 } 1029 1030 /** 1031 * Gets the Wi-Fi AP Configuration. 1032 * @return AP details in WifiConfiguration 1033 * 1034 * @hide Dont open yet 1035 */ 1036 public WifiConfiguration getWifiApConfiguration() { 1037 try { 1038 return mService.getWifiApConfiguration(); 1039 } catch (RemoteException e) { 1040 return null; 1041 } 1042 } 1043 1044 /** 1045 * Sets the Wi-Fi AP Configuration. 1046 * @return {@code true} if the operation succeeded, {@code false} otherwise 1047 * 1048 * @hide Dont open yet 1049 */ 1050 public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) { 1051 try { 1052 mService.setWifiApConfiguration(wifiConfig); 1053 return true; 1054 } catch (RemoteException e) { 1055 return false; 1056 } 1057 } 1058 1059 /** 1060 * Start the driver and connect to network. 1061 * 1062 * This function will over-ride WifiLock and device idle status. For example, 1063 * even if the device is idle or there is only a scan-only lock held, 1064 * a start wifi would mean that wifi connection is kept active until 1065 * a stopWifi() is sent. 1066 * 1067 * This API is used by WifiStateTracker 1068 * 1069 * @return {@code true} if the operation succeeds else {@code false} 1070 * @hide 1071 */ 1072 public boolean startWifi() { 1073 try { 1074 mService.startWifi(); 1075 return true; 1076 } catch (RemoteException e) { 1077 return false; 1078 } 1079 } 1080 1081 /** 1082 * Disconnect from a network (if any) and stop the driver. 1083 * 1084 * This function will over-ride WifiLock and device idle status. Wi-Fi 1085 * stays inactive until a startWifi() is issued. 1086 * 1087 * This API is used by WifiStateTracker 1088 * 1089 * @return {@code true} if the operation succeeds else {@code false} 1090 * @hide 1091 */ 1092 public boolean stopWifi() { 1093 try { 1094 mService.stopWifi(); 1095 return true; 1096 } catch (RemoteException e) { 1097 return false; 1098 } 1099 } 1100 1101 /** 1102 * Add a bssid to the supplicant blacklist 1103 * 1104 * This API is used by WifiWatchdogService 1105 * 1106 * @return {@code true} if the operation succeeds else {@code false} 1107 * @hide 1108 */ 1109 public boolean addToBlacklist(String bssid) { 1110 try { 1111 mService.addToBlacklist(bssid); 1112 return true; 1113 } catch (RemoteException e) { 1114 return false; 1115 } 1116 } 1117 1118 /** 1119 * Clear the supplicant blacklist 1120 * 1121 * This API is used by WifiWatchdogService 1122 * 1123 * @return {@code true} if the operation succeeds else {@code false} 1124 * @hide 1125 */ 1126 public boolean clearBlacklist() { 1127 try { 1128 mService.clearBlacklist(); 1129 return true; 1130 } catch (RemoteException e) { 1131 return false; 1132 } 1133 } 1134 1135 /* TODO: deprecate synchronous API and open up the following API */ 1136 1137 private static final int BASE = Protocol.BASE_WIFI_MANAGER; 1138 1139 /* Commands to WifiService */ 1140 /** @hide */ 1141 public static final int CONNECT_NETWORK = BASE + 1; 1142 /** @hide */ 1143 public static final int CONNECT_NETWORK_FAILED = BASE + 2; 1144 /** @hide */ 1145 public static final int CONNECT_NETWORK_SUCCEEDED = BASE + 3; 1146 1147 /** @hide */ 1148 public static final int FORGET_NETWORK = BASE + 4; 1149 /** @hide */ 1150 public static final int FORGET_NETWORK_FAILED = BASE + 5; 1151 /** @hide */ 1152 public static final int FORGET_NETWORK_SUCCEEDED = BASE + 6; 1153 1154 /** @hide */ 1155 public static final int SAVE_NETWORK = BASE + 7; 1156 /** @hide */ 1157 public static final int SAVE_NETWORK_FAILED = BASE + 8; 1158 /** @hide */ 1159 public static final int SAVE_NETWORK_SUCCEEDED = BASE + 9; 1160 1161 /** @hide */ 1162 public static final int START_WPS = BASE + 10; 1163 /** @hide */ 1164 public static final int START_WPS_SUCCEEDED = BASE + 11; 1165 /** @hide */ 1166 public static final int WPS_FAILED = BASE + 12; 1167 /** @hide */ 1168 public static final int WPS_COMPLETED = BASE + 13; 1169 1170 /** @hide */ 1171 public static final int CANCEL_WPS = BASE + 14; 1172 /** @hide */ 1173 public static final int CANCEL_WPS_FAILED = BASE + 15; 1174 /** @hide */ 1175 public static final int CANCEL_WPS_SUCCEDED = BASE + 16; 1176 1177 /** @hide */ 1178 public static final int DISABLE_NETWORK = BASE + 17; 1179 /** @hide */ 1180 public static final int DISABLE_NETWORK_FAILED = BASE + 18; 1181 /** @hide */ 1182 public static final int DISABLE_NETWORK_SUCCEEDED = BASE + 19; 1183 1184 /** @hide */ 1185 public static final int RSSI_PKTCNT_FETCH = BASE + 20; 1186 /** @hide */ 1187 public static final int RSSI_PKTCNT_FETCH_SUCCEEDED = BASE + 21; 1188 /** @hide */ 1189 public static final int RSSI_PKTCNT_FETCH_FAILED = BASE + 22; 1190 1191 1192 /** 1193 * Passed with {@link ActionListener#onFailure}. 1194 * Indicates that the operation failed due to an internal error. 1195 * @hide 1196 */ 1197 public static final int ERROR = 0; 1198 1199 /** 1200 * Passed with {@link ActionListener#onFailure}. 1201 * Indicates that the operation is already in progress 1202 * @hide 1203 */ 1204 public static final int IN_PROGRESS = 1; 1205 1206 /** 1207 * Passed with {@link ActionListener#onFailure}. 1208 * Indicates that the operation failed because the framework is busy and 1209 * unable to service the request 1210 * @hide 1211 */ 1212 public static final int BUSY = 2; 1213 1214 /* WPS specific errors */ 1215 /** WPS overlap detected {@hide} */ 1216 public static final int WPS_OVERLAP_ERROR = 3; 1217 /** WEP on WPS is prohibited {@hide} */ 1218 public static final int WPS_WEP_PROHIBITED = 4; 1219 /** TKIP only prohibited {@hide} */ 1220 public static final int WPS_TKIP_ONLY_PROHIBITED = 5; 1221 /** Authentication failure on WPS {@hide} */ 1222 public static final int WPS_AUTH_FAILURE = 6; 1223 /** WPS timed out {@hide} */ 1224 public static final int WPS_TIMED_OUT = 7; 1225 1226 /** Interface for callback invocation on an application action {@hide} */ 1227 public interface ActionListener { 1228 /** The operation succeeded */ 1229 public void onSuccess(); 1230 /** 1231 * The operation failed 1232 * @param reason The reason for failure could be one of 1233 * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY} 1234 */ 1235 public void onFailure(int reason); 1236 } 1237 1238 /** Interface for callback invocation on a start WPS action {@hide} */ 1239 public interface WpsListener { 1240 /** WPS start succeeded */ 1241 public void onStartSuccess(String pin); 1242 1243 /** WPS operation completed succesfully */ 1244 public void onCompletion(); 1245 1246 /** 1247 * WPS operation failed 1248 * @param reason The reason for failure could be one of 1249 * {@link #IN_PROGRESS}, {@link #WPS_OVERLAP_ERROR},{@link #ERROR} or {@link #BUSY} 1250 */ 1251 public void onFailure(int reason); 1252 } 1253 1254 /** Interface for callback invocation on a TX packet count poll action {@hide} */ 1255 public interface TxPacketCountListener { 1256 /** 1257 * The operation succeeded 1258 * @param count TX packet counter 1259 */ 1260 public void onSuccess(int count); 1261 /** 1262 * The operation failed 1263 * @param reason The reason for failure could be one of 1264 * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY} 1265 */ 1266 public void onFailure(int reason); 1267 } 1268 1269 private static class ServiceHandler extends Handler { 1270 ServiceHandler(Looper looper) { 1271 super(looper); 1272 } 1273 1274 @Override 1275 public void handleMessage(Message message) { 1276 Object listener = removeListener(message.arg2); 1277 switch (message.what) { 1278 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 1279 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 1280 sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 1281 } else { 1282 Log.e(TAG, "Failed to set up channel connection"); 1283 // This will cause all further async API calls on the WifiManager 1284 // to fail and throw an exception 1285 sAsyncChannel = null; 1286 } 1287 sConnected.countDown(); 1288 break; 1289 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: 1290 // Ignore 1291 break; 1292 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 1293 Log.e(TAG, "Channel connection lost"); 1294 // This will cause all further async API calls on the WifiManager 1295 // to fail and throw an exception 1296 sAsyncChannel = null; 1297 getLooper().quit(); 1298 break; 1299 /* ActionListeners grouped together */ 1300 case WifiManager.CONNECT_NETWORK_FAILED: 1301 case WifiManager.FORGET_NETWORK_FAILED: 1302 case WifiManager.SAVE_NETWORK_FAILED: 1303 case WifiManager.CANCEL_WPS_FAILED: 1304 case WifiManager.DISABLE_NETWORK_FAILED: 1305 if (listener != null) { 1306 ((ActionListener) listener).onFailure(message.arg1); 1307 } 1308 break; 1309 /* ActionListeners grouped together */ 1310 case WifiManager.CONNECT_NETWORK_SUCCEEDED: 1311 case WifiManager.FORGET_NETWORK_SUCCEEDED: 1312 case WifiManager.SAVE_NETWORK_SUCCEEDED: 1313 case WifiManager.CANCEL_WPS_SUCCEDED: 1314 case WifiManager.DISABLE_NETWORK_SUCCEEDED: 1315 if (listener != null) { 1316 ((ActionListener) listener).onSuccess(); 1317 } 1318 break; 1319 case WifiManager.START_WPS_SUCCEEDED: 1320 if (listener != null) { 1321 WpsResult result = (WpsResult) message.obj; 1322 ((WpsListener) listener).onStartSuccess(result.pin); 1323 //Listener needs to stay until completion or failure 1324 synchronized(sListenerMapLock) { 1325 sListenerMap.put(message.arg2, listener); 1326 } 1327 } 1328 break; 1329 case WifiManager.WPS_COMPLETED: 1330 if (listener != null) { 1331 ((WpsListener) listener).onCompletion(); 1332 } 1333 break; 1334 case WifiManager.WPS_FAILED: 1335 if (listener != null) { 1336 ((WpsListener) listener).onFailure(message.arg1); 1337 } 1338 break; 1339 case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED: 1340 if (listener != null) { 1341 RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj; 1342 if (info != null) 1343 ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad); 1344 else 1345 ((TxPacketCountListener) listener).onFailure(ERROR); 1346 } 1347 break; 1348 case WifiManager.RSSI_PKTCNT_FETCH_FAILED: 1349 if (listener != null) { 1350 ((TxPacketCountListener) listener).onFailure(message.arg1); 1351 } 1352 break; 1353 default: 1354 //ignore 1355 break; 1356 } 1357 } 1358 } 1359 1360 private static int putListener(Object listener) { 1361 if (listener == null) return INVALID_KEY; 1362 int key; 1363 synchronized (sListenerMapLock) { 1364 do { 1365 key = sListenerKey++; 1366 } while (key == INVALID_KEY); 1367 sListenerMap.put(key, listener); 1368 } 1369 return key; 1370 } 1371 1372 private static Object removeListener(int key) { 1373 if (key == INVALID_KEY) return null; 1374 synchronized (sListenerMapLock) { 1375 Object listener = sListenerMap.get(key); 1376 sListenerMap.remove(key); 1377 return listener; 1378 } 1379 } 1380 1381 private void init() { 1382 synchronized (sThreadRefLock) { 1383 if (++sThreadRefCount == 1) { 1384 Messenger messenger = getWifiServiceMessenger(); 1385 if (messenger == null) { 1386 sAsyncChannel = null; 1387 return; 1388 } 1389 1390 sHandlerThread = new HandlerThread("WifiManager"); 1391 sAsyncChannel = new AsyncChannel(); 1392 sConnected = new CountDownLatch(1); 1393 1394 sHandlerThread.start(); 1395 Handler handler = new ServiceHandler(sHandlerThread.getLooper()); 1396 sAsyncChannel.connect(mContext, handler, messenger); 1397 try { 1398 sConnected.await(); 1399 } catch (InterruptedException e) { 1400 Log.e(TAG, "interrupted wait at init"); 1401 } 1402 } 1403 } 1404 } 1405 1406 private void validateChannel() { 1407 if (sAsyncChannel == null) throw new IllegalStateException( 1408 "No permission to access and change wifi or a bad initialization"); 1409 } 1410 1411 /** 1412 * Connect to a network with the given configuration. The network also 1413 * gets added to the supplicant configuration. 1414 * 1415 * For a new network, this function is used instead of a 1416 * sequence of addNetwork(), enableNetwork(), saveConfiguration() and 1417 * reconnect() 1418 * 1419 * @param config the set of variables that describe the configuration, 1420 * contained in a {@link WifiConfiguration} object. 1421 * @param listener for callbacks on success or failure. Can be null. 1422 * @throws IllegalStateException if the WifiManager instance needs to be 1423 * initialized again 1424 * 1425 * @hide 1426 */ 1427 public void connect(WifiConfiguration config, ActionListener listener) { 1428 if (config == null) throw new IllegalArgumentException("config cannot be null"); 1429 validateChannel(); 1430 // Use INVALID_NETWORK_ID for arg1 when passing a config object 1431 // arg1 is used to pass network id when the network already exists 1432 sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID, 1433 putListener(listener), config); 1434 } 1435 1436 /** 1437 * Connect to a network with the given networkId. 1438 * 1439 * This function is used instead of a enableNetwork(), saveConfiguration() and 1440 * reconnect() 1441 * 1442 * @param networkId the network id identifiying the network in the 1443 * supplicant configuration list 1444 * @param listener for callbacks on success or failure. Can be null. 1445 * @throws IllegalStateException if the WifiManager instance needs to be 1446 * initialized again 1447 * @hide 1448 */ 1449 public void connect(int networkId, ActionListener listener) { 1450 if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative"); 1451 validateChannel(); 1452 sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener)); 1453 } 1454 1455 /** 1456 * Save the given network in the supplicant config. If the network already 1457 * exists, the configuration is updated. A new network is enabled 1458 * by default. 1459 * 1460 * For a new network, this function is used instead of a 1461 * sequence of addNetwork(), enableNetwork() and saveConfiguration(). 1462 * 1463 * For an existing network, it accomplishes the task of updateNetwork() 1464 * and saveConfiguration() 1465 * 1466 * @param config the set of variables that describe the configuration, 1467 * contained in a {@link WifiConfiguration} object. 1468 * @param listener for callbacks on success or failure. Can be null. 1469 * @throws IllegalStateException if the WifiManager instance needs to be 1470 * initialized again 1471 * @hide 1472 */ 1473 public void save(WifiConfiguration config, ActionListener listener) { 1474 if (config == null) throw new IllegalArgumentException("config cannot be null"); 1475 validateChannel(); 1476 sAsyncChannel.sendMessage(SAVE_NETWORK, 0, putListener(listener), config); 1477 } 1478 1479 /** 1480 * Delete the network in the supplicant config. 1481 * 1482 * This function is used instead of a sequence of removeNetwork() 1483 * and saveConfiguration(). 1484 * 1485 * @param config the set of variables that describe the configuration, 1486 * contained in a {@link WifiConfiguration} object. 1487 * @param listener for callbacks on success or failure. Can be null. 1488 * @throws IllegalStateException if the WifiManager instance needs to be 1489 * initialized again 1490 * @hide 1491 */ 1492 public void forget(int netId, ActionListener listener) { 1493 if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative"); 1494 validateChannel(); 1495 sAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener)); 1496 } 1497 1498 /** 1499 * Disable network 1500 * 1501 * @param netId is the network Id 1502 * @param listener for callbacks on success or failure. Can be null. 1503 * @throws IllegalStateException if the WifiManager instance needs to be 1504 * initialized again 1505 * @hide 1506 */ 1507 public void disable(int netId, ActionListener listener) { 1508 if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative"); 1509 validateChannel(); 1510 sAsyncChannel.sendMessage(DISABLE_NETWORK, netId, putListener(listener)); 1511 } 1512 1513 /** 1514 * Start Wi-fi Protected Setup 1515 * 1516 * @param config WPS configuration 1517 * @param listener for callbacks on success or failure. Can be null. 1518 * @throws IllegalStateException if the WifiManager instance needs to be 1519 * initialized again 1520 * @hide 1521 */ 1522 public void startWps(WpsInfo config, WpsListener listener) { 1523 if (config == null) throw new IllegalArgumentException("config cannot be null"); 1524 validateChannel(); 1525 sAsyncChannel.sendMessage(START_WPS, 0, putListener(listener), config); 1526 } 1527 1528 /** 1529 * Cancel any ongoing Wi-fi Protected Setup 1530 * 1531 * @param listener for callbacks on success or failure. Can be null. 1532 * @throws IllegalStateException if the WifiManager instance needs to be 1533 * initialized again 1534 * @hide 1535 */ 1536 public void cancelWps(ActionListener listener) { 1537 validateChannel(); 1538 sAsyncChannel.sendMessage(CANCEL_WPS, 0, putListener(listener)); 1539 } 1540 1541 /** 1542 * Get a reference to WifiService handler. This is used by a client to establish 1543 * an AsyncChannel communication with WifiService 1544 * 1545 * @return Messenger pointing to the WifiService handler 1546 * @hide 1547 */ 1548 public Messenger getWifiServiceMessenger() { 1549 try { 1550 return mService.getWifiServiceMessenger(); 1551 } catch (RemoteException e) { 1552 return null; 1553 } catch (SecurityException e) { 1554 return null; 1555 } 1556 } 1557 1558 /** 1559 * Get a reference to WifiStateMachine handler. 1560 * @return Messenger pointing to the WifiService handler 1561 * @hide 1562 */ 1563 public Messenger getWifiStateMachineMessenger() { 1564 try { 1565 return mService.getWifiStateMachineMessenger(); 1566 } catch (RemoteException e) { 1567 return null; 1568 } 1569 } 1570 1571 /** 1572 * Returns the file in which IP and proxy configuration data is stored 1573 * @hide 1574 */ 1575 public String getConfigFile() { 1576 try { 1577 return mService.getConfigFile(); 1578 } catch (RemoteException e) { 1579 return null; 1580 } 1581 } 1582 1583 /** 1584 * Allows an application to keep the Wi-Fi radio awake. 1585 * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. 1586 * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple 1587 * applications may hold WifiLocks, and the radio will only be allowed to turn off when no 1588 * WifiLocks are held in any application. 1589 * <p> 1590 * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or 1591 * could function over a mobile network, if available. A program that needs to download large 1592 * files should hold a WifiLock to ensure that the download will complete, but a program whose 1593 * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely 1594 * affecting battery life. 1595 * <p> 1596 * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane 1597 * Mode. They simply keep the radio from turning off when Wi-Fi is already on but the device 1598 * is idle. 1599 * <p> 1600 * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK} 1601 * permission in an {@code <uses-permission>} element of the application's manifest. 1602 */ 1603 public class WifiLock { 1604 private String mTag; 1605 private final IBinder mBinder; 1606 private int mRefCount; 1607 int mLockType; 1608 private boolean mRefCounted; 1609 private boolean mHeld; 1610 private WorkSource mWorkSource; 1611 1612 private WifiLock(int lockType, String tag) { 1613 mTag = tag; 1614 mLockType = lockType; 1615 mBinder = new Binder(); 1616 mRefCount = 0; 1617 mRefCounted = true; 1618 mHeld = false; 1619 } 1620 1621 /** 1622 * Locks the Wi-Fi radio on until {@link #release} is called. 1623 * 1624 * If this WifiLock is reference-counted, each call to {@code acquire} will increment the 1625 * reference count, and the radio will remain locked as long as the reference count is 1626 * above zero. 1627 * 1628 * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock 1629 * the radio, but subsequent calls will be ignored. Only one call to {@link #release} 1630 * will be required, regardless of the number of times that {@code acquire} is called. 1631 */ 1632 public void acquire() { 1633 synchronized (mBinder) { 1634 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) { 1635 try { 1636 mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource); 1637 synchronized (WifiManager.this) { 1638 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 1639 mService.releaseWifiLock(mBinder); 1640 throw new UnsupportedOperationException( 1641 "Exceeded maximum number of wifi locks"); 1642 } 1643 mActiveLockCount++; 1644 } 1645 } catch (RemoteException ignore) { 1646 } 1647 mHeld = true; 1648 } 1649 } 1650 } 1651 1652 /** 1653 * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle. 1654 * 1655 * If this WifiLock is reference-counted, each call to {@code release} will decrement the 1656 * reference count, and the radio will be unlocked only when the reference count reaches 1657 * zero. If the reference count goes below zero (that is, if {@code release} is called 1658 * a greater number of times than {@link #acquire}), an exception is thrown. 1659 * 1660 * If this WifiLock is not reference-counted, the first call to {@code release} (after 1661 * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent 1662 * calls will be ignored. 1663 */ 1664 public void release() { 1665 synchronized (mBinder) { 1666 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 1667 try { 1668 mService.releaseWifiLock(mBinder); 1669 synchronized (WifiManager.this) { 1670 mActiveLockCount--; 1671 } 1672 } catch (RemoteException ignore) { 1673 } 1674 mHeld = false; 1675 } 1676 if (mRefCount < 0) { 1677 throw new RuntimeException("WifiLock under-locked " + mTag); 1678 } 1679 } 1680 } 1681 1682 /** 1683 * Controls whether this is a reference-counted or non-reference-counted WifiLock. 1684 * 1685 * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and 1686 * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire} 1687 * has been balanced with a call to {@link #release}. Non-reference-counted WifiLocks 1688 * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the 1689 * radio whenever {@link #release} is called and it is locked. 1690 * 1691 * @param refCounted true if this WifiLock should keep a reference count 1692 */ 1693 public void setReferenceCounted(boolean refCounted) { 1694 mRefCounted = refCounted; 1695 } 1696 1697 /** 1698 * Checks whether this WifiLock is currently held. 1699 * 1700 * @return true if this WifiLock is held, false otherwise 1701 */ 1702 public boolean isHeld() { 1703 synchronized (mBinder) { 1704 return mHeld; 1705 } 1706 } 1707 1708 public void setWorkSource(WorkSource ws) { 1709 synchronized (mBinder) { 1710 if (ws != null && ws.size() == 0) { 1711 ws = null; 1712 } 1713 boolean changed = true; 1714 if (ws == null) { 1715 mWorkSource = null; 1716 } else if (mWorkSource == null) { 1717 changed = mWorkSource != null; 1718 mWorkSource = new WorkSource(ws); 1719 } else { 1720 changed = mWorkSource.diff(ws); 1721 if (changed) { 1722 mWorkSource.set(ws); 1723 } 1724 } 1725 if (changed && mHeld) { 1726 try { 1727 mService.updateWifiLockWorkSource(mBinder, mWorkSource); 1728 } catch (RemoteException e) { 1729 } 1730 } 1731 } 1732 } 1733 1734 public String toString() { 1735 String s1, s2, s3; 1736 synchronized (mBinder) { 1737 s1 = Integer.toHexString(System.identityHashCode(this)); 1738 s2 = mHeld ? "held; " : ""; 1739 if (mRefCounted) { 1740 s3 = "refcounted: refcount = " + mRefCount; 1741 } else { 1742 s3 = "not refcounted"; 1743 } 1744 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }"; 1745 } 1746 } 1747 1748 @Override 1749 protected void finalize() throws Throwable { 1750 super.finalize(); 1751 synchronized (mBinder) { 1752 if (mHeld) { 1753 try { 1754 mService.releaseWifiLock(mBinder); 1755 synchronized (WifiManager.this) { 1756 mActiveLockCount--; 1757 } 1758 } catch (RemoteException ignore) { 1759 } 1760 } 1761 } 1762 } 1763 } 1764 1765 /** 1766 * Creates a new WifiLock. 1767 * 1768 * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL}, 1769 * {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for 1770 * descriptions of the types of Wi-Fi locks. 1771 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 1772 * never shown to the user under normal conditions, but should be descriptive 1773 * enough to identify your application and the specific WifiLock within it, if it 1774 * holds multiple WifiLocks. 1775 * 1776 * @return a new, unacquired WifiLock with the given tag. 1777 * 1778 * @see WifiLock 1779 */ 1780 public WifiLock createWifiLock(int lockType, String tag) { 1781 return new WifiLock(lockType, tag); 1782 } 1783 1784 /** 1785 * Creates a new WifiLock. 1786 * 1787 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 1788 * never shown to the user under normal conditions, but should be descriptive 1789 * enough to identify your application and the specific WifiLock within it, if it 1790 * holds multiple WifiLocks. 1791 * 1792 * @return a new, unacquired WifiLock with the given tag. 1793 * 1794 * @see WifiLock 1795 */ 1796 public WifiLock createWifiLock(String tag) { 1797 return new WifiLock(WIFI_MODE_FULL, tag); 1798 } 1799 1800 1801 /** 1802 * Create a new MulticastLock 1803 * 1804 * @param tag a tag for the MulticastLock to identify it in debugging 1805 * messages. This string is never shown to the user under 1806 * normal conditions, but should be descriptive enough to 1807 * identify your application and the specific MulticastLock 1808 * within it, if it holds multiple MulticastLocks. 1809 * 1810 * @return a new, unacquired MulticastLock with the given tag. 1811 * 1812 * @see MulticastLock 1813 */ 1814 public MulticastLock createMulticastLock(String tag) { 1815 return new MulticastLock(tag); 1816 } 1817 1818 /** 1819 * Allows an application to receive Wifi Multicast packets. 1820 * Normally the Wifi stack filters out packets not explicitly 1821 * addressed to this device. Acquring a MulticastLock will 1822 * cause the stack to receive packets addressed to multicast 1823 * addresses. Processing these extra packets can cause a noticable 1824 * battery drain and should be disabled when not needed. 1825 */ 1826 public class MulticastLock { 1827 private String mTag; 1828 private final IBinder mBinder; 1829 private int mRefCount; 1830 private boolean mRefCounted; 1831 private boolean mHeld; 1832 1833 private MulticastLock(String tag) { 1834 mTag = tag; 1835 mBinder = new Binder(); 1836 mRefCount = 0; 1837 mRefCounted = true; 1838 mHeld = false; 1839 } 1840 1841 /** 1842 * Locks Wifi Multicast on until {@link #release} is called. 1843 * 1844 * If this MulticastLock is reference-counted each call to 1845 * {@code acquire} will increment the reference count, and the 1846 * wifi interface will receive multicast packets as long as the 1847 * reference count is above zero. 1848 * 1849 * If this MulticastLock is not reference-counted, the first call to 1850 * {@code acquire} will turn on the multicast packets, but subsequent 1851 * calls will be ignored. Only one call to {@link #release} will 1852 * be required, regardless of the number of times that {@code acquire} 1853 * is called. 1854 * 1855 * Note that other applications may also lock Wifi Multicast on. 1856 * Only they can relinquish their lock. 1857 * 1858 * Also note that applications cannot leave Multicast locked on. 1859 * When an app exits or crashes, any Multicast locks will be released. 1860 */ 1861 public void acquire() { 1862 synchronized (mBinder) { 1863 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) { 1864 try { 1865 mService.acquireMulticastLock(mBinder, mTag); 1866 synchronized (WifiManager.this) { 1867 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 1868 mService.releaseMulticastLock(); 1869 throw new UnsupportedOperationException( 1870 "Exceeded maximum number of wifi locks"); 1871 } 1872 mActiveLockCount++; 1873 } 1874 } catch (RemoteException ignore) { 1875 } 1876 mHeld = true; 1877 } 1878 } 1879 } 1880 1881 /** 1882 * Unlocks Wifi Multicast, restoring the filter of packets 1883 * not addressed specifically to this device and saving power. 1884 * 1885 * If this MulticastLock is reference-counted, each call to 1886 * {@code release} will decrement the reference count, and the 1887 * multicast packets will only stop being received when the reference 1888 * count reaches zero. If the reference count goes below zero (that 1889 * is, if {@code release} is called a greater number of times than 1890 * {@link #acquire}), an exception is thrown. 1891 * 1892 * If this MulticastLock is not reference-counted, the first call to 1893 * {@code release} (after the radio was multicast locked using 1894 * {@link #acquire}) will unlock the multicast, and subsequent calls 1895 * will be ignored. 1896 * 1897 * Note that if any other Wifi Multicast Locks are still outstanding 1898 * this {@code release} call will not have an immediate effect. Only 1899 * when all applications have released all their Multicast Locks will 1900 * the Multicast filter be turned back on. 1901 * 1902 * Also note that when an app exits or crashes all of its Multicast 1903 * Locks will be automatically released. 1904 */ 1905 public void release() { 1906 synchronized (mBinder) { 1907 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 1908 try { 1909 mService.releaseMulticastLock(); 1910 synchronized (WifiManager.this) { 1911 mActiveLockCount--; 1912 } 1913 } catch (RemoteException ignore) { 1914 } 1915 mHeld = false; 1916 } 1917 if (mRefCount < 0) { 1918 throw new RuntimeException("MulticastLock under-locked " 1919 + mTag); 1920 } 1921 } 1922 } 1923 1924 /** 1925 * Controls whether this is a reference-counted or non-reference- 1926 * counted MulticastLock. 1927 * 1928 * Reference-counted MulticastLocks keep track of the number of calls 1929 * to {@link #acquire} and {@link #release}, and only stop the 1930 * reception of multicast packets when every call to {@link #acquire} 1931 * has been balanced with a call to {@link #release}. Non-reference- 1932 * counted MulticastLocks allow the reception of multicast packets 1933 * whenever {@link #acquire} is called and stop accepting multicast 1934 * packets whenever {@link #release} is called. 1935 * 1936 * @param refCounted true if this MulticastLock should keep a reference 1937 * count 1938 */ 1939 public void setReferenceCounted(boolean refCounted) { 1940 mRefCounted = refCounted; 1941 } 1942 1943 /** 1944 * Checks whether this MulticastLock is currently held. 1945 * 1946 * @return true if this MulticastLock is held, false otherwise 1947 */ 1948 public boolean isHeld() { 1949 synchronized (mBinder) { 1950 return mHeld; 1951 } 1952 } 1953 1954 public String toString() { 1955 String s1, s2, s3; 1956 synchronized (mBinder) { 1957 s1 = Integer.toHexString(System.identityHashCode(this)); 1958 s2 = mHeld ? "held; " : ""; 1959 if (mRefCounted) { 1960 s3 = "refcounted: refcount = " + mRefCount; 1961 } else { 1962 s3 = "not refcounted"; 1963 } 1964 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }"; 1965 } 1966 } 1967 1968 @Override 1969 protected void finalize() throws Throwable { 1970 super.finalize(); 1971 setReferenceCounted(false); 1972 release(); 1973 } 1974 } 1975 1976 /** 1977 * Check multicast filter status. 1978 * 1979 * @return true if multicast packets are allowed. 1980 * 1981 * @hide pending API council approval 1982 */ 1983 public boolean isMulticastEnabled() { 1984 try { 1985 return mService.isMulticastEnabled(); 1986 } catch (RemoteException e) { 1987 return false; 1988 } 1989 } 1990 1991 /** 1992 * Initialize the multicast filtering to 'on' 1993 * @hide no intent to publish 1994 */ 1995 public boolean initializeMulticastFiltering() { 1996 try { 1997 mService.initializeMulticastFiltering(); 1998 return true; 1999 } catch (RemoteException e) { 2000 return false; 2001 } 2002 } 2003 2004 /** @hide */ 2005 public void captivePortalCheckComplete() { 2006 try { 2007 mService.captivePortalCheckComplete(); 2008 } catch (RemoteException e) {} 2009 } 2010 2011 protected void finalize() throws Throwable { 2012 try { 2013 synchronized (sThreadRefLock) { 2014 if (--sThreadRefCount == 0 && sAsyncChannel != null) { 2015 sAsyncChannel.disconnect(); 2016 } 2017 } 2018 } finally { 2019 super.finalize(); 2020 } 2021 } 2022 } 2023