WifiManager.java revision 4a51c20ce607c74914f90fd897f04080121ac13b
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 * @param persist {@code true} if you want this remembered 569 * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g., 570 * {@code numChannels} is out of range. 571 * 572 * @hide pending API council 573 */ 574 public boolean setNumAllowedChannels(int numChannels, boolean persist) { 575 try { 576 return mService.setNumAllowedChannels(numChannels, persist); 577 } catch (RemoteException e) { 578 return false; 579 } 580 } 581 582 /** 583 * Return the list of valid values for the number of allowed radio channels 584 * for various regulatory domains. 585 * @return the list of channel counts, or {@code null} if the operation fails 586 * 587 * @hide pending API council review 588 */ 589 public int[] getValidChannelCounts() { 590 try { 591 return mService.getValidChannelCounts(); 592 } catch (RemoteException e) { 593 return null; 594 } 595 } 596 597 /** 598 * Return the DHCP-assigned addresses from the last successful DHCP request, 599 * if any. 600 * @return the DHCP information 601 */ 602 public DhcpInfo getDhcpInfo() { 603 try { 604 return mService.getDhcpInfo(); 605 } catch (RemoteException e) { 606 return null; 607 } 608 } 609 610 611 /** 612 * Enable or disable Wi-Fi. 613 * @param enabled {@code true} to enable, {@code false} to disable. 614 * @return {@code true} if the operation succeeds (or if the existing state 615 * is the same as the requested state). 616 */ 617 public boolean setWifiEnabled(boolean enabled) { 618 try { 619 return mService.setWifiEnabled(enabled); 620 } catch (RemoteException e) { 621 return false; 622 } 623 } 624 625 /** 626 * Gets the Wi-Fi enabled state. 627 * @return One of {@link #WIFI_STATE_DISABLED}, 628 * {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED}, 629 * {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN} 630 * @see #isWifiEnabled() 631 */ 632 public int getWifiState() { 633 try { 634 return mService.getWifiEnabledState(); 635 } catch (RemoteException e) { 636 return WIFI_STATE_UNKNOWN; 637 } 638 } 639 640 /** 641 * Return whether Wi-Fi is enabled or disabled. 642 * @return {@code true} if Wi-Fi is enabled 643 * @see #getWifiState() 644 */ 645 public boolean isWifiEnabled() { 646 return getWifiState() == WIFI_STATE_ENABLED; 647 } 648 649 /** 650 * Calculates the level of the signal. This should be used any time a signal 651 * is being shown. 652 * 653 * @param rssi The power of the signal measured in RSSI. 654 * @param numLevels The number of levels to consider in the calculated 655 * level. 656 * @return A level of the signal, given in the range of 0 to numLevels-1 657 * (both inclusive). 658 */ 659 public static int calculateSignalLevel(int rssi, int numLevels) { 660 if (rssi <= MIN_RSSI) { 661 return 0; 662 } else if (rssi >= MAX_RSSI) { 663 return numLevels - 1; 664 } else { 665 int partitionSize = (MAX_RSSI - MIN_RSSI) / (numLevels - 1); 666 return (rssi - MIN_RSSI) / partitionSize; 667 } 668 } 669 670 /** 671 * Compares two signal strengths. 672 * 673 * @param rssiA The power of the first signal measured in RSSI. 674 * @param rssiB The power of the second signal measured in RSSI. 675 * @return Returns <0 if the first signal is weaker than the second signal, 676 * 0 if the two signals have the same strength, and >0 if the first 677 * signal is stronger than the second signal. 678 */ 679 public static int compareSignalLevel(int rssiA, int rssiB) { 680 return rssiA - rssiB; 681 } 682 683 /** 684 * Allows an application to keep the Wi-Fi radio awake. 685 * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. 686 * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple 687 * applications may hold WifiLocks, and the radio will only be allowed to turn off when no 688 * WifiLocks are held in any application. 689 * 690 * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or 691 * could function over a mobile network, if available. A program that needs to download large 692 * files should hold a WifiLock to ensure that the download will complete, but a program whose 693 * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely 694 * affecting battery life. 695 * 696 * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane 697 * Mode. They simply keep the radio from turning off when Wi-Fi is already on but the device 698 * is idle. 699 */ 700 public class WifiLock { 701 private String mTag; 702 private final IBinder mBinder; 703 private int mRefCount; 704 int mLockType; 705 private boolean mRefCounted; 706 private boolean mHeld; 707 708 private WifiLock(int lockType, String tag) { 709 mTag = tag; 710 mLockType = lockType; 711 mBinder = new Binder(); 712 mRefCount = 0; 713 mRefCounted = true; 714 mHeld = false; 715 } 716 717 /** 718 * Locks the Wi-Fi radio on until {@link #release} is called. 719 * 720 * If this WifiLock is reference-counted, each call to {@code acquire} will increment the 721 * reference count, and the radio will remain locked as long as the reference count is 722 * above zero. 723 * 724 * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock 725 * the radio, but subsequent calls will be ignored. Only one call to {@link #release} 726 * will be required, regardless of the number of times that {@code acquire} is called. 727 */ 728 public void acquire() { 729 synchronized (mBinder) { 730 if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) { 731 try { 732 mService.acquireWifiLock(mBinder, mLockType, mTag); 733 synchronized (WifiManager.this) { 734 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 735 mService.releaseWifiLock(mBinder); 736 throw new UnsupportedOperationException( 737 "Exceeded maximum number of wifi locks"); 738 } 739 mActiveLockCount++; 740 } 741 } catch (RemoteException ignore) { 742 } 743 mHeld = true; 744 } 745 } 746 } 747 748 /** 749 * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle. 750 * 751 * If this WifiLock is reference-counted, each call to {@code release} will decrement the 752 * reference count, and the radio will be unlocked only when the reference count reaches 753 * zero. If the reference count goes below zero (that is, if {@code release} is called 754 * a greater number of times than {@link #acquire}), an exception is thrown. 755 * 756 * If this WifiLock is not reference-counted, the first call to {@code release} (after 757 * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent 758 * calls will be ignored. 759 */ 760 public void release() { 761 synchronized (mBinder) { 762 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 763 try { 764 mService.releaseWifiLock(mBinder); 765 synchronized (WifiManager.this) { 766 mActiveLockCount--; 767 } 768 } catch (RemoteException ignore) { 769 } 770 mHeld = false; 771 } 772 if (mRefCount < 0) { 773 throw new RuntimeException("WifiLock under-locked " + mTag); 774 } 775 } 776 } 777 778 /** 779 * Controls whether this is a reference-counted or non-reference-counted WifiLock. 780 * 781 * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and 782 * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire} 783 * has been balanced with a call to {@link #release}. Non-reference-counted WifiLocks 784 * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the 785 * radio whenever {@link #release} is called and it is locked. 786 * 787 * @param refCounted true if this WifiLock should keep a reference count 788 */ 789 public void setReferenceCounted(boolean refCounted) { 790 mRefCounted = refCounted; 791 } 792 793 /** 794 * Checks whether this WifiLock is currently held. 795 * 796 * @return true if this WifiLock is held, false otherwise 797 */ 798 public boolean isHeld() { 799 synchronized (mBinder) { 800 return mHeld; 801 } 802 } 803 804 public String toString() { 805 String s1, s2, s3; 806 synchronized (mBinder) { 807 s1 = Integer.toHexString(System.identityHashCode(this)); 808 s2 = mHeld ? "held; " : ""; 809 if (mRefCounted) { 810 s3 = "refcounted: refcount = " + mRefCount; 811 } else { 812 s3 = "not refcounted"; 813 } 814 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }"; 815 } 816 } 817 818 @Override 819 protected void finalize() throws Throwable { 820 super.finalize(); 821 synchronized (mBinder) { 822 if (mHeld) { 823 try { 824 mService.releaseWifiLock(mBinder); 825 synchronized (WifiManager.this) { 826 mActiveLockCount--; 827 } 828 } catch (RemoteException ignore) { 829 } 830 } 831 } 832 } 833 } 834 835 /** 836 * Creates a new WifiLock. 837 * 838 * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL} and 839 * {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks. 840 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 841 * never shown to the user under normal conditions, but should be descriptive 842 * enough to identify your application and the specific WifiLock within it, if it 843 * holds multiple WifiLocks. 844 * 845 * @return a new, unacquired WifiLock with the given tag. 846 * 847 * @see WifiLock 848 */ 849 public WifiLock createWifiLock(int lockType, String tag) { 850 return new WifiLock(lockType, tag); 851 } 852 853 /** 854 * Creates a new WifiLock. 855 * 856 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 857 * never shown to the user under normal conditions, but should be descriptive 858 * enough to identify your application and the specific WifiLock within it, if it 859 * holds multiple WifiLocks. 860 * 861 * @return a new, unacquired WifiLock with the given tag. 862 * 863 * @see WifiLock 864 */ 865 public WifiLock createWifiLock(String tag) { 866 return new WifiLock(WIFI_MODE_FULL, tag); 867 } 868 869 870 /** 871 * Create a new MulticastLock 872 * 873 * @param tag a tag for the MulticastLock to identify it in debugging 874 * messages. This string is never shown to the user under 875 * normal conditions, but should be descriptive enough to 876 * identify your application and the specific MulticastLock 877 * within it, if it holds multiple MulticastLocks. 878 * 879 * @return a new, unacquired MulticastLock with the given tag. 880 * 881 * @see MulticastLock 882 */ 883 public MulticastLock createMulticastLock(String tag) { 884 return new MulticastLock(tag); 885 } 886 887 /** 888 * Allows an application to receive Wifi Multicast packets. 889 * Normally the Wifi stack filters out packets not explicitly 890 * addressed to this device. Acquring a MulticastLock will 891 * cause the stack to receive packets addressed to multicast 892 * addresses. Processing these extra packets can cause a noticable 893 * battery drain and should be disabled when not needed. 894 */ 895 public class MulticastLock { 896 private String mTag; 897 private final IBinder mBinder; 898 private int mRefCount; 899 private boolean mRefCounted; 900 private boolean mHeld; 901 902 private MulticastLock(String tag) { 903 mTag = tag; 904 mBinder = new Binder(); 905 mRefCount = 0; 906 mRefCounted = true; 907 mHeld = false; 908 } 909 910 /** 911 * Locks Wifi Multicast on until {@link #release} is called. 912 * 913 * If this MulticastLock is reference-counted each call to 914 * {@code acquire} will increment the reference count, and the 915 * wifi interface will receive multicast packets as long as the 916 * reference count is above zero. 917 * 918 * If this MulticastLock is not reference-counted, the first call to 919 * {@code acquire} will turn on the multicast packets, but subsequent 920 * calls will be ignored. Only one call to {@link #release} will 921 * be required, regardless of the number of times that {@code acquire} 922 * is called. 923 * 924 * Note that other applications may also lock Wifi Multicast on. 925 * Only they can relinquish their lock. 926 * 927 * Also note that applications cannot leave Multicast locked on. 928 * When an app exits or crashes, any Multicast locks will be released. 929 */ 930 public void acquire() { 931 synchronized (mBinder) { 932 if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) { 933 try { 934 mService.acquireMulticastLock(mBinder, mTag); 935 synchronized (WifiManager.this) { 936 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 937 mService.releaseMulticastLock(); 938 throw new UnsupportedOperationException( 939 "Exceeded maximum number of wifi locks"); 940 } 941 mActiveLockCount++; 942 } 943 } catch (RemoteException ignore) { 944 } 945 mHeld = true; 946 } 947 } 948 } 949 950 /** 951 * Unlocks Wifi Multicast, restoring the filter of packets 952 * not addressed specifically to this device and saving power. 953 * 954 * If this MulticastLock is reference-counted, each call to 955 * {@code release} will decrement the reference count, and the 956 * multicast packets will only stop being received when the reference 957 * count reaches zero. If the reference count goes below zero (that 958 * is, if {@code release} is called a greater number of times than 959 * {@link #acquire}), an exception is thrown. 960 * 961 * If this MulticastLock is not reference-counted, the first call to 962 * {@code release} (after the radio was multicast locked using 963 * {@link #acquire}) will unlock the multicast, and subsequent calls 964 * will be ignored. 965 * 966 * Note that if any other Wifi Multicast Locks are still outstanding 967 * this {@code release} call will not have an immediate effect. Only 968 * when all applications have released all their Multicast Locks will 969 * the Multicast filter be turned back on. 970 * 971 * Also note that when an app exits or crashes all of its Multicast 972 * Locks will be automatically released. 973 */ 974 public void release() { 975 synchronized (mBinder) { 976 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 977 try { 978 mService.releaseMulticastLock(); 979 synchronized (WifiManager.this) { 980 mActiveLockCount--; 981 } 982 } catch (RemoteException ignore) { 983 } 984 mHeld = false; 985 } 986 if (mRefCount < 0) { 987 throw new RuntimeException("MulticastLock under-locked " 988 + mTag); 989 } 990 } 991 } 992 993 /** 994 * Controls whether this is a reference-counted or non-reference- 995 * counted MulticastLock. 996 * 997 * Reference-counted MulticastLocks keep track of the number of calls 998 * to {@link #acquire} and {@link #release}, and only stop the 999 * reception of multicast packets when every call to {@link #acquire} 1000 * has been balanced with a call to {@link #release}. Non-reference- 1001 * counted MulticastLocks allow the reception of multicast packets 1002 * whenever {@link #acquire} is called and stop accepting multicast 1003 * packets whenever {@link #release} is called. 1004 * 1005 * @param refCounted true if this MulticastLock should keep a reference 1006 * count 1007 */ 1008 public void setReferenceCounted(boolean refCounted) { 1009 mRefCounted = refCounted; 1010 } 1011 1012 /** 1013 * Checks whether this MulticastLock is currently held. 1014 * 1015 * @return true if this MulticastLock is held, false otherwise 1016 */ 1017 public boolean isHeld() { 1018 synchronized (mBinder) { 1019 return mHeld; 1020 } 1021 } 1022 1023 public String toString() { 1024 String s1, s2, s3; 1025 synchronized (mBinder) { 1026 s1 = Integer.toHexString(System.identityHashCode(this)); 1027 s2 = mHeld ? "held; " : ""; 1028 if (mRefCounted) { 1029 s3 = "refcounted: refcount = " + mRefCount; 1030 } else { 1031 s3 = "not refcounted"; 1032 } 1033 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }"; 1034 } 1035 } 1036 1037 @Override 1038 protected void finalize() throws Throwable { 1039 super.finalize(); 1040 setReferenceCounted(false); 1041 release(); 1042 } 1043 } 1044 1045 /** 1046 * Check multicast filter status. 1047 * 1048 * @return true if multicast packets are allowed. 1049 * 1050 * @hide pending API council approval 1051 */ 1052 public boolean isMulticastEnabled() { 1053 try { 1054 return mService.isMulticastEnabled(); 1055 } catch (RemoteException e) { 1056 return false; 1057 } 1058 } 1059} 1060