WifiManager.java revision fca3ae1517b19c3cd40b761cd4bc134e98c0c565
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(); 482 } catch (RemoteException e) { 483 return false; 484 } 485 } 486 487 /** 488 * Return dynamic information about the current Wi-Fi connection, if any is active. 489 * @return the Wi-Fi information, contained in {@link WifiInfo}. 490 */ 491 public WifiInfo getConnectionInfo() { 492 try { 493 return mService.getConnectionInfo(); 494 } catch (RemoteException e) { 495 return null; 496 } 497 } 498 499 /** 500 * Return the results of the latest access point scan. 501 * @return the list of access points found in the most recent scan. 502 */ 503 public List<ScanResult> getScanResults() { 504 try { 505 return mService.getScanResults(); 506 } catch (RemoteException e) { 507 return null; 508 } 509 } 510 511 /** 512 * Tell the supplicant to persist the current list of configured networks. 513 * <p> 514 * Note: It is possible for this method to change the network IDs of 515 * existing networks. You should assume the network IDs can be different 516 * after calling this method. 517 * 518 * @return {@code true} if the operation succeeded 519 */ 520 public boolean saveConfiguration() { 521 try { 522 return mService.saveConfiguration(); 523 } catch (RemoteException e) { 524 return false; 525 } 526 } 527 528 /** 529 * Return the number of frequency channels that are allowed 530 * to be used in the current regulatory domain. 531 * @return the number of allowed channels, or {@code -1} if an error occurs 532 * 533 * @hide pending API council 534 */ 535 public int getNumAllowedChannels() { 536 try { 537 return mService.getNumAllowedChannels(); 538 } catch (RemoteException e) { 539 return -1; 540 } 541 } 542 543 /** 544 * Set the number of frequency channels that are allowed to be used 545 * in the current regulatory domain. This method should be used only 546 * if the correct number of channels cannot be determined automatically 547 * for some reason. 548 * @param numChannels the number of allowed channels. Must be greater than 0 549 * and less than or equal to 16. 550 * @param persist {@code true} if you want this remembered 551 * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g., 552 * {@code numChannels} is out of range. 553 * 554 * @hide pending API council 555 */ 556 public boolean setNumAllowedChannels(int numChannels, boolean persist) { 557 try { 558 return mService.setNumAllowedChannels(numChannels, persist); 559 } catch (RemoteException e) { 560 return false; 561 } 562 } 563 564 /** 565 * Return the list of valid values for the number of allowed radio channels 566 * for various regulatory domains. 567 * @return the list of channel counts, or {@code null} if the operation fails 568 * 569 * @hide pending API council review 570 */ 571 public int[] getValidChannelCounts() { 572 try { 573 return mService.getValidChannelCounts(); 574 } catch (RemoteException e) { 575 return null; 576 } 577 } 578 579 /** 580 * Return the DHCP-assigned addresses from the last successful DHCP request, 581 * if any. 582 * @return the DHCP information 583 */ 584 public DhcpInfo getDhcpInfo() { 585 try { 586 return mService.getDhcpInfo(); 587 } catch (RemoteException e) { 588 return null; 589 } 590 } 591 592 593 /** 594 * Enable or disable Wi-Fi. 595 * @param enabled {@code true} to enable, {@code false} to disable. 596 * @return {@code true} if the operation succeeds (or if the existing state 597 * is the same as the requested state). 598 */ 599 public boolean setWifiEnabled(boolean enabled) { 600 try { 601 return mService.setWifiEnabled(enabled); 602 } catch (RemoteException e) { 603 return false; 604 } 605 } 606 607 /** 608 * Gets the Wi-Fi enabled state. 609 * @return One of {@link #WIFI_STATE_DISABLED}, 610 * {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED}, 611 * {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN} 612 * @see #isWifiEnabled() 613 */ 614 public int getWifiState() { 615 try { 616 return mService.getWifiEnabledState(); 617 } catch (RemoteException e) { 618 return WIFI_STATE_UNKNOWN; 619 } 620 } 621 622 /** 623 * Return whether Wi-Fi is enabled or disabled. 624 * @return {@code true} if Wi-Fi is enabled 625 * @see #getWifiState() 626 */ 627 public boolean isWifiEnabled() { 628 return getWifiState() == WIFI_STATE_ENABLED; 629 } 630 631 /** 632 * Calculates the level of the signal. This should be used any time a signal 633 * is being shown. 634 * 635 * @param rssi The power of the signal measured in RSSI. 636 * @param numLevels The number of levels to consider in the calculated 637 * level. 638 * @return A level of the signal, given in the range of 0 to numLevels-1 639 * (both inclusive). 640 */ 641 public static int calculateSignalLevel(int rssi, int numLevels) { 642 if (rssi <= MIN_RSSI) { 643 return 0; 644 } else if (rssi >= MAX_RSSI) { 645 return numLevels - 1; 646 } else { 647 int partitionSize = (MAX_RSSI - MIN_RSSI) / (numLevels - 1); 648 return (rssi - MIN_RSSI) / partitionSize; 649 } 650 } 651 652 /** 653 * Compares two signal strengths. 654 * 655 * @param rssiA The power of the first signal measured in RSSI. 656 * @param rssiB The power of the second signal measured in RSSI. 657 * @return Returns <0 if the first signal is weaker than the second signal, 658 * 0 if the two signals have the same strength, and >0 if the first 659 * signal is stronger than the second signal. 660 */ 661 public static int compareSignalLevel(int rssiA, int rssiB) { 662 return rssiA - rssiB; 663 } 664 665 /** 666 * Allows an application to keep the Wi-Fi radio awake. 667 * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. 668 * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple 669 * applications may hold WifiLocks, and the radio will only be allowed to turn off when no 670 * WifiLocks are held in any application. 671 * 672 * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or 673 * could function over a mobile network, if available. A program that needs to download large 674 * files should hold a WifiLock to ensure that the download will complete, but a program whose 675 * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely 676 * affecting battery life. 677 * 678 * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane 679 * Mode. They simply keep the radio from turning off when Wi-Fi is already on but the device 680 * is idle. 681 */ 682 public class WifiLock { 683 private String mTag; 684 private final IBinder mBinder; 685 private int mRefCount; 686 int mLockType; 687 private boolean mRefCounted; 688 private boolean mHeld; 689 690 private WifiLock(int lockType, String tag) { 691 mTag = tag; 692 mLockType = lockType; 693 mBinder = new Binder(); 694 mRefCount = 0; 695 mRefCounted = true; 696 mHeld = false; 697 } 698 699 /** 700 * Locks the Wi-Fi radio on until {@link #release} is called. 701 * 702 * If this WifiLock is reference-counted, each call to {@code acquire} will increment the 703 * reference count, and the radio will remain locked as long as the reference count is 704 * above zero. 705 * 706 * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock 707 * the radio, but subsequent calls will be ignored. Only one call to {@link #release} 708 * will be required, regardless of the number of times that {@code acquire} is called. 709 */ 710 public void acquire() { 711 synchronized (mBinder) { 712 if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) { 713 try { 714 mService.acquireWifiLock(mBinder, mLockType, mTag); 715 synchronized (WifiManager.this) { 716 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 717 mService.releaseWifiLock(mBinder); 718 throw new UnsupportedOperationException( 719 "Exceeded maximum number of wifi locks"); 720 } 721 mActiveLockCount++; 722 } 723 } catch (RemoteException ignore) { 724 } 725 mHeld = true; 726 } 727 } 728 } 729 730 /** 731 * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle. 732 * 733 * If this WifiLock is reference-counted, each call to {@code release} will decrement the 734 * reference count, and the radio will be unlocked only when the reference count reaches 735 * zero. If the reference count goes below zero (that is, if {@code release} is called 736 * a greater number of times than {@link #acquire}), an exception is thrown. 737 * 738 * If this WifiLock is not reference-counted, the first call to {@code release} (after 739 * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent 740 * calls will be ignored. 741 */ 742 public void release() { 743 synchronized (mBinder) { 744 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 745 try { 746 mService.releaseWifiLock(mBinder); 747 synchronized (WifiManager.this) { 748 mActiveLockCount--; 749 } 750 } catch (RemoteException ignore) { 751 } 752 mHeld = false; 753 } 754 if (mRefCount < 0) { 755 throw new RuntimeException("WifiLock under-locked " + mTag); 756 } 757 } 758 } 759 760 /** 761 * Controls whether this is a reference-counted or non-reference-counted WifiLock. 762 * 763 * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and 764 * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire} 765 * has been balanced with a call to {@link #release}. Non-reference-counted WifiLocks 766 * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the 767 * radio whenever {@link #release} is called and it is locked. 768 * 769 * @param refCounted true if this WifiLock should keep a reference count 770 */ 771 public void setReferenceCounted(boolean refCounted) { 772 mRefCounted = refCounted; 773 } 774 775 /** 776 * Checks whether this WifiLock is currently held. 777 * 778 * @return true if this WifiLock is held, false otherwise 779 */ 780 public boolean isHeld() { 781 synchronized (mBinder) { 782 return mHeld; 783 } 784 } 785 786 public String toString() { 787 String s1, s2, s3; 788 synchronized (mBinder) { 789 s1 = Integer.toHexString(System.identityHashCode(this)); 790 s2 = mHeld ? "held; " : ""; 791 if (mRefCounted) { 792 s3 = "refcounted: refcount = " + mRefCount; 793 } else { 794 s3 = "not refcounted"; 795 } 796 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }"; 797 } 798 } 799 800 @Override 801 protected void finalize() throws Throwable { 802 super.finalize(); 803 synchronized (mBinder) { 804 if (mHeld) { 805 try { 806 mService.releaseWifiLock(mBinder); 807 synchronized (WifiManager.this) { 808 mActiveLockCount--; 809 } 810 } catch (RemoteException ignore) { 811 } 812 } 813 } 814 } 815 } 816 817 /** 818 * Creates a new WifiLock. 819 * 820 * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL} and 821 * {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks. 822 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 823 * never shown to the user under normal conditions, but should be descriptive 824 * enough to identify your application and the specific WifiLock within it, if it 825 * holds multiple WifiLocks. 826 * 827 * @return a new, unacquired WifiLock with the given tag. 828 * 829 * @see WifiLock 830 */ 831 public WifiLock createWifiLock(int lockType, String tag) { 832 return new WifiLock(lockType, tag); 833 } 834 835 /** 836 * Creates a new WifiLock. 837 * 838 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 839 * never shown to the user under normal conditions, but should be descriptive 840 * enough to identify your application and the specific WifiLock within it, if it 841 * holds multiple WifiLocks. 842 * 843 * @return a new, unacquired WifiLock with the given tag. 844 * 845 * @see WifiLock 846 */ 847 public WifiLock createWifiLock(String tag) { 848 return new WifiLock(WIFI_MODE_FULL, tag); 849 } 850 851 852 /** 853 * Create a new MulticastLock 854 * 855 * @param tag a tag for the MulticastLock to identify it in debugging 856 * messages. 857 * 858 * @return a new, unacquired MulticastLock with the given tag. 859 * 860 * @see MulticastLock 861 */ 862 public MulticastLock createMulticastLock(String tag) { 863 return new MulticastLock(tag); 864 } 865 866 /** 867 * Allows an application to receive Wifi Multicast packets. 868 * Normally the Wifi stack filters out packets not explicitly 869 * addressed to this device. Acquring a MulticastLock will 870 * cause the stack to receive packets addressed to multicast 871 * addresses. Processing these extra packets can cause a noticable 872 * battery drain and should be disabled when not needed 873 */ 874 public class MulticastLock { 875 private String mTag; 876 private final IBinder mBinder; 877 private boolean mHeld; 878 879 private MulticastLock(String tag) { 880 mTag = tag; 881 mBinder = new Binder(); 882 mHeld = false; 883 } 884 885 /** 886 * Locks Wifi Multicast on until {@link #release} is called. 887 * 888 * The first call to {@code acquire} will lock the Multicast on 889 * but subsequent calls will be ignored. Only one call to 890 * {@link #release} will be required, regardless of the number of 891 * times that {@code acquire} is called. 892 * 893 * Note that other applications may also lock Wifi Multicast on. 894 * Only they can relinquish their lock. 895 * 896 * Also note that applications cannot leave Multicast locked on. 897 * When an app exits or crashes, any Multicast locks will be released. 898 */ 899 public void acquire() { 900 synchronized (mBinder) { 901 if (!mHeld) { 902 try { 903 mService.acquireMulticastLock(mBinder, mTag); 904 synchronized (WifiManager.this) { 905 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 906 mService.releaseMulticastLock(); 907 throw new UnsupportedOperationException( 908 "Exceeded maximum number of wifi locks"); 909 } 910 mActiveLockCount++; 911 } 912 mHeld = true; 913 } catch (RemoteException ignore) { 914 } 915 } 916 } 917 } 918 919 /** 920 * Unlocks Wifi Multicast, restoring the filter of packets 921 * not addressed specifically to this device and saving power. 922 * 923 * Note that if any other Wifi Multicast Locks are still outstanding 924 * this {@code release} call will not have an immediate effect. Only 925 * when all applications have released all their Multicast Locks will 926 * the Multicast filter be turned back on. 927 * 928 * Also note that when an app exits or crashes all of its Multicast 929 * Locks will be automatically released. 930 */ 931 public void release() { 932 synchronized (mBinder) { 933 if (mHeld) { 934 try { 935 mService.releaseMulticastLock(); 936 synchronized (WifiManager.this) { 937 mActiveLockCount--; 938 } 939 mHeld = false; 940 } catch (RemoteException ignore) { 941 } 942 } 943 } 944 } 945 946 /** 947 * Checks whether this MulticastLock is currently held. 948 * 949 * @return true if this MulticastLock is held, false otherwise 950 */ 951 public boolean isHeld() { 952 synchronized (mBinder) { 953 return mHeld; 954 } 955 } 956 957 public String toString() { 958 String s1, s2; 959 synchronized (mBinder) { 960 s1 = Integer.toHexString(System.identityHashCode(this)); 961 s2 = mHeld ? "held; " : ""; 962 return "MulticastLock{ " + s1 + "; " + s2 + " }"; 963 } 964 } 965 966 @Override 967 protected void finalize() throws Throwable { 968 super.finalize(); 969 release(); 970 } 971 } 972 973 /** 974 * Check multicast filter status. 975 * 976 * @return true if multicast packets are allowed. 977 * 978 * @hide pending API council approval 979 */ 980 public boolean isMulticastEnabled() { 981 try { 982 return mService.isMulticastEnabled(); 983 } catch (RemoteException e) { 984 return false; 985 } 986 } 987} 988