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