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