WifiManager.java revision ebe606fccd9293674273d5f73246e0e8e6e6ddcf
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.net.wifi; 18 19import android.annotation.SdkConstant; 20import android.annotation.SdkConstant.SdkConstantType; 21import android.content.Context; 22import android.net.DhcpInfo; 23import android.os.Binder; 24import android.os.IBinder; 25import android.os.Handler; 26import android.os.RemoteException; 27import android.os.WorkSource; 28import android.os.Messenger; 29 30import com.android.internal.util.AsyncChannel; 31 32import java.util.List; 33 34/** 35 * This class provides the primary API for managing all aspects of Wi-Fi 36 * connectivity. Get an instance of this class by calling 37 * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}. 38 39 * It deals with several categories of items: 40 * <ul> 41 * <li>The list of configured networks. The list can be viewed and updated, 42 * and attributes of individual entries can be modified.</li> 43 * <li>The currently active Wi-Fi network, if any. Connectivity can be 44 * established or torn down, and dynamic information about the state of 45 * the network can be queried.</li> 46 * <li>Results of access point scans, containing enough information to 47 * make decisions about what access point to connect to.</li> 48 * <li>It defines the names of various Intent actions that are broadcast 49 * upon any sort of change in Wi-Fi state. 50 * </ul> 51 * This is the API to use when performing Wi-Fi specific operations. To 52 * perform operations that pertain to network connectivity at an abstract 53 * level, use {@link android.net.ConnectivityManager}. 54 */ 55public class WifiManager { 56 57 // Supplicant error codes: 58 /** 59 * The error code if there was a problem authenticating. 60 */ 61 public static final int ERROR_AUTHENTICATING = 1; 62 63 /** 64 * Broadcast intent action indicating that Wi-Fi has been enabled, disabled, 65 * enabling, disabling, or unknown. One extra provides this state as an int. 66 * Another extra provides the previous state, if available. 67 * 68 * @see #EXTRA_WIFI_STATE 69 * @see #EXTRA_PREVIOUS_WIFI_STATE 70 */ 71 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 72 public static final String WIFI_STATE_CHANGED_ACTION = 73 "android.net.wifi.WIFI_STATE_CHANGED"; 74 /** 75 * The lookup key for an int that indicates whether Wi-Fi is enabled, 76 * disabled, enabling, disabling, or unknown. Retrieve it with 77 * {@link android.content.Intent#getIntExtra(String,int)}. 78 * 79 * @see #WIFI_STATE_DISABLED 80 * @see #WIFI_STATE_DISABLING 81 * @see #WIFI_STATE_ENABLED 82 * @see #WIFI_STATE_ENABLING 83 * @see #WIFI_STATE_UNKNOWN 84 */ 85 public static final String EXTRA_WIFI_STATE = "wifi_state"; 86 /** 87 * The previous Wi-Fi state. 88 * 89 * @see #EXTRA_WIFI_STATE 90 */ 91 public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state"; 92 93 /** 94 * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if 95 * it finishes successfully. 96 * 97 * @see #WIFI_STATE_CHANGED_ACTION 98 * @see #getWifiState() 99 */ 100 public static final int WIFI_STATE_DISABLING = 0; 101 /** 102 * Wi-Fi is disabled. 103 * 104 * @see #WIFI_STATE_CHANGED_ACTION 105 * @see #getWifiState() 106 */ 107 public static final int WIFI_STATE_DISABLED = 1; 108 /** 109 * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if 110 * it finishes successfully. 111 * 112 * @see #WIFI_STATE_CHANGED_ACTION 113 * @see #getWifiState() 114 */ 115 public static final int WIFI_STATE_ENABLING = 2; 116 /** 117 * Wi-Fi is enabled. 118 * 119 * @see #WIFI_STATE_CHANGED_ACTION 120 * @see #getWifiState() 121 */ 122 public static final int WIFI_STATE_ENABLED = 3; 123 /** 124 * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling 125 * or disabling. 126 * 127 * @see #WIFI_STATE_CHANGED_ACTION 128 * @see #getWifiState() 129 */ 130 public static final int WIFI_STATE_UNKNOWN = 4; 131 132 /** 133 * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled, 134 * enabling, disabling, or failed. 135 * 136 * @hide 137 */ 138 public static final String WIFI_AP_STATE_CHANGED_ACTION = 139 "android.net.wifi.WIFI_AP_STATE_CHANGED"; 140 141 /** 142 * The lookup key for an int that indicates whether Wi-Fi AP is enabled, 143 * disabled, enabling, disabling, or failed. Retrieve it with 144 * {@link android.content.Intent#getIntExtra(String,int)}. 145 * 146 * @see #WIFI_AP_STATE_DISABLED 147 * @see #WIFI_AP_STATE_DISABLING 148 * @see #WIFI_AP_STATE_ENABLED 149 * @see #WIFI_AP_STATE_ENABLING 150 * @see #WIFI_AP_STATE_FAILED 151 * 152 * @hide 153 */ 154 public static final String EXTRA_WIFI_AP_STATE = "wifi_state"; 155 /** 156 * The previous Wi-Fi state. 157 * 158 * @see #EXTRA_WIFI_AP_STATE 159 * 160 * @hide 161 */ 162 public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state"; 163 /** 164 * Wi-Fi AP is currently being disabled. The state will change to 165 * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully. 166 * 167 * @see #WIFI_AP_STATE_CHANGED_ACTION 168 * @see #getWifiApState() 169 * 170 * @hide 171 */ 172 public static final int WIFI_AP_STATE_DISABLING = 10; 173 /** 174 * Wi-Fi AP is disabled. 175 * 176 * @see #WIFI_AP_STATE_CHANGED_ACTION 177 * @see #getWifiState() 178 * 179 * @hide 180 */ 181 public static final int WIFI_AP_STATE_DISABLED = 11; 182 /** 183 * Wi-Fi AP is currently being enabled. The state will change to 184 * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully. 185 * 186 * @see #WIFI_AP_STATE_CHANGED_ACTION 187 * @see #getWifiApState() 188 * 189 * @hide 190 */ 191 public static final int WIFI_AP_STATE_ENABLING = 12; 192 /** 193 * Wi-Fi AP is enabled. 194 * 195 * @see #WIFI_AP_STATE_CHANGED_ACTION 196 * @see #getWifiApState() 197 * 198 * @hide 199 */ 200 public static final int WIFI_AP_STATE_ENABLED = 13; 201 /** 202 * Wi-Fi AP is in a failed state. This state will occur when an error occurs during 203 * enabling or disabling 204 * 205 * @see #WIFI_AP_STATE_CHANGED_ACTION 206 * @see #getWifiApState() 207 * 208 * @hide 209 */ 210 public static final int WIFI_AP_STATE_FAILED = 14; 211 212 /** 213 * Broadcast intent action indicating that a connection to the supplicant has 214 * been established (and it is now possible 215 * to perform Wi-Fi operations) or the connection to the supplicant has been 216 * lost. One extra provides the connection state as a boolean, where {@code true} 217 * means CONNECTED. 218 * @see #EXTRA_SUPPLICANT_CONNECTED 219 */ 220 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 221 public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION = 222 "android.net.wifi.supplicant.CONNECTION_CHANGE"; 223 /** 224 * The lookup key for a boolean that indicates whether a connection to 225 * the supplicant daemon has been gained or lost. {@code true} means 226 * a connection now exists. 227 * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. 228 */ 229 public static final String EXTRA_SUPPLICANT_CONNECTED = "connected"; 230 /** 231 * Broadcast intent action indicating that the state of Wi-Fi connectivity 232 * has changed. One extra provides the new state 233 * in the form of a {@link android.net.NetworkInfo} object. If the new state is 234 * CONNECTED, a second extra may provide the BSSID of the access point, 235 * as a {@code String}. 236 * @see #EXTRA_NETWORK_INFO 237 * @see #EXTRA_BSSID 238 */ 239 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 240 public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"; 241 /** 242 * The lookup key for a {@link android.net.NetworkInfo} object associated with the 243 * Wi-Fi network. Retrieve with 244 * {@link android.content.Intent#getParcelableExtra(String)}. 245 */ 246 public static final String EXTRA_NETWORK_INFO = "networkInfo"; 247 /** 248 * The lookup key for a String giving the BSSID of the access point to which 249 * we are connected. Only present when the new state is CONNECTED. 250 * Retrieve with 251 * {@link android.content.Intent#getStringExtra(String)}. 252 */ 253 public static final String EXTRA_BSSID = "bssid"; 254 /** 255 * Broadcast intent action indicating that the state of establishing a connection to 256 * an access point has changed.One extra provides the new 257 * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and 258 * is not generally the most useful thing to look at if you are just interested in 259 * the overall state of connectivity. 260 * @see #EXTRA_NEW_STATE 261 * @see #EXTRA_SUPPLICANT_ERROR 262 */ 263 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 264 public static final String SUPPLICANT_STATE_CHANGED_ACTION = 265 "android.net.wifi.supplicant.STATE_CHANGE"; 266 /** 267 * The lookup key for a {@link SupplicantState} describing the new state 268 * Retrieve with 269 * {@link android.content.Intent#getParcelableExtra(String)}. 270 */ 271 public static final String EXTRA_NEW_STATE = "newState"; 272 273 /** 274 * The lookup key for a {@link SupplicantState} describing the supplicant 275 * error code if any 276 * Retrieve with 277 * {@link android.content.Intent#getIntExtra(String, int)}. 278 * @see #ERROR_AUTHENTICATING 279 */ 280 public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError"; 281 282 /** 283 * Broadcast intent action for reporting errors 284 * @hide 285 */ 286 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 287 public static final String ERROR_ACTION = "android.net.wifi.ERROR"; 288 /** 289 * The type of error being reported 290 * @hide 291 */ 292 public static final String EXTRA_ERROR_CODE = "errorCode"; 293 294 /** 295 * Valid error codes 296 * @hide 297 */ 298 public static final int WPS_OVERLAP_ERROR = 1; 299 300 /** 301 * Broadcast intent action indicating that the configured networks changed. 302 * This can be as a result of adding/updating/deleting a network 303 * @hide 304 */ 305 public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = 306 "android.net.wifi.CONFIGURED_NETWORKS_CHANGE"; 307 /** 308 * An access point scan has completed, and results are available from the supplicant. 309 * Call {@link #getScanResults()} to obtain the results. 310 */ 311 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 312 public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS"; 313 /** 314 * The RSSI (signal strength) has changed. 315 * @see #EXTRA_NEW_RSSI 316 */ 317 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 318 public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED"; 319 /** 320 * The lookup key for an {@code int} giving the new RSSI in dBm. 321 */ 322 public static final String EXTRA_NEW_RSSI = "newRssi"; 323 324 /** 325 * Broadcast intent action indicating that the link configuration 326 * changed on wifi. 327 * @hide 328 */ 329 public static final String LINK_CONFIGURATION_CHANGED_ACTION = 330 "android.net.wifi.LINK_CONFIGURATION_CHANGED"; 331 332 /** 333 * The lookup key for a {@link android.net.LinkProperties} object associated with the 334 * Wi-Fi network. Retrieve with 335 * {@link android.content.Intent#getParcelableExtra(String)}. 336 * @hide 337 */ 338 public static final String EXTRA_LINK_PROPERTIES = "linkProperties"; 339 340 /** 341 * The lookup key for a {@link android.net.LinkCapabilities} object associated with the 342 * Wi-Fi network. Retrieve with 343 * {@link android.content.Intent#getParcelableExtra(String)}. 344 * @hide 345 */ 346 public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities"; 347 348 /** 349 * The network IDs of the configured networks could have changed. 350 */ 351 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 352 public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED"; 353 354 /** 355 * Activity Action: Pick a Wi-Fi network to connect to. 356 * <p>Input: Nothing. 357 * <p>Output: Nothing. 358 */ 359 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 360 public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; 361 362 /** 363 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 364 * and will behave normally, i.e., it will attempt to automatically 365 * establish a connection to a remembered access point that is 366 * within range, and will do periodic scans if there are remembered 367 * access points but none are in range. 368 */ 369 public static final int WIFI_MODE_FULL = 1; 370 /** 371 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 372 * but the only operation that will be supported is initiation of 373 * scans, and the subsequent reporting of scan results. No attempts 374 * will be made to automatically connect to remembered access points, 375 * nor will periodic scans be automatically performed looking for 376 * remembered access points. Scans must be explicitly requested by 377 * an application in this mode. 378 */ 379 public static final int WIFI_MODE_SCAN_ONLY = 2; 380 /** 381 * In this Wi-Fi lock mode, Wi-Fi will be kept active as in mode 382 * {@link #WIFI_MODE_FULL} but it operates at high performance 383 * with minimum packet loss and low packet latency even when 384 * the device screen is off. This mode will consume more power 385 * and hence should be used only when there is a need for such 386 * an active connection. 387 * <p> 388 * An example use case is when a voice connection needs to be 389 * kept active even after the device screen goes off. Holding the 390 * regular {@link #WIFI_MODE_FULL} lock will keep the wifi 391 * connection active, but the connection can be lossy. 392 * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the 393 * duration of the voice call will improve the call quality. 394 * <p> 395 * When there is no support from the hardware, this lock mode 396 * will have the same behavior as {@link #WIFI_MODE_FULL} 397 */ 398 public static final int WIFI_MODE_FULL_HIGH_PERF = 3; 399 400 /** Anything worse than or equal to this will show 0 bars. */ 401 private static final int MIN_RSSI = -100; 402 403 /** Anything better than or equal to this will show the max bars. */ 404 private static final int MAX_RSSI = -55; 405 406 /** 407 * Auto settings in the driver. The driver could choose to operate on both 408 * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band. 409 * @hide 410 */ 411 public static final int WIFI_FREQUENCY_BAND_AUTO = 0; 412 413 /** 414 * Operation on 5 GHz alone 415 * @hide 416 */ 417 public static final int WIFI_FREQUENCY_BAND_5GHZ = 1; 418 419 /** 420 * Operation on 2.4 GHz alone 421 * @hide 422 */ 423 public static final int WIFI_FREQUENCY_BAND_2GHZ = 2; 424 425 /** List of asyncronous notifications 426 * @hide 427 */ 428 public static final int DATA_ACTIVITY_NOTIFICATION = 1; 429 430 //Lowest bit indicates data reception and the second lowest 431 //bit indicates data transmitted 432 /** @hide */ 433 public static final int DATA_ACTIVITY_NONE = 0x00; 434 /** @hide */ 435 public static final int DATA_ACTIVITY_IN = 0x01; 436 /** @hide */ 437 public static final int DATA_ACTIVITY_OUT = 0x02; 438 /** @hide */ 439 public static final int DATA_ACTIVITY_INOUT = 0x03; 440 441 IWifiManager mService; 442 Handler mHandler; 443 444 /* Maximum number of active locks we allow. 445 * This limit was added to prevent apps from creating a ridiculous number 446 * of locks and crashing the system by overflowing the global ref table. 447 */ 448 private static final int MAX_ACTIVE_LOCKS = 50; 449 450 /* Number of currently active WifiLocks and MulticastLocks */ 451 private int mActiveLockCount; 452 453 /* For communication with WifiService */ 454 private AsyncChannel mAsyncChannel = new AsyncChannel(); 455 456 /** 457 * Create a new WifiManager instance. 458 * Applications will almost always want to use 459 * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve 460 * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. 461 * @param service the Binder interface 462 * @param handler target for messages 463 * @hide - hide this because it takes in a parameter of type IWifiManager, which 464 * is a system private class. 465 */ 466 public WifiManager(IWifiManager service, Handler handler) { 467 mService = service; 468 mHandler = handler; 469 } 470 471 /** 472 * Return a list of all the networks configured in the supplicant. 473 * Not all fields of WifiConfiguration are returned. Only the following 474 * fields are filled in: 475 * <ul> 476 * <li>networkId</li> 477 * <li>SSID</li> 478 * <li>BSSID</li> 479 * <li>priority</li> 480 * <li>allowedProtocols</li> 481 * <li>allowedKeyManagement</li> 482 * <li>allowedAuthAlgorithms</li> 483 * <li>allowedPairwiseCiphers</li> 484 * <li>allowedGroupCiphers</li> 485 * </ul> 486 * @return a list of network configurations in the form of a list 487 * of {@link WifiConfiguration} objects. 488 */ 489 public List<WifiConfiguration> getConfiguredNetworks() { 490 try { 491 return mService.getConfiguredNetworks(); 492 } catch (RemoteException e) { 493 return null; 494 } 495 } 496 497 /** 498 * Add a new network description to the set of configured networks. 499 * The {@code networkId} field of the supplied configuration object 500 * is ignored. 501 * <p/> 502 * The new network will be marked DISABLED by default. To enable it, 503 * called {@link #enableNetwork}. 504 * 505 * @param config the set of variables that describe the configuration, 506 * contained in a {@link WifiConfiguration} object. 507 * @return the ID of the newly created network description. This is used in 508 * other operations to specified the network to be acted upon. 509 * Returns {@code -1} on failure. 510 */ 511 public int addNetwork(WifiConfiguration config) { 512 if (config == null) { 513 return -1; 514 } 515 config.networkId = -1; 516 return addOrUpdateNetwork(config); 517 } 518 519 /** 520 * Update the network description of an existing configured network. 521 * 522 * @param config the set of variables that describe the configuration, 523 * contained in a {@link WifiConfiguration} object. It may 524 * be sparse, so that only the items that are being changed 525 * are non-<code>null</code>. The {@code networkId} field 526 * must be set to the ID of the existing network being updated. 527 * @return Returns the {@code networkId} of the supplied 528 * {@code WifiConfiguration} on success. 529 * <br/> 530 * Returns {@code -1} on failure, including when the {@code networkId} 531 * field of the {@code WifiConfiguration} does not refer to an 532 * existing network. 533 */ 534 public int updateNetwork(WifiConfiguration config) { 535 if (config == null || config.networkId < 0) { 536 return -1; 537 } 538 return addOrUpdateNetwork(config); 539 } 540 541 /** 542 * Internal method for doing the RPC that creates a new network description 543 * or updates an existing one. 544 * 545 * @param config The possibly sparse object containing the variables that 546 * are to set or updated in the network description. 547 * @return the ID of the network on success, {@code -1} on failure. 548 */ 549 private int addOrUpdateNetwork(WifiConfiguration config) { 550 try { 551 return mService.addOrUpdateNetwork(config); 552 } catch (RemoteException e) { 553 return -1; 554 } 555 } 556 557 /** 558 * Remove the specified network from the list of configured networks. 559 * This may result in the asynchronous delivery of state change 560 * events. 561 * @param netId the integer that identifies the network configuration 562 * to the supplicant 563 * @return {@code true} if the operation succeeded 564 */ 565 public boolean removeNetwork(int netId) { 566 try { 567 return mService.removeNetwork(netId); 568 } catch (RemoteException e) { 569 return false; 570 } 571 } 572 573 /** 574 * Allow a previously configured network to be associated with. If 575 * <code>disableOthers</code> is true, then all other configured 576 * networks are disabled, and an attempt to connect to the selected 577 * network is initiated. This may result in the asynchronous delivery 578 * of state change events. 579 * @param netId the ID of the network in the list of configured networks 580 * @param disableOthers if true, disable all other networks. The way to 581 * select a particular network to connect to is specify {@code true} 582 * for this parameter. 583 * @return {@code true} if the operation succeeded 584 */ 585 public boolean enableNetwork(int netId, boolean disableOthers) { 586 try { 587 return mService.enableNetwork(netId, disableOthers); 588 } catch (RemoteException e) { 589 return false; 590 } 591 } 592 593 /** 594 * Disable a configured network. The specified network will not be 595 * a candidate for associating. This may result in the asynchronous 596 * delivery of state change events. 597 * @param netId the ID of the network as returned by {@link #addNetwork}. 598 * @return {@code true} if the operation succeeded 599 */ 600 public boolean disableNetwork(int netId) { 601 try { 602 return mService.disableNetwork(netId); 603 } catch (RemoteException e) { 604 return false; 605 } 606 } 607 608 /** 609 * Disassociate from the currently active access point. This may result 610 * in the asynchronous delivery of state change events. 611 * @return {@code true} if the operation succeeded 612 */ 613 public boolean disconnect() { 614 try { 615 mService.disconnect(); 616 return true; 617 } catch (RemoteException e) { 618 return false; 619 } 620 } 621 622 /** 623 * Reconnect to the currently active access point, if we are currently 624 * disconnected. This may result in the asynchronous delivery of state 625 * change events. 626 * @return {@code true} if the operation succeeded 627 */ 628 public boolean reconnect() { 629 try { 630 mService.reconnect(); 631 return true; 632 } catch (RemoteException e) { 633 return false; 634 } 635 } 636 637 /** 638 * Reconnect to the currently active access point, even if we are already 639 * connected. This may result in the asynchronous delivery of state 640 * change events. 641 * @return {@code true} if the operation succeeded 642 */ 643 public boolean reassociate() { 644 try { 645 mService.reassociate(); 646 return true; 647 } catch (RemoteException e) { 648 return false; 649 } 650 } 651 652 /** 653 * Check that the supplicant daemon is responding to requests. 654 * @return {@code true} if we were able to communicate with the supplicant and 655 * it returned the expected response to the PING message. 656 */ 657 public boolean pingSupplicant() { 658 if (mService == null) 659 return false; 660 try { 661 return mService.pingSupplicant(); 662 } catch (RemoteException e) { 663 return false; 664 } 665 } 666 667 /** 668 * Request a scan for access points. Returns immediately. The availability 669 * of the results is made known later by means of an asynchronous event sent 670 * on completion of the scan. 671 * @return {@code true} if the operation succeeded, i.e., the scan was initiated 672 */ 673 public boolean startScan() { 674 try { 675 mService.startScan(false); 676 return true; 677 } catch (RemoteException e) { 678 return false; 679 } 680 } 681 682 /** 683 * Request a scan for access points. Returns immediately. The availability 684 * of the results is made known later by means of an asynchronous event sent 685 * on completion of the scan. 686 * This is a variant of startScan that forces an active scan, even if passive 687 * scans are the current default 688 * @return {@code true} if the operation succeeded, i.e., the scan was initiated 689 * 690 * @hide 691 */ 692 public boolean startScanActive() { 693 try { 694 mService.startScan(true); 695 return true; 696 } catch (RemoteException e) { 697 return false; 698 } 699 } 700 701 /** 702 * Return dynamic information about the current Wi-Fi connection, if any is active. 703 * @return the Wi-Fi information, contained in {@link WifiInfo}. 704 */ 705 public WifiInfo getConnectionInfo() { 706 try { 707 return mService.getConnectionInfo(); 708 } catch (RemoteException e) { 709 return null; 710 } 711 } 712 713 /** 714 * Return the results of the latest access point scan. 715 * @return the list of access points found in the most recent scan. 716 */ 717 public List<ScanResult> getScanResults() { 718 try { 719 return mService.getScanResults(); 720 } catch (RemoteException e) { 721 return null; 722 } 723 } 724 725 /** 726 * Tell the supplicant to persist the current list of configured networks. 727 * <p> 728 * Note: It is possible for this method to change the network IDs of 729 * existing networks. You should assume the network IDs can be different 730 * after calling this method. 731 * 732 * @return {@code true} if the operation succeeded 733 */ 734 public boolean saveConfiguration() { 735 try { 736 return mService.saveConfiguration(); 737 } catch (RemoteException e) { 738 return false; 739 } 740 } 741 742 /** 743 * Set the country code. 744 * @param countryCode country code in ISO 3166 format. 745 * @param persist {@code true} if this needs to be remembered 746 * 747 * @hide 748 */ 749 public void setCountryCode(String country, boolean persist) { 750 try { 751 mService.setCountryCode(country, persist); 752 } catch (RemoteException e) { } 753 } 754 755 /** 756 * Set the operational frequency band. 757 * @param band One of 758 * {@link #WIFI_FREQUENCY_BAND_AUTO}, 759 * {@link #WIFI_FREQUENCY_BAND_5GHZ}, 760 * {@link #WIFI_FREQUENCY_BAND_2GHZ}, 761 * @param persist {@code true} if this needs to be remembered 762 * @hide 763 */ 764 public void setFrequencyBand(int band, boolean persist) { 765 try { 766 mService.setFrequencyBand(band, persist); 767 } catch (RemoteException e) { } 768 } 769 770 /** 771 * Get the operational frequency band. 772 * @return One of 773 * {@link #WIFI_FREQUENCY_BAND_AUTO}, 774 * {@link #WIFI_FREQUENCY_BAND_5GHZ}, 775 * {@link #WIFI_FREQUENCY_BAND_2GHZ} or 776 * {@code -1} on failure. 777 * @hide 778 */ 779 public int getFrequencyBand() { 780 try { 781 return mService.getFrequencyBand(); 782 } catch (RemoteException e) { 783 return -1; 784 } 785 } 786 787 /** 788 * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz) 789 * @return {@code true} if supported, {@code false} otherwise. 790 * @hide 791 */ 792 public boolean isDualBandSupported() { 793 try { 794 return mService.isDualBandSupported(); 795 } catch (RemoteException e) { 796 return false; 797 } 798 } 799 800 /** 801 * Return the DHCP-assigned addresses from the last successful DHCP request, 802 * if any. 803 * @return the DHCP information 804 */ 805 public DhcpInfo getDhcpInfo() { 806 try { 807 return mService.getDhcpInfo(); 808 } catch (RemoteException e) { 809 return null; 810 } 811 } 812 813 814 /** 815 * Enable or disable Wi-Fi. 816 * @param enabled {@code true} to enable, {@code false} to disable. 817 * @return {@code true} if the operation succeeds (or if the existing state 818 * is the same as the requested state). 819 */ 820 public boolean setWifiEnabled(boolean enabled) { 821 try { 822 return mService.setWifiEnabled(enabled); 823 } catch (RemoteException e) { 824 return false; 825 } 826 } 827 828 /** 829 * Gets the Wi-Fi enabled state. 830 * @return One of {@link #WIFI_STATE_DISABLED}, 831 * {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED}, 832 * {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN} 833 * @see #isWifiEnabled() 834 */ 835 public int getWifiState() { 836 try { 837 return mService.getWifiEnabledState(); 838 } catch (RemoteException e) { 839 return WIFI_STATE_UNKNOWN; 840 } 841 } 842 843 /** 844 * Return whether Wi-Fi is enabled or disabled. 845 * @return {@code true} if Wi-Fi is enabled 846 * @see #getWifiState() 847 */ 848 public boolean isWifiEnabled() { 849 return getWifiState() == WIFI_STATE_ENABLED; 850 } 851 852 /** 853 * Calculates the level of the signal. This should be used any time a signal 854 * is being shown. 855 * 856 * @param rssi The power of the signal measured in RSSI. 857 * @param numLevels The number of levels to consider in the calculated 858 * level. 859 * @return A level of the signal, given in the range of 0 to numLevels-1 860 * (both inclusive). 861 */ 862 public static int calculateSignalLevel(int rssi, int numLevels) { 863 if (rssi <= MIN_RSSI) { 864 return 0; 865 } else if (rssi >= MAX_RSSI) { 866 return numLevels - 1; 867 } else { 868 float inputRange = (MAX_RSSI - MIN_RSSI); 869 float outputRange = (numLevels - 1); 870 return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange); 871 } 872 } 873 874 /** 875 * Compares two signal strengths. 876 * 877 * @param rssiA The power of the first signal measured in RSSI. 878 * @param rssiB The power of the second signal measured in RSSI. 879 * @return Returns <0 if the first signal is weaker than the second signal, 880 * 0 if the two signals have the same strength, and >0 if the first 881 * signal is stronger than the second signal. 882 */ 883 public static int compareSignalLevel(int rssiA, int rssiB) { 884 return rssiA - rssiB; 885 } 886 887 /** 888 * Start AccessPoint mode with the specified 889 * configuration. If the radio is already running in 890 * AP mode, update the new configuration 891 * Note that starting in access point mode disables station 892 * mode operation 893 * @param wifiConfig SSID, security and channel details as 894 * part of WifiConfiguration 895 * @return {@code true} if the operation succeeds, {@code false} otherwise 896 * 897 * @hide Dont open up yet 898 */ 899 public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { 900 try { 901 return mService.setWifiApEnabled(wifiConfig, enabled); 902 } catch (RemoteException e) { 903 return false; 904 } 905 } 906 907 /** 908 * Gets the Wi-Fi enabled state. 909 * @return One of {@link #WIFI_AP_STATE_DISABLED}, 910 * {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED}, 911 * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} 912 * @see #isWifiApEnabled() 913 * 914 * @hide Dont open yet 915 */ 916 public int getWifiApState() { 917 try { 918 return mService.getWifiApEnabledState(); 919 } catch (RemoteException e) { 920 return WIFI_AP_STATE_FAILED; 921 } 922 } 923 924 /** 925 * Return whether Wi-Fi AP is enabled or disabled. 926 * @return {@code true} if Wi-Fi AP is enabled 927 * @see #getWifiApState() 928 * 929 * @hide Dont open yet 930 */ 931 public boolean isWifiApEnabled() { 932 return getWifiApState() == WIFI_AP_STATE_ENABLED; 933 } 934 935 /** 936 * Gets the Wi-Fi AP Configuration. 937 * @return AP details in WifiConfiguration 938 * 939 * @hide Dont open yet 940 */ 941 public WifiConfiguration getWifiApConfiguration() { 942 try { 943 return mService.getWifiApConfiguration(); 944 } catch (RemoteException e) { 945 return null; 946 } 947 } 948 949 /** 950 * Sets the Wi-Fi AP Configuration. 951 * @return {@code true} if the operation succeeded, {@code false} otherwise 952 * 953 * @hide Dont open yet 954 */ 955 public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) { 956 try { 957 mService.setWifiApConfiguration(wifiConfig); 958 return true; 959 } catch (RemoteException e) { 960 return false; 961 } 962 } 963 964 /** 965 * Start the driver and connect to network. 966 * 967 * This function will over-ride WifiLock and device idle status. For example, 968 * even if the device is idle or there is only a scan-only lock held, 969 * a start wifi would mean that wifi connection is kept active until 970 * a stopWifi() is sent. 971 * 972 * This API is used by WifiStateTracker 973 * 974 * @return {@code true} if the operation succeeds else {@code false} 975 * @hide 976 */ 977 public boolean startWifi() { 978 try { 979 mService.startWifi(); 980 return true; 981 } catch (RemoteException e) { 982 return false; 983 } 984 } 985 986 /** 987 * Disconnect from a network (if any) and stop the driver. 988 * 989 * This function will over-ride WifiLock and device idle status. Wi-Fi 990 * stays inactive until a startWifi() is issued. 991 * 992 * This API is used by WifiStateTracker 993 * 994 * @return {@code true} if the operation succeeds else {@code false} 995 * @hide 996 */ 997 public boolean stopWifi() { 998 try { 999 mService.stopWifi(); 1000 return true; 1001 } catch (RemoteException e) { 1002 return false; 1003 } 1004 } 1005 1006 /** 1007 * Add a bssid to the supplicant blacklist 1008 * 1009 * This API is used by WifiWatchdogService 1010 * 1011 * @return {@code true} if the operation succeeds else {@code false} 1012 * @hide 1013 */ 1014 public boolean addToBlacklist(String bssid) { 1015 try { 1016 mService.addToBlacklist(bssid); 1017 return true; 1018 } catch (RemoteException e) { 1019 return false; 1020 } 1021 } 1022 1023 /** 1024 * Clear the supplicant blacklist 1025 * 1026 * This API is used by WifiWatchdogService 1027 * 1028 * @return {@code true} if the operation succeeds else {@code false} 1029 * @hide 1030 */ 1031 public boolean clearBlacklist() { 1032 try { 1033 mService.clearBlacklist(); 1034 return true; 1035 } catch (RemoteException e) { 1036 return false; 1037 } 1038 } 1039 1040 /* TODO: deprecate synchronous API and open up the following API */ 1041 1042 /* Commands to WifiService */ 1043 /** @hide */ 1044 public static final int CMD_CONNECT_NETWORK = 1; 1045 /** @hide */ 1046 public static final int CMD_FORGET_NETWORK = 2; 1047 /** @hide */ 1048 public static final int CMD_SAVE_NETWORK = 3; 1049 /** @hide */ 1050 public static final int CMD_START_WPS = 4; 1051 1052 /* Events from WifiService */ 1053 /** @hide */ 1054 public static final int CMD_WPS_COMPLETED = 11; 1055 1056 /* For system use only */ 1057 /** @hide */ 1058 public static final int CMD_ENABLE_TRAFFIC_STATS_POLL = 21; 1059 /** @hide */ 1060 public static final int CMD_TRAFFIC_STATS_POLL = 22; 1061 1062 /** 1063 * Initiate an asynchronous channel connection setup 1064 * @param srcContext is the context of the source 1065 * @param srcHandler is the handler on which the source receives messages 1066 * @hide 1067 */ 1068 public void asyncConnect(Context srcContext, Handler srcHandler) { 1069 mAsyncChannel.connect(srcContext, srcHandler, getMessenger()); 1070 } 1071 1072 /** 1073 * Connect to a network with the given configuration. The network also 1074 * gets added to the supplicant configuration. 1075 * 1076 * For a new network, this function is used instead of a 1077 * sequence of addNetwork(), enableNetwork(), saveConfiguration() and 1078 * reconnect() 1079 * 1080 * @param config the set of variables that describe the configuration, 1081 * contained in a {@link WifiConfiguration} object. 1082 * @hide 1083 */ 1084 public void connectNetwork(WifiConfiguration config) { 1085 if (config == null) { 1086 return; 1087 } 1088 mAsyncChannel.sendMessage(CMD_CONNECT_NETWORK, config); 1089 } 1090 1091 /** 1092 * Connect to a network with the given networkId. 1093 * 1094 * This function is used instead of a enableNetwork(), saveConfiguration() and 1095 * reconnect() 1096 * 1097 * @param networkId the network id identifiying the network in the 1098 * supplicant configuration list 1099 * @hide 1100 */ 1101 public void connectNetwork(int networkId) { 1102 if (networkId < 0) { 1103 return; 1104 } 1105 mAsyncChannel.sendMessage(CMD_CONNECT_NETWORK, networkId); 1106 } 1107 1108 /** 1109 * Save the given network in the supplicant config. If the network already 1110 * exists, the configuration is updated. A new network is enabled 1111 * by default. 1112 * 1113 * For a new network, this function is used instead of a 1114 * sequence of addNetwork(), enableNetwork() and saveConfiguration(). 1115 * 1116 * For an existing network, it accomplishes the task of updateNetwork() 1117 * and saveConfiguration() 1118 * 1119 * @param config the set of variables that describe the configuration, 1120 * contained in a {@link WifiConfiguration} object. 1121 * @hide 1122 */ 1123 public void saveNetwork(WifiConfiguration config) { 1124 if (config == null) { 1125 return; 1126 } 1127 1128 mAsyncChannel.sendMessage(CMD_SAVE_NETWORK, config); 1129 } 1130 1131 /** 1132 * Delete the network in the supplicant config. 1133 * 1134 * This function is used instead of a sequence of removeNetwork() 1135 * and saveConfiguration(). 1136 * 1137 * @param config the set of variables that describe the configuration, 1138 * contained in a {@link WifiConfiguration} object. 1139 * @hide 1140 */ 1141 public void forgetNetwork(int netId) { 1142 if (netId < 0) { 1143 return; 1144 } 1145 1146 mAsyncChannel.sendMessage(CMD_FORGET_NETWORK, netId); 1147 } 1148 1149 /** 1150 * Start Wi-fi Protected Setup 1151 * 1152 * @param config WPS configuration 1153 * @hide 1154 */ 1155 public void startWps(WpsConfiguration config) { 1156 if (config == null) { 1157 return; 1158 } 1159 1160 mAsyncChannel.sendMessage(CMD_START_WPS, config); 1161 } 1162 1163 /** 1164 * Get a reference to WifiService handler. This is used by a client to establish 1165 * an AsyncChannel communication with WifiService 1166 * 1167 * @return Messenger pointing to the WifiService handler 1168 * @hide 1169 */ 1170 public Messenger getMessenger() { 1171 try { 1172 return mService.getMessenger(); 1173 } catch (RemoteException e) { 1174 return null; 1175 } 1176 } 1177 1178 /** 1179 * Allows an application to keep the Wi-Fi radio awake. 1180 * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. 1181 * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple 1182 * applications may hold WifiLocks, and the radio will only be allowed to turn off when no 1183 * WifiLocks are held in any application. 1184 * 1185 * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or 1186 * could function over a mobile network, if available. A program that needs to download large 1187 * files should hold a WifiLock to ensure that the download will complete, but a program whose 1188 * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely 1189 * affecting battery life. 1190 * 1191 * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane 1192 * Mode. They simply keep the radio from turning off when Wi-Fi is already on but the device 1193 * is idle. 1194 */ 1195 public class WifiLock { 1196 private String mTag; 1197 private final IBinder mBinder; 1198 private int mRefCount; 1199 int mLockType; 1200 private boolean mRefCounted; 1201 private boolean mHeld; 1202 private WorkSource mWorkSource; 1203 1204 private WifiLock(int lockType, String tag) { 1205 mTag = tag; 1206 mLockType = lockType; 1207 mBinder = new Binder(); 1208 mRefCount = 0; 1209 mRefCounted = true; 1210 mHeld = false; 1211 } 1212 1213 /** 1214 * Locks the Wi-Fi radio on until {@link #release} is called. 1215 * 1216 * If this WifiLock is reference-counted, each call to {@code acquire} will increment the 1217 * reference count, and the radio will remain locked as long as the reference count is 1218 * above zero. 1219 * 1220 * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock 1221 * the radio, but subsequent calls will be ignored. Only one call to {@link #release} 1222 * will be required, regardless of the number of times that {@code acquire} is called. 1223 */ 1224 public void acquire() { 1225 synchronized (mBinder) { 1226 if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) { 1227 try { 1228 mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource); 1229 synchronized (WifiManager.this) { 1230 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 1231 mService.releaseWifiLock(mBinder); 1232 throw new UnsupportedOperationException( 1233 "Exceeded maximum number of wifi locks"); 1234 } 1235 mActiveLockCount++; 1236 } 1237 } catch (RemoteException ignore) { 1238 } 1239 mHeld = true; 1240 } 1241 } 1242 } 1243 1244 /** 1245 * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle. 1246 * 1247 * If this WifiLock is reference-counted, each call to {@code release} will decrement the 1248 * reference count, and the radio will be unlocked only when the reference count reaches 1249 * zero. If the reference count goes below zero (that is, if {@code release} is called 1250 * a greater number of times than {@link #acquire}), an exception is thrown. 1251 * 1252 * If this WifiLock is not reference-counted, the first call to {@code release} (after 1253 * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent 1254 * calls will be ignored. 1255 */ 1256 public void release() { 1257 synchronized (mBinder) { 1258 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 1259 try { 1260 mService.releaseWifiLock(mBinder); 1261 synchronized (WifiManager.this) { 1262 mActiveLockCount--; 1263 } 1264 } catch (RemoteException ignore) { 1265 } 1266 mHeld = false; 1267 } 1268 if (mRefCount < 0) { 1269 throw new RuntimeException("WifiLock under-locked " + mTag); 1270 } 1271 } 1272 } 1273 1274 /** 1275 * Controls whether this is a reference-counted or non-reference-counted WifiLock. 1276 * 1277 * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and 1278 * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire} 1279 * has been balanced with a call to {@link #release}. Non-reference-counted WifiLocks 1280 * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the 1281 * radio whenever {@link #release} is called and it is locked. 1282 * 1283 * @param refCounted true if this WifiLock should keep a reference count 1284 */ 1285 public void setReferenceCounted(boolean refCounted) { 1286 mRefCounted = refCounted; 1287 } 1288 1289 /** 1290 * Checks whether this WifiLock is currently held. 1291 * 1292 * @return true if this WifiLock is held, false otherwise 1293 */ 1294 public boolean isHeld() { 1295 synchronized (mBinder) { 1296 return mHeld; 1297 } 1298 } 1299 1300 public void setWorkSource(WorkSource ws) { 1301 synchronized (mBinder) { 1302 if (ws != null && ws.size() == 0) { 1303 ws = null; 1304 } 1305 boolean changed = true; 1306 if (ws == null) { 1307 mWorkSource = null; 1308 } else if (mWorkSource == null) { 1309 changed = mWorkSource != null; 1310 mWorkSource = new WorkSource(ws); 1311 } else { 1312 changed = mWorkSource.diff(ws); 1313 if (changed) { 1314 mWorkSource.set(ws); 1315 } 1316 } 1317 if (changed && mHeld) { 1318 try { 1319 mService.updateWifiLockWorkSource(mBinder, mWorkSource); 1320 } catch (RemoteException e) { 1321 } 1322 } 1323 } 1324 } 1325 1326 public String toString() { 1327 String s1, s2, s3; 1328 synchronized (mBinder) { 1329 s1 = Integer.toHexString(System.identityHashCode(this)); 1330 s2 = mHeld ? "held; " : ""; 1331 if (mRefCounted) { 1332 s3 = "refcounted: refcount = " + mRefCount; 1333 } else { 1334 s3 = "not refcounted"; 1335 } 1336 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }"; 1337 } 1338 } 1339 1340 @Override 1341 protected void finalize() throws Throwable { 1342 super.finalize(); 1343 synchronized (mBinder) { 1344 if (mHeld) { 1345 try { 1346 mService.releaseWifiLock(mBinder); 1347 synchronized (WifiManager.this) { 1348 mActiveLockCount--; 1349 } 1350 } catch (RemoteException ignore) { 1351 } 1352 } 1353 } 1354 } 1355 } 1356 1357 /** 1358 * Creates a new WifiLock. 1359 * 1360 * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL}, 1361 * {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for 1362 * descriptions of the types of Wi-Fi locks. 1363 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 1364 * never shown to the user under normal conditions, but should be descriptive 1365 * enough to identify your application and the specific WifiLock within it, if it 1366 * holds multiple WifiLocks. 1367 * 1368 * @return a new, unacquired WifiLock with the given tag. 1369 * 1370 * @see WifiLock 1371 */ 1372 public WifiLock createWifiLock(int lockType, String tag) { 1373 return new WifiLock(lockType, tag); 1374 } 1375 1376 /** 1377 * Creates a new WifiLock. 1378 * 1379 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 1380 * never shown to the user under normal conditions, but should be descriptive 1381 * enough to identify your application and the specific WifiLock within it, if it 1382 * holds multiple WifiLocks. 1383 * 1384 * @return a new, unacquired WifiLock with the given tag. 1385 * 1386 * @see WifiLock 1387 */ 1388 public WifiLock createWifiLock(String tag) { 1389 return new WifiLock(WIFI_MODE_FULL, tag); 1390 } 1391 1392 1393 /** 1394 * Create a new MulticastLock 1395 * 1396 * @param tag a tag for the MulticastLock to identify it in debugging 1397 * messages. This string is never shown to the user under 1398 * normal conditions, but should be descriptive enough to 1399 * identify your application and the specific MulticastLock 1400 * within it, if it holds multiple MulticastLocks. 1401 * 1402 * @return a new, unacquired MulticastLock with the given tag. 1403 * 1404 * @see MulticastLock 1405 */ 1406 public MulticastLock createMulticastLock(String tag) { 1407 return new MulticastLock(tag); 1408 } 1409 1410 /** 1411 * Allows an application to receive Wifi Multicast packets. 1412 * Normally the Wifi stack filters out packets not explicitly 1413 * addressed to this device. Acquring a MulticastLock will 1414 * cause the stack to receive packets addressed to multicast 1415 * addresses. Processing these extra packets can cause a noticable 1416 * battery drain and should be disabled when not needed. 1417 */ 1418 public class MulticastLock { 1419 private String mTag; 1420 private final IBinder mBinder; 1421 private int mRefCount; 1422 private boolean mRefCounted; 1423 private boolean mHeld; 1424 1425 private MulticastLock(String tag) { 1426 mTag = tag; 1427 mBinder = new Binder(); 1428 mRefCount = 0; 1429 mRefCounted = true; 1430 mHeld = false; 1431 } 1432 1433 /** 1434 * Locks Wifi Multicast on until {@link #release} is called. 1435 * 1436 * If this MulticastLock is reference-counted each call to 1437 * {@code acquire} will increment the reference count, and the 1438 * wifi interface will receive multicast packets as long as the 1439 * reference count is above zero. 1440 * 1441 * If this MulticastLock is not reference-counted, the first call to 1442 * {@code acquire} will turn on the multicast packets, but subsequent 1443 * calls will be ignored. Only one call to {@link #release} will 1444 * be required, regardless of the number of times that {@code acquire} 1445 * is called. 1446 * 1447 * Note that other applications may also lock Wifi Multicast on. 1448 * Only they can relinquish their lock. 1449 * 1450 * Also note that applications cannot leave Multicast locked on. 1451 * When an app exits or crashes, any Multicast locks will be released. 1452 */ 1453 public void acquire() { 1454 synchronized (mBinder) { 1455 if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) { 1456 try { 1457 mService.acquireMulticastLock(mBinder, mTag); 1458 synchronized (WifiManager.this) { 1459 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 1460 mService.releaseMulticastLock(); 1461 throw new UnsupportedOperationException( 1462 "Exceeded maximum number of wifi locks"); 1463 } 1464 mActiveLockCount++; 1465 } 1466 } catch (RemoteException ignore) { 1467 } 1468 mHeld = true; 1469 } 1470 } 1471 } 1472 1473 /** 1474 * Unlocks Wifi Multicast, restoring the filter of packets 1475 * not addressed specifically to this device and saving power. 1476 * 1477 * If this MulticastLock is reference-counted, each call to 1478 * {@code release} will decrement the reference count, and the 1479 * multicast packets will only stop being received when the reference 1480 * count reaches zero. If the reference count goes below zero (that 1481 * is, if {@code release} is called a greater number of times than 1482 * {@link #acquire}), an exception is thrown. 1483 * 1484 * If this MulticastLock is not reference-counted, the first call to 1485 * {@code release} (after the radio was multicast locked using 1486 * {@link #acquire}) will unlock the multicast, and subsequent calls 1487 * will be ignored. 1488 * 1489 * Note that if any other Wifi Multicast Locks are still outstanding 1490 * this {@code release} call will not have an immediate effect. Only 1491 * when all applications have released all their Multicast Locks will 1492 * the Multicast filter be turned back on. 1493 * 1494 * Also note that when an app exits or crashes all of its Multicast 1495 * Locks will be automatically released. 1496 */ 1497 public void release() { 1498 synchronized (mBinder) { 1499 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 1500 try { 1501 mService.releaseMulticastLock(); 1502 synchronized (WifiManager.this) { 1503 mActiveLockCount--; 1504 } 1505 } catch (RemoteException ignore) { 1506 } 1507 mHeld = false; 1508 } 1509 if (mRefCount < 0) { 1510 throw new RuntimeException("MulticastLock under-locked " 1511 + mTag); 1512 } 1513 } 1514 } 1515 1516 /** 1517 * Controls whether this is a reference-counted or non-reference- 1518 * counted MulticastLock. 1519 * 1520 * Reference-counted MulticastLocks keep track of the number of calls 1521 * to {@link #acquire} and {@link #release}, and only stop the 1522 * reception of multicast packets when every call to {@link #acquire} 1523 * has been balanced with a call to {@link #release}. Non-reference- 1524 * counted MulticastLocks allow the reception of multicast packets 1525 * whenever {@link #acquire} is called and stop accepting multicast 1526 * packets whenever {@link #release} is called. 1527 * 1528 * @param refCounted true if this MulticastLock should keep a reference 1529 * count 1530 */ 1531 public void setReferenceCounted(boolean refCounted) { 1532 mRefCounted = refCounted; 1533 } 1534 1535 /** 1536 * Checks whether this MulticastLock is currently held. 1537 * 1538 * @return true if this MulticastLock is held, false otherwise 1539 */ 1540 public boolean isHeld() { 1541 synchronized (mBinder) { 1542 return mHeld; 1543 } 1544 } 1545 1546 public String toString() { 1547 String s1, s2, s3; 1548 synchronized (mBinder) { 1549 s1 = Integer.toHexString(System.identityHashCode(this)); 1550 s2 = mHeld ? "held; " : ""; 1551 if (mRefCounted) { 1552 s3 = "refcounted: refcount = " + mRefCount; 1553 } else { 1554 s3 = "not refcounted"; 1555 } 1556 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }"; 1557 } 1558 } 1559 1560 @Override 1561 protected void finalize() throws Throwable { 1562 super.finalize(); 1563 setReferenceCounted(false); 1564 release(); 1565 } 1566 } 1567 1568 /** 1569 * Check multicast filter status. 1570 * 1571 * @return true if multicast packets are allowed. 1572 * 1573 * @hide pending API council approval 1574 */ 1575 public boolean isMulticastEnabled() { 1576 try { 1577 return mService.isMulticastEnabled(); 1578 } catch (RemoteException e) { 1579 return false; 1580 } 1581 } 1582 1583 /** 1584 * Initialize the multicast filtering to 'on' 1585 * @hide no intent to publish 1586 */ 1587 public boolean initializeMulticastFiltering() { 1588 try { 1589 mService.initializeMulticastFiltering(); 1590 return true; 1591 } catch (RemoteException e) { 1592 return false; 1593 } 1594 } 1595} 1596