WifiManager.java revision a5ec95cdb1a7d2024249277dff1f99d0046c9b56
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.net.DhcpInfo; 22import android.os.Binder; 23import android.os.IBinder; 24import android.os.Handler; 25import android.os.RemoteException; 26 27import java.util.List; 28 29/** 30 * This class provides the primary API for managing all aspects of Wi-Fi 31 * connectivity. Get an instance of this class by calling 32 * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}. 33 34 * It deals with several categories of items: 35 * <ul> 36 * <li>The list of configured networks. The list can be viewed and updated, 37 * and attributes of individual entries can be modified.</li> 38 * <li>The currently active Wi-Fi network, if any. Connectivity can be 39 * established or torn down, and dynamic information about the state of 40 * the network can be queried.</li> 41 * <li>Results of access point scans, containing enough information to 42 * make decisions about what access point to connect to.</li> 43 * <li>It defines the names of various Intent actions that are broadcast 44 * upon any sort of change in Wi-Fi state. 45 * </ul> 46 * This is the API to use when performing Wi-Fi specific operations. To 47 * perform operations that pertain to network connectivity at an abstract 48 * level, use {@link android.net.ConnectivityManager}. 49 */ 50public class WifiManager { 51 52 // Supplicant error codes: 53 /** 54 * The error code if there was a problem authenticating. 55 */ 56 public static final int ERROR_AUTHENTICATING = 1; 57 58 /** 59 * Broadcast intent action indicating that Wi-Fi has been enabled, disabled, 60 * enabling, disabling, or unknown. One extra provides this state as an int. 61 * Another extra provides the previous state, if available. 62 * 63 * @see #EXTRA_WIFI_STATE 64 * @see #EXTRA_PREVIOUS_WIFI_STATE 65 */ 66 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 67 public static final String WIFI_STATE_CHANGED_ACTION = 68 "android.net.wifi.WIFI_STATE_CHANGED"; 69 /** 70 * The lookup key for an int that indicates whether Wi-Fi is enabled, 71 * disabled, enabling, disabling, or unknown. Retrieve it with 72 * {@link android.content.Intent#getIntExtra(String,int)}. 73 * 74 * @see #WIFI_STATE_DISABLED 75 * @see #WIFI_STATE_DISABLING 76 * @see #WIFI_STATE_ENABLED 77 * @see #WIFI_STATE_ENABLING 78 * @see #WIFI_STATE_UNKNOWN 79 */ 80 public static final String EXTRA_WIFI_STATE = "wifi_state"; 81 /** 82 * The previous Wi-Fi state. 83 * 84 * @see #EXTRA_WIFI_STATE 85 */ 86 public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state"; 87 88 /** 89 * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if 90 * it finishes successfully. 91 * 92 * @see #WIFI_STATE_CHANGED_ACTION 93 * @see #getWifiState() 94 */ 95 public static final int WIFI_STATE_DISABLING = 0; 96 /** 97 * Wi-Fi is disabled. 98 * 99 * @see #WIFI_STATE_CHANGED_ACTION 100 * @see #getWifiState() 101 */ 102 public static final int WIFI_STATE_DISABLED = 1; 103 /** 104 * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if 105 * it finishes successfully. 106 * 107 * @see #WIFI_STATE_CHANGED_ACTION 108 * @see #getWifiState() 109 */ 110 public static final int WIFI_STATE_ENABLING = 2; 111 /** 112 * Wi-Fi is enabled. 113 * 114 * @see #WIFI_STATE_CHANGED_ACTION 115 * @see #getWifiState() 116 */ 117 public static final int WIFI_STATE_ENABLED = 3; 118 /** 119 * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling 120 * or disabling. 121 * 122 * @see #WIFI_STATE_CHANGED_ACTION 123 * @see #getWifiState() 124 */ 125 public static final int WIFI_STATE_UNKNOWN = 4; 126 127 /** 128 * Broadcast intent action indicating that a connection to the supplicant has 129 * been established (and it is now possible 130 * to perform Wi-Fi operations) or the connection to the supplicant has been 131 * lost. One extra provides the connection state as a boolean, where {@code true} 132 * means CONNECTED. 133 * @see #EXTRA_SUPPLICANT_CONNECTED 134 */ 135 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 136 public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION = 137 "android.net.wifi.supplicant.CONNECTION_CHANGE"; 138 /** 139 * The lookup key for a boolean that indicates whether a connection to 140 * the supplicant daemon has been gained or lost. {@code true} means 141 * a connection now exists. 142 * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. 143 */ 144 public static final String EXTRA_SUPPLICANT_CONNECTED = "connected"; 145 /** 146 * Broadcast intent action indicating that the state of Wi-Fi connectivity 147 * has changed. One extra provides the new state 148 * in the form of a {@link android.net.NetworkInfo} object. If the new state is 149 * CONNECTED, a second extra may provide the BSSID of the access point, 150 * as a {@code String}. 151 * @see #EXTRA_NETWORK_INFO 152 * @see #EXTRA_BSSID 153 */ 154 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 155 public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"; 156 /** 157 * The lookup key for a {@link android.net.NetworkInfo} object associated with the 158 * Wi-Fi network. Retrieve with 159 * {@link android.content.Intent#getParcelableExtra(String)}. 160 */ 161 public static final String EXTRA_NETWORK_INFO = "networkInfo"; 162 /** 163 * The lookup key for a String giving the BSSID of the access point to which 164 * we are connected. Only present when the new state is CONNECTED. 165 * Retrieve with 166 * {@link android.content.Intent#getStringExtra(String)}. 167 */ 168 public static final String EXTRA_BSSID = "bssid"; 169 /** 170 * Broadcast intent action indicating that the state of establishing a connection to 171 * an access point has changed.One extra provides the new 172 * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and 173 * is not generally the most useful thing to look at if you are just interested in 174 * the overall state of connectivity. 175 * @see #EXTRA_NEW_STATE 176 * @see #EXTRA_SUPPLICANT_ERROR 177 */ 178 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 179 public static final String SUPPLICANT_STATE_CHANGED_ACTION = 180 "android.net.wifi.supplicant.STATE_CHANGE"; 181 /** 182 * The lookup key for a {@link SupplicantState} describing the new state 183 * Retrieve with 184 * {@link android.content.Intent#getParcelableExtra(String)}. 185 */ 186 public static final String EXTRA_NEW_STATE = "newState"; 187 188 /** 189 * The lookup key for a {@link SupplicantState} describing the supplicant 190 * error code if any 191 * Retrieve with 192 * {@link android.content.Intent#getIntExtra(String, int)}. 193 * @see #ERROR_AUTHENTICATING 194 */ 195 public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError"; 196 197 /** 198 * An access point scan has completed, and results are available from the supplicant. 199 * Call {@link #getScanResults()} to obtain the results. 200 */ 201 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 202 public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS"; 203 /** 204 * The RSSI (signal strength) has changed. 205 * @see #EXTRA_NEW_RSSI 206 */ 207 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 208 public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED"; 209 /** 210 * The lookup key for an {@code int} giving the new RSSI in dBm. 211 */ 212 public static final String EXTRA_NEW_RSSI = "newRssi"; 213 214 /** 215 * The network IDs of the configured networks could have changed. 216 */ 217 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 218 public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED"; 219 220 /** 221 * Activity Action: Pick a Wi-Fi network to connect to. 222 * <p>Input: Nothing. 223 * <p>Output: Nothing. 224 */ 225 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 226 public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; 227 228 /** 229 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 230 * and will behave normally, i.e., it will attempt to automatically 231 * establish a connection to a remembered access point that is 232 * within range, and will do periodic scans if there are remembered 233 * access points but none are in range. 234 */ 235 public static final int WIFI_MODE_FULL = 1; 236 /** 237 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 238 * but the only operation that will be supported is initiation of 239 * scans, and the subsequent reporting of scan results. No attempts 240 * will be made to automatically connect to remembered access points, 241 * nor will periodic scans be automatically performed looking for 242 * remembered access points. Scans must be explicitly requested by 243 * an application in this mode. 244 */ 245 public static final int WIFI_MODE_SCAN_ONLY = 2; 246 247 /** Anything worse than or equal to this will show 0 bars. */ 248 private static final int MIN_RSSI = -100; 249 250 /** Anything better than or equal to this will show the max bars. */ 251 private static final int MAX_RSSI = -55; 252 253 IWifiManager mService; 254 Handler mHandler; 255 256 /* Maximum number of active locks we allow. 257 * This limit was added to prevent apps from creating a ridiculous number 258 * of locks and crashing the system by overflowing the global ref table. 259 */ 260 private static final int MAX_ACTIVE_LOCKS = 50; 261 262 /* Number of currently active WifiLocks and MulticastLocks */ 263 private int mActiveLockCount; 264 265 /** 266 * Create a new WifiManager instance. 267 * Applications will almost always want to use 268 * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve 269 * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. 270 * @param service the Binder interface 271 * @param handler target for messages 272 * @hide - hide this because it takes in a parameter of type IWifiManager, which 273 * is a system private class. 274 */ 275 public WifiManager(IWifiManager service, Handler handler) { 276 mService = service; 277 mHandler = handler; 278 } 279 280 /** 281 * Return a list of all the networks configured in the supplicant. 282 * Not all fields of WifiConfiguration are returned. Only the following 283 * fields are filled in: 284 * <ul> 285 * <li>networkId</li> 286 * <li>SSID</li> 287 * <li>BSSID</li> 288 * <li>priority</li> 289 * <li>allowedProtocols</li> 290 * <li>allowedKeyManagement</li> 291 * <li>allowedAuthAlgorithms</li> 292 * <li>allowedPairwiseCiphers</li> 293 * <li>allowedGroupCiphers</li> 294 * </ul> 295 * @return a list of network configurations in the form of a list 296 * of {@link WifiConfiguration} objects. 297 */ 298 public List<WifiConfiguration> getConfiguredNetworks() { 299 try { 300 return mService.getConfiguredNetworks(); 301 } catch (RemoteException e) { 302 return null; 303 } 304 } 305 306 /** 307 * Add a new network description to the set of configured networks. 308 * The {@code networkId} field of the supplied configuration object 309 * is ignored. 310 * <p/> 311 * The new network will be marked DISABLED by default. To enable it, 312 * called {@link #enableNetwork}. 313 * 314 * @param config the set of variables that describe the configuration, 315 * contained in a {@link WifiConfiguration} object. 316 * @return the ID of the newly created network description. This is used in 317 * other operations to specified the network to be acted upon. 318 * Returns {@code -1} on failure. 319 */ 320 public int addNetwork(WifiConfiguration config) { 321 if (config == null) { 322 return -1; 323 } 324 config.networkId = -1; 325 return addOrUpdateNetwork(config); 326 } 327 328 /** 329 * Update the network description of an existing configured network. 330 * 331 * @param config the set of variables that describe the configuration, 332 * contained in a {@link WifiConfiguration} object. It may 333 * be sparse, so that only the items that are being changed 334 * are non-<code>null</code>. The {@code networkId} field 335 * must be set to the ID of the existing network being updated. 336 * @return Returns the {@code networkId} of the supplied 337 * {@code WifiConfiguration} on success. 338 * <br/> 339 * Returns {@code -1} on failure, including when the {@code networkId} 340 * field of the {@code WifiConfiguration} does not refer to an 341 * existing network. 342 */ 343 public int updateNetwork(WifiConfiguration config) { 344 if (config == null || config.networkId < 0) { 345 return -1; 346 } 347 return addOrUpdateNetwork(config); 348 } 349 350 /** 351 * Internal method for doing the RPC that creates a new network description 352 * or updates an existing one. 353 * 354 * @param config The possibly sparse object containing the variables that 355 * are to set or updated in the network description. 356 * @return the ID of the network on success, {@code -1} on failure. 357 */ 358 private int addOrUpdateNetwork(WifiConfiguration config) { 359 try { 360 return mService.addOrUpdateNetwork(config); 361 } catch (RemoteException e) { 362 return -1; 363 } 364 } 365 366 /** 367 * Remove the specified network from the list of configured networks. 368 * This may result in the asynchronous delivery of state change 369 * events. 370 * @param netId the integer that identifies the network configuration 371 * to the supplicant 372 * @return {@code true} if the operation succeeded 373 */ 374 public boolean removeNetwork(int netId) { 375 try { 376 return mService.removeNetwork(netId); 377 } catch (RemoteException e) { 378 return false; 379 } 380 } 381 382 /** 383 * Allow a previously configured network to be associated with. If 384 * <code>disableOthers</code> is true, then all other configured 385 * networks are disabled, and an attempt to connect to the selected 386 * network is initiated. This may result in the asynchronous delivery 387 * of state change events. 388 * @param netId the ID of the network in the list of configured networks 389 * @param disableOthers if true, disable all other networks. The way to 390 * select a particular network to connect to is specify {@code true} 391 * for this parameter. 392 * @return {@code true} if the operation succeeded 393 */ 394 public boolean enableNetwork(int netId, boolean disableOthers) { 395 try { 396 return mService.enableNetwork(netId, disableOthers); 397 } catch (RemoteException e) { 398 return false; 399 } 400 } 401 402 /** 403 * Disable a configured network. The specified network will not be 404 * a candidate for associating. This may result in the asynchronous 405 * delivery of state change events. 406 * @param netId the ID of the network as returned by {@link #addNetwork}. 407 * @return {@code true} if the operation succeeded 408 */ 409 public boolean disableNetwork(int netId) { 410 try { 411 return mService.disableNetwork(netId); 412 } catch (RemoteException e) { 413 return false; 414 } 415 } 416 417 /** 418 * Disassociate from the currently active access point. This may result 419 * in the asynchronous delivery of state change events. 420 * @return {@code true} if the operation succeeded 421 */ 422 public boolean disconnect() { 423 try { 424 return mService.disconnect(); 425 } catch (RemoteException e) { 426 return false; 427 } 428 } 429 430 /** 431 * Reconnect to the currently active access point, if we are currently 432 * disconnected. This may result in the asynchronous delivery of state 433 * change events. 434 * @return {@code true} if the operation succeeded 435 */ 436 public boolean reconnect() { 437 try { 438 return mService.reconnect(); 439 } catch (RemoteException e) { 440 return false; 441 } 442 } 443 444 /** 445 * Reconnect to the currently active access point, even if we are already 446 * connected. This may result in the asynchronous delivery of state 447 * change events. 448 * @return {@code true} if the operation succeeded 449 */ 450 public boolean reassociate() { 451 try { 452 return mService.reassociate(); 453 } catch (RemoteException e) { 454 return false; 455 } 456 } 457 458 /** 459 * Check that the supplicant daemon is responding to requests. 460 * @return {@code true} if we were able to communicate with the supplicant and 461 * it returned the expected response to the PING message. 462 */ 463 public boolean pingSupplicant() { 464 if (mService == null) 465 return false; 466 try { 467 return mService.pingSupplicant(); 468 } catch (RemoteException e) { 469 return false; 470 } 471 } 472 473 /** 474 * Request a scan for access points. Returns immediately. The availability 475 * of the results is made known later by means of an asynchronous event sent 476 * on completion of the scan. 477 * @return {@code true} if the operation succeeded, i.e., the scan was initiated 478 */ 479 public boolean startScan() { 480 try { 481 return mService.startScan(false); 482 } catch (RemoteException e) { 483 return false; 484 } 485 } 486 487 /** 488 * Request a scan for access points. Returns immediately. The availability 489 * of the results is made known later by means of an asynchronous event sent 490 * on completion of the scan. 491 * This is a variant of startScan that forces an active scan, even if passive 492 * scans are the current default 493 * @return {@code true} if the operation succeeded, i.e., the scan was initiated 494 * 495 * @hide 496 */ 497 public boolean startScanActive() { 498 try { 499 return mService.startScan(true); 500 } catch (RemoteException e) { 501 return false; 502 } 503 } 504 505 /** 506 * Return dynamic information about the current Wi-Fi connection, if any is active. 507 * @return the Wi-Fi information, contained in {@link WifiInfo}. 508 */ 509 public WifiInfo getConnectionInfo() { 510 try { 511 return mService.getConnectionInfo(); 512 } catch (RemoteException e) { 513 return null; 514 } 515 } 516 517 /** 518 * Return the results of the latest access point scan. 519 * @return the list of access points found in the most recent scan. 520 */ 521 public List<ScanResult> getScanResults() { 522 try { 523 return mService.getScanResults(); 524 } catch (RemoteException e) { 525 return null; 526 } 527 } 528 529 /** 530 * Tell the supplicant to persist the current list of configured networks. 531 * <p> 532 * Note: It is possible for this method to change the network IDs of 533 * existing networks. You should assume the network IDs can be different 534 * after calling this method. 535 * 536 * @return {@code true} if the operation succeeded 537 */ 538 public boolean saveConfiguration() { 539 try { 540 return mService.saveConfiguration(); 541 } catch (RemoteException e) { 542 return false; 543 } 544 } 545 546 /** 547 * Return the number of frequency channels that are allowed 548 * to be used in the current regulatory domain. 549 * @return the number of allowed channels, or {@code -1} if an error occurs 550 * 551 * @hide pending API council 552 */ 553 public int getNumAllowedChannels() { 554 try { 555 return mService.getNumAllowedChannels(); 556 } catch (RemoteException e) { 557 return -1; 558 } 559 } 560 561 /** 562 * Set the number of frequency channels that are allowed to be used 563 * in the current regulatory domain. This method should be used only 564 * if the correct number of channels cannot be determined automatically 565 * for some reason. 566 * @param numChannels the number of allowed channels. Must be greater than 0 567 * and less than or equal to 16. 568 * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g., 569 * {@code numChannels} is out of range. 570 * 571 * @hide pending API council 572 */ 573 public boolean setNumAllowedChannels(int numChannels) { 574 try { 575 return mService.setNumAllowedChannels(numChannels); 576 } catch (RemoteException e) { 577 return false; 578 } 579 } 580 581 /** 582 * Return the list of valid values for the number of allowed radio channels 583 * for various regulatory domains. 584 * @return the list of channel counts, or {@code null} if the operation fails 585 * 586 * @hide pending API council review 587 */ 588 public int[] getValidChannelCounts() { 589 try { 590 return mService.getValidChannelCounts(); 591 } catch (RemoteException e) { 592 return null; 593 } 594 } 595 596 /** 597 * Return the DHCP-assigned addresses from the last successful DHCP request, 598 * if any. 599 * @return the DHCP information 600 */ 601 public DhcpInfo getDhcpInfo() { 602 try { 603 return mService.getDhcpInfo(); 604 } catch (RemoteException e) { 605 return null; 606 } 607 } 608 609 610 /** 611 * Enable or disable Wi-Fi. 612 * @param enabled {@code true} to enable, {@code false} to disable. 613 * @return {@code true} if the operation succeeds (or if the existing state 614 * is the same as the requested state). 615 */ 616 public boolean setWifiEnabled(boolean enabled) { 617 try { 618 return mService.setWifiEnabled(enabled); 619 } catch (RemoteException e) { 620 return false; 621 } 622 } 623 624 /** 625 * Gets the Wi-Fi enabled state. 626 * @return One of {@link #WIFI_STATE_DISABLED}, 627 * {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED}, 628 * {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN} 629 * @see #isWifiEnabled() 630 */ 631 public int getWifiState() { 632 try { 633 return mService.getWifiEnabledState(); 634 } catch (RemoteException e) { 635 return WIFI_STATE_UNKNOWN; 636 } 637 } 638 639 /** 640 * Return whether Wi-Fi is enabled or disabled. 641 * @return {@code true} if Wi-Fi is enabled 642 * @see #getWifiState() 643 */ 644 public boolean isWifiEnabled() { 645 return getWifiState() == WIFI_STATE_ENABLED; 646 } 647 648 /** 649 * Calculates the level of the signal. This should be used any time a signal 650 * is being shown. 651 * 652 * @param rssi The power of the signal measured in RSSI. 653 * @param numLevels The number of levels to consider in the calculated 654 * level. 655 * @return A level of the signal, given in the range of 0 to numLevels-1 656 * (both inclusive). 657 */ 658 public static int calculateSignalLevel(int rssi, int numLevels) { 659 if (rssi <= MIN_RSSI) { 660 return 0; 661 } else if (rssi >= MAX_RSSI) { 662 return numLevels - 1; 663 } else { 664 int partitionSize = (MAX_RSSI - MIN_RSSI) / (numLevels - 1); 665 return (rssi - MIN_RSSI) / partitionSize; 666 } 667 } 668 669 /** 670 * Compares two signal strengths. 671 * 672 * @param rssiA The power of the first signal measured in RSSI. 673 * @param rssiB The power of the second signal measured in RSSI. 674 * @return Returns <0 if the first signal is weaker than the second signal, 675 * 0 if the two signals have the same strength, and >0 if the first 676 * signal is stronger than the second signal. 677 */ 678 public static int compareSignalLevel(int rssiA, int rssiB) { 679 return rssiA - rssiB; 680 } 681 682 /** 683 * Allows an application to keep the Wi-Fi radio awake. 684 * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. 685 * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple 686 * applications may hold WifiLocks, and the radio will only be allowed to turn off when no 687 * WifiLocks are held in any application. 688 * 689 * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or 690 * could function over a mobile network, if available. A program that needs to download large 691 * files should hold a WifiLock to ensure that the download will complete, but a program whose 692 * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely 693 * affecting battery life. 694 * 695 * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane 696 * Mode. They simply keep the radio from turning off when Wi-Fi is already on but the device 697 * is idle. 698 */ 699 public class WifiLock { 700 private String mTag; 701 private final IBinder mBinder; 702 private int mRefCount; 703 int mLockType; 704 private boolean mRefCounted; 705 private boolean mHeld; 706 707 private WifiLock(int lockType, String tag) { 708 mTag = tag; 709 mLockType = lockType; 710 mBinder = new Binder(); 711 mRefCount = 0; 712 mRefCounted = true; 713 mHeld = false; 714 } 715 716 /** 717 * Locks the Wi-Fi radio on until {@link #release} is called. 718 * 719 * If this WifiLock is reference-counted, each call to {@code acquire} will increment the 720 * reference count, and the radio will remain locked as long as the reference count is 721 * above zero. 722 * 723 * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock 724 * the radio, but subsequent calls will be ignored. Only one call to {@link #release} 725 * will be required, regardless of the number of times that {@code acquire} is called. 726 */ 727 public void acquire() { 728 synchronized (mBinder) { 729 if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) { 730 try { 731 mService.acquireWifiLock(mBinder, mLockType, mTag); 732 synchronized (WifiManager.this) { 733 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 734 mService.releaseWifiLock(mBinder); 735 throw new UnsupportedOperationException( 736 "Exceeded maximum number of wifi locks"); 737 } 738 mActiveLockCount++; 739 } 740 } catch (RemoteException ignore) { 741 } 742 mHeld = true; 743 } 744 } 745 } 746 747 /** 748 * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle. 749 * 750 * If this WifiLock is reference-counted, each call to {@code release} will decrement the 751 * reference count, and the radio will be unlocked only when the reference count reaches 752 * zero. If the reference count goes below zero (that is, if {@code release} is called 753 * a greater number of times than {@link #acquire}), an exception is thrown. 754 * 755 * If this WifiLock is not reference-counted, the first call to {@code release} (after 756 * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent 757 * calls will be ignored. 758 */ 759 public void release() { 760 synchronized (mBinder) { 761 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 762 try { 763 mService.releaseWifiLock(mBinder); 764 synchronized (WifiManager.this) { 765 mActiveLockCount--; 766 } 767 } catch (RemoteException ignore) { 768 } 769 mHeld = false; 770 } 771 if (mRefCount < 0) { 772 throw new RuntimeException("WifiLock under-locked " + mTag); 773 } 774 } 775 } 776 777 /** 778 * Controls whether this is a reference-counted or non-reference-counted WifiLock. 779 * 780 * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and 781 * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire} 782 * has been balanced with a call to {@link #release}. Non-reference-counted WifiLocks 783 * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the 784 * radio whenever {@link #release} is called and it is locked. 785 * 786 * @param refCounted true if this WifiLock should keep a reference count 787 */ 788 public void setReferenceCounted(boolean refCounted) { 789 mRefCounted = refCounted; 790 } 791 792 /** 793 * Checks whether this WifiLock is currently held. 794 * 795 * @return true if this WifiLock is held, false otherwise 796 */ 797 public boolean isHeld() { 798 synchronized (mBinder) { 799 return mHeld; 800 } 801 } 802 803 public String toString() { 804 String s1, s2, s3; 805 synchronized (mBinder) { 806 s1 = Integer.toHexString(System.identityHashCode(this)); 807 s2 = mHeld ? "held; " : ""; 808 if (mRefCounted) { 809 s3 = "refcounted: refcount = " + mRefCount; 810 } else { 811 s3 = "not refcounted"; 812 } 813 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }"; 814 } 815 } 816 817 @Override 818 protected void finalize() throws Throwable { 819 super.finalize(); 820 synchronized (mBinder) { 821 if (mHeld) { 822 try { 823 mService.releaseWifiLock(mBinder); 824 synchronized (WifiManager.this) { 825 mActiveLockCount--; 826 } 827 } catch (RemoteException ignore) { 828 } 829 } 830 } 831 } 832 } 833 834 /** 835 * Creates a new WifiLock. 836 * 837 * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL} and 838 * {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks. 839 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 840 * never shown to the user under normal conditions, but should be descriptive 841 * enough to identify your application and the specific WifiLock within it, if it 842 * holds multiple WifiLocks. 843 * 844 * @return a new, unacquired WifiLock with the given tag. 845 * 846 * @see WifiLock 847 */ 848 public WifiLock createWifiLock(int lockType, String tag) { 849 return new WifiLock(lockType, tag); 850 } 851 852 /** 853 * Creates a new WifiLock. 854 * 855 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 856 * never shown to the user under normal conditions, but should be descriptive 857 * enough to identify your application and the specific WifiLock within it, if it 858 * holds multiple WifiLocks. 859 * 860 * @return a new, unacquired WifiLock with the given tag. 861 * 862 * @see WifiLock 863 */ 864 public WifiLock createWifiLock(String tag) { 865 return new WifiLock(WIFI_MODE_FULL, tag); 866 } 867 868 869 /** 870 * Create a new MulticastLock 871 * 872 * @param tag a tag for the MulticastLock to identify it in debugging 873 * messages. 874 * 875 * @return a new, unacquired MulticastLock with the given tag. 876 * 877 * @see MulticastLock 878 */ 879 public MulticastLock createMulticastLock(String tag) { 880 return new MulticastLock(tag); 881 } 882 883 /** 884 * Allows an application to receive Wifi Multicast packets. 885 * Normally the Wifi stack filters out packets not explicitly 886 * addressed to this device. Acquring a MulticastLock will 887 * cause the stack to receive packets addressed to multicast 888 * addresses. Processing these extra packets can cause a noticable 889 * battery drain and should be disabled when not needed 890 */ 891 public class MulticastLock { 892 private String mTag; 893 private final IBinder mBinder; 894 private boolean mHeld; 895 896 private MulticastLock(String tag) { 897 mTag = tag; 898 mBinder = new Binder(); 899 mHeld = false; 900 } 901 902 /** 903 * Locks Wifi Multicast on until {@link #release} is called. 904 * 905 * The first call to {@code acquire} will lock the Multicast on 906 * but subsequent calls will be ignored. Only one call to 907 * {@link #release} will be required, regardless of the number of 908 * times that {@code acquire} is called. 909 * 910 * Note that other applications may also lock Wifi Multicast on. 911 * Only they can relinquish their lock. 912 * 913 * Also note that applications cannot leave Multicast locked on. 914 * When an app exits or crashes, any Multicast locks will be released. 915 */ 916 public void acquire() { 917 synchronized (mBinder) { 918 if (!mHeld) { 919 try { 920 mService.acquireMulticastLock(mBinder, mTag); 921 synchronized (WifiManager.this) { 922 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 923 mService.releaseMulticastLock(); 924 throw new UnsupportedOperationException( 925 "Exceeded maximum number of wifi locks"); 926 } 927 mActiveLockCount++; 928 } 929 mHeld = true; 930 } catch (RemoteException ignore) { 931 } 932 } 933 } 934 } 935 936 /** 937 * Unlocks Wifi Multicast, restoring the filter of packets 938 * not addressed specifically to this device and saving power. 939 * 940 * Note that if any other Wifi Multicast Locks are still outstanding 941 * this {@code release} call will not have an immediate effect. Only 942 * when all applications have released all their Multicast Locks will 943 * the Multicast filter be turned back on. 944 * 945 * Also note that when an app exits or crashes all of its Multicast 946 * Locks will be automatically released. 947 */ 948 public void release() { 949 synchronized (mBinder) { 950 if (mHeld) { 951 try { 952 mService.releaseMulticastLock(); 953 synchronized (WifiManager.this) { 954 mActiveLockCount--; 955 } 956 mHeld = false; 957 } catch (RemoteException ignore) { 958 } 959 } 960 } 961 } 962 963 /** 964 * Checks whether this MulticastLock is currently held. 965 * 966 * @return true if this MulticastLock is held, false otherwise 967 */ 968 public boolean isHeld() { 969 synchronized (mBinder) { 970 return mHeld; 971 } 972 } 973 974 public String toString() { 975 String s1, s2; 976 synchronized (mBinder) { 977 s1 = Integer.toHexString(System.identityHashCode(this)); 978 s2 = mHeld ? "held; " : ""; 979 return "MulticastLock{ " + s1 + "; " + s2 + " }"; 980 } 981 } 982 983 @Override 984 protected void finalize() throws Throwable { 985 super.finalize(); 986 release(); 987 } 988 } 989 990 /** 991 * Check multicast filter status. 992 * 993 * @return true if multicast packets are allowed. 994 * 995 * @hide pending API council approval 996 */ 997 public boolean isMulticastEnabled() { 998 try { 999 return mService.isMulticastEnabled(); 1000 } catch (RemoteException e) { 1001 return false; 1002 } 1003 } 1004} 1005