WifiManager.java revision 738803fee62a98f244250996380820c4923e7f7b
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.net.wifi.ScanSettings; 24import android.net.wifi.WifiChannel; 25import android.os.Binder; 26import android.os.IBinder; 27import android.os.Handler; 28import android.os.HandlerThread; 29import android.os.Looper; 30import android.os.Message; 31import android.os.RemoteException; 32import android.os.WorkSource; 33import android.os.Messenger; 34import android.util.Log; 35import android.util.SparseArray; 36 37import java.net.InetAddress; 38import java.util.concurrent.CountDownLatch; 39 40import com.android.internal.util.AsyncChannel; 41import com.android.internal.util.Protocol; 42 43import java.util.List; 44 45/** 46 * This class provides the primary API for managing all aspects of Wi-Fi 47 * connectivity. Get an instance of this class by calling 48 * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}. 49 50 * It deals with several categories of items: 51 * <ul> 52 * <li>The list of configured networks. The list can be viewed and updated, 53 * and attributes of individual entries can be modified.</li> 54 * <li>The currently active Wi-Fi network, if any. Connectivity can be 55 * established or torn down, and dynamic information about the state of 56 * the network can be queried.</li> 57 * <li>Results of access point scans, containing enough information to 58 * make decisions about what access point to connect to.</li> 59 * <li>It defines the names of various Intent actions that are broadcast 60 * upon any sort of change in Wi-Fi state. 61 * </ul> 62 * This is the API to use when performing Wi-Fi specific operations. To 63 * perform operations that pertain to network connectivity at an abstract 64 * level, use {@link android.net.ConnectivityManager}. 65 */ 66public class WifiManager { 67 68 private static final String TAG = "WifiManager"; 69 // Supplicant error codes: 70 /** 71 * The error code if there was a problem authenticating. 72 */ 73 public static final int ERROR_AUTHENTICATING = 1; 74 75 /** 76 * Broadcast intent action indicating whether Wi-Fi scanning is allowed currently 77 * @hide 78 */ 79 public static final String WIFI_SCAN_AVAILABLE = "wifi_scan_available"; 80 81 /** 82 * Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED 83 * @hide 84 */ 85 public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled"; 86 87 /** 88 * Broadcast intent action indicating that Wi-Fi has been enabled, disabled, 89 * enabling, disabling, or unknown. One extra provides this state as an int. 90 * Another extra provides the previous state, if available. 91 * 92 * @see #EXTRA_WIFI_STATE 93 * @see #EXTRA_PREVIOUS_WIFI_STATE 94 */ 95 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 96 public static final String WIFI_STATE_CHANGED_ACTION = 97 "android.net.wifi.WIFI_STATE_CHANGED"; 98 /** 99 * The lookup key for an int that indicates whether Wi-Fi is enabled, 100 * disabled, enabling, disabling, or unknown. Retrieve it with 101 * {@link android.content.Intent#getIntExtra(String,int)}. 102 * 103 * @see #WIFI_STATE_DISABLED 104 * @see #WIFI_STATE_DISABLING 105 * @see #WIFI_STATE_ENABLED 106 * @see #WIFI_STATE_ENABLING 107 * @see #WIFI_STATE_UNKNOWN 108 */ 109 public static final String EXTRA_WIFI_STATE = "wifi_state"; 110 /** 111 * The previous Wi-Fi state. 112 * 113 * @see #EXTRA_WIFI_STATE 114 */ 115 public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state"; 116 117 /** 118 * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if 119 * it finishes successfully. 120 * 121 * @see #WIFI_STATE_CHANGED_ACTION 122 * @see #getWifiState() 123 */ 124 public static final int WIFI_STATE_DISABLING = 0; 125 /** 126 * Wi-Fi is disabled. 127 * 128 * @see #WIFI_STATE_CHANGED_ACTION 129 * @see #getWifiState() 130 */ 131 public static final int WIFI_STATE_DISABLED = 1; 132 /** 133 * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if 134 * it finishes successfully. 135 * 136 * @see #WIFI_STATE_CHANGED_ACTION 137 * @see #getWifiState() 138 */ 139 public static final int WIFI_STATE_ENABLING = 2; 140 /** 141 * Wi-Fi is enabled. 142 * 143 * @see #WIFI_STATE_CHANGED_ACTION 144 * @see #getWifiState() 145 */ 146 public static final int WIFI_STATE_ENABLED = 3; 147 /** 148 * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling 149 * or disabling. 150 * 151 * @see #WIFI_STATE_CHANGED_ACTION 152 * @see #getWifiState() 153 */ 154 public static final int WIFI_STATE_UNKNOWN = 4; 155 156 /** 157 * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled, 158 * enabling, disabling, or failed. 159 * 160 * @hide 161 */ 162 public static final String WIFI_AP_STATE_CHANGED_ACTION = 163 "android.net.wifi.WIFI_AP_STATE_CHANGED"; 164 165 /** 166 * The lookup key for an int that indicates whether Wi-Fi AP is enabled, 167 * disabled, enabling, disabling, or failed. Retrieve it with 168 * {@link android.content.Intent#getIntExtra(String,int)}. 169 * 170 * @see #WIFI_AP_STATE_DISABLED 171 * @see #WIFI_AP_STATE_DISABLING 172 * @see #WIFI_AP_STATE_ENABLED 173 * @see #WIFI_AP_STATE_ENABLING 174 * @see #WIFI_AP_STATE_FAILED 175 * 176 * @hide 177 */ 178 public static final String EXTRA_WIFI_AP_STATE = "wifi_state"; 179 /** 180 * The previous Wi-Fi state. 181 * 182 * @see #EXTRA_WIFI_AP_STATE 183 * 184 * @hide 185 */ 186 public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state"; 187 /** 188 * Wi-Fi AP is currently being disabled. The state will change to 189 * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully. 190 * 191 * @see #WIFI_AP_STATE_CHANGED_ACTION 192 * @see #getWifiApState() 193 * 194 * @hide 195 */ 196 public static final int WIFI_AP_STATE_DISABLING = 10; 197 /** 198 * Wi-Fi AP is disabled. 199 * 200 * @see #WIFI_AP_STATE_CHANGED_ACTION 201 * @see #getWifiState() 202 * 203 * @hide 204 */ 205 public static final int WIFI_AP_STATE_DISABLED = 11; 206 /** 207 * Wi-Fi AP is currently being enabled. The state will change to 208 * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully. 209 * 210 * @see #WIFI_AP_STATE_CHANGED_ACTION 211 * @see #getWifiApState() 212 * 213 * @hide 214 */ 215 public static final int WIFI_AP_STATE_ENABLING = 12; 216 /** 217 * Wi-Fi AP is enabled. 218 * 219 * @see #WIFI_AP_STATE_CHANGED_ACTION 220 * @see #getWifiApState() 221 * 222 * @hide 223 */ 224 public static final int WIFI_AP_STATE_ENABLED = 13; 225 /** 226 * Wi-Fi AP is in a failed state. This state will occur when an error occurs during 227 * enabling or disabling 228 * 229 * @see #WIFI_AP_STATE_CHANGED_ACTION 230 * @see #getWifiApState() 231 * 232 * @hide 233 */ 234 public static final int WIFI_AP_STATE_FAILED = 14; 235 236 /** 237 * Broadcast intent action indicating that a connection to the supplicant has 238 * been established (and it is now possible 239 * to perform Wi-Fi operations) or the connection to the supplicant has been 240 * lost. One extra provides the connection state as a boolean, where {@code true} 241 * means CONNECTED. 242 * @see #EXTRA_SUPPLICANT_CONNECTED 243 */ 244 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 245 public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION = 246 "android.net.wifi.supplicant.CONNECTION_CHANGE"; 247 /** 248 * The lookup key for a boolean that indicates whether a connection to 249 * the supplicant daemon has been gained or lost. {@code true} means 250 * a connection now exists. 251 * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. 252 */ 253 public static final String EXTRA_SUPPLICANT_CONNECTED = "connected"; 254 /** 255 * Broadcast intent action indicating that the state of Wi-Fi connectivity 256 * has changed. One extra provides the new state 257 * in the form of a {@link android.net.NetworkInfo} object. If the new 258 * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of 259 * the access point. 260 * as a {@code String}. 261 * @see #EXTRA_NETWORK_INFO 262 * @see #EXTRA_BSSID 263 * @see #EXTRA_WIFI_INFO 264 */ 265 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 266 public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"; 267 /** 268 * The lookup key for a {@link android.net.NetworkInfo} object associated with the 269 * Wi-Fi network. Retrieve with 270 * {@link android.content.Intent#getParcelableExtra(String)}. 271 */ 272 public static final String EXTRA_NETWORK_INFO = "networkInfo"; 273 /** 274 * The lookup key for a String giving the BSSID of the access point to which 275 * we are connected. Only present when the new state is CONNECTED. 276 * Retrieve with 277 * {@link android.content.Intent#getStringExtra(String)}. 278 */ 279 public static final String EXTRA_BSSID = "bssid"; 280 /** 281 * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the 282 * information about the access point to which we are connected. Only present 283 * when the new state is CONNECTED. Retrieve with 284 * {@link android.content.Intent#getParcelableExtra(String)}. 285 */ 286 public static final String EXTRA_WIFI_INFO = "wifiInfo"; 287 /** 288 * Broadcast intent action indicating that the state of establishing a connection to 289 * an access point has changed.One extra provides the new 290 * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and 291 * is not generally the most useful thing to look at if you are just interested in 292 * the overall state of connectivity. 293 * @see #EXTRA_NEW_STATE 294 * @see #EXTRA_SUPPLICANT_ERROR 295 */ 296 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 297 public static final String SUPPLICANT_STATE_CHANGED_ACTION = 298 "android.net.wifi.supplicant.STATE_CHANGE"; 299 /** 300 * The lookup key for a {@link SupplicantState} describing the new state 301 * Retrieve with 302 * {@link android.content.Intent#getParcelableExtra(String)}. 303 */ 304 public static final String EXTRA_NEW_STATE = "newState"; 305 306 /** 307 * The lookup key for a {@link SupplicantState} describing the supplicant 308 * error code if any 309 * Retrieve with 310 * {@link android.content.Intent#getIntExtra(String, int)}. 311 * @see #ERROR_AUTHENTICATING 312 */ 313 public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError"; 314 315 /** 316 * Broadcast intent action indicating that the configured networks changed. 317 * This can be as a result of adding/updating/deleting a network. If 318 * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set to true the new configuration 319 * can be retreived with the {@link #EXTRA_WIFI_CONFIGURATION} extra. If multiple 320 * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present. 321 * @hide 322 */ 323 public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = 324 "android.net.wifi.CONFIGURED_NETWORKS_CHANGE"; 325 /** 326 * The lookup key for a (@link android.net.wifi.WifiConfiguration} object representing 327 * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION} 328 * broadcast is sent. 329 * @hide 330 */ 331 public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration"; 332 /** 333 * Multiple network configurations have changed. 334 * @see #CONFIGURED_NETWORKS_CHANGED_ACTION 335 * 336 * @hide 337 */ 338 public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges"; 339 /** 340 * The lookup key for an integer indicating the reason a Wi-Fi network configuration 341 * has changed. Only present if {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is {@code false} 342 * @see #CONFIGURED_NETWORKS_CHANGED_ACTION 343 * @hide 344 */ 345 public static final String EXTRA_CHANGE_REASON = "changeReason"; 346 /** 347 * The configuration is new and was added. 348 * @hide 349 */ 350 public static final int CHANGE_REASON_ADDED = 0; 351 /** 352 * The configuration was removed and is no longer present in the system's list of 353 * configured networks. 354 * @hide 355 */ 356 public static final int CHANGE_REASON_REMOVED = 1; 357 /** 358 * The configuration has changed as a result of explicit action or because the system 359 * took an automated action such as disabling a malfunctioning configuration. 360 * @hide 361 */ 362 public static final int CHANGE_REASON_CONFIG_CHANGE = 2; 363 /** 364 * An access point scan has completed, and results are available from the supplicant. 365 * Call {@link #getScanResults()} to obtain the results. 366 */ 367 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 368 public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS"; 369 /** 370 * A batch of access point scans has been completed and the results areavailable. 371 * Call {@link #getBatchedScanResults()} to obtain the results. 372 * @hide pending review 373 */ 374 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 375 public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION = 376 "android.net.wifi.BATCHED_RESULTS"; 377 /** 378 * The RSSI (signal strength) has changed. 379 * @see #EXTRA_NEW_RSSI 380 */ 381 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 382 public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED"; 383 /** 384 * The lookup key for an {@code int} giving the new RSSI in dBm. 385 */ 386 public static final String EXTRA_NEW_RSSI = "newRssi"; 387 388 /** 389 * Broadcast intent action indicating that the link configuration 390 * changed on wifi. 391 * @hide 392 */ 393 public static final String LINK_CONFIGURATION_CHANGED_ACTION = 394 "android.net.wifi.LINK_CONFIGURATION_CHANGED"; 395 396 /** 397 * The lookup key for a {@link android.net.LinkProperties} object associated with the 398 * Wi-Fi network. Retrieve with 399 * {@link android.content.Intent#getParcelableExtra(String)}. 400 * @hide 401 */ 402 public static final String EXTRA_LINK_PROPERTIES = "linkProperties"; 403 404 /** 405 * The lookup key for a {@link android.net.LinkCapabilities} object associated with the 406 * Wi-Fi network. Retrieve with 407 * {@link android.content.Intent#getParcelableExtra(String)}. 408 * @hide 409 */ 410 public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities"; 411 412 /** 413 * The network IDs of the configured networks could have changed. 414 */ 415 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 416 public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED"; 417 418 /** 419 * Activity Action: Show a system activity that allows the user to enable 420 * scans to be available even with Wi-Fi turned off. 421 * 422 * <p>Notification of the result of this activity is posted using the 423 * {@link android.app.Activity#onActivityResult} callback. The 424 * <code>resultCode</code> 425 * will be {@link android.app.Activity#RESULT_OK} if scan always mode has 426 * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user 427 * has rejected the request or an error has occurred. 428 */ 429 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 430 public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = 431 "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE"; 432 433 /** 434 * Activity Action: Pick a Wi-Fi network to connect to. 435 * <p>Input: Nothing. 436 * <p>Output: Nothing. 437 */ 438 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 439 public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; 440 441 /** 442 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 443 * and will behave normally, i.e., it will attempt to automatically 444 * establish a connection to a remembered access point that is 445 * within range, and will do periodic scans if there are remembered 446 * access points but none are in range. 447 */ 448 public static final int WIFI_MODE_FULL = 1; 449 /** 450 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 451 * but the only operation that will be supported is initiation of 452 * scans, and the subsequent reporting of scan results. No attempts 453 * will be made to automatically connect to remembered access points, 454 * nor will periodic scans be automatically performed looking for 455 * remembered access points. Scans must be explicitly requested by 456 * an application in this mode. 457 */ 458 public static final int WIFI_MODE_SCAN_ONLY = 2; 459 /** 460 * In this Wi-Fi lock mode, Wi-Fi will be kept active as in mode 461 * {@link #WIFI_MODE_FULL} but it operates at high performance 462 * with minimum packet loss and low packet latency even when 463 * the device screen is off. This mode will consume more power 464 * and hence should be used only when there is a need for such 465 * an active connection. 466 * <p> 467 * An example use case is when a voice connection needs to be 468 * kept active even after the device screen goes off. Holding the 469 * regular {@link #WIFI_MODE_FULL} lock will keep the wifi 470 * connection active, but the connection can be lossy. 471 * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the 472 * duration of the voice call will improve the call quality. 473 * <p> 474 * When there is no support from the hardware, this lock mode 475 * will have the same behavior as {@link #WIFI_MODE_FULL} 476 */ 477 public static final int WIFI_MODE_FULL_HIGH_PERF = 3; 478 479 /** Anything worse than or equal to this will show 0 bars. */ 480 private static final int MIN_RSSI = -100; 481 482 /** Anything better than or equal to this will show the max bars. */ 483 private static final int MAX_RSSI = -55; 484 485 /** 486 * Number of RSSI levels used in the framework to initiate 487 * {@link #RSSI_CHANGED_ACTION} broadcast 488 * @hide 489 */ 490 public static final int RSSI_LEVELS = 5; 491 492 /** 493 * Auto settings in the driver. The driver could choose to operate on both 494 * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band. 495 * @hide 496 */ 497 public static final int WIFI_FREQUENCY_BAND_AUTO = 0; 498 499 /** 500 * Operation on 5 GHz alone 501 * @hide 502 */ 503 public static final int WIFI_FREQUENCY_BAND_5GHZ = 1; 504 505 /** 506 * Operation on 2.4 GHz alone 507 * @hide 508 */ 509 public static final int WIFI_FREQUENCY_BAND_2GHZ = 2; 510 511 /** List of asyncronous notifications 512 * @hide 513 */ 514 public static final int DATA_ACTIVITY_NOTIFICATION = 1; 515 516 //Lowest bit indicates data reception and the second lowest 517 //bit indicates data transmitted 518 /** @hide */ 519 public static final int DATA_ACTIVITY_NONE = 0x00; 520 /** @hide */ 521 public static final int DATA_ACTIVITY_IN = 0x01; 522 /** @hide */ 523 public static final int DATA_ACTIVITY_OUT = 0x02; 524 /** @hide */ 525 public static final int DATA_ACTIVITY_INOUT = 0x03; 526 527 /** @hide */ 528 public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false; 529 530 /* Maximum number of active locks we allow. 531 * This limit was added to prevent apps from creating a ridiculous number 532 * of locks and crashing the system by overflowing the global ref table. 533 */ 534 private static final int MAX_ACTIVE_LOCKS = 50; 535 536 /* Number of currently active WifiLocks and MulticastLocks */ 537 private int mActiveLockCount; 538 539 private Context mContext; 540 IWifiManager mService; 541 542 private static final int INVALID_KEY = 0; 543 private static int sListenerKey = 1; 544 private static final SparseArray sListenerMap = new SparseArray(); 545 private static final Object sListenerMapLock = new Object(); 546 547 private static AsyncChannel sAsyncChannel; 548 private static CountDownLatch sConnected; 549 550 private static final Object sThreadRefLock = new Object(); 551 private static int sThreadRefCount; 552 private static HandlerThread sHandlerThread; 553 554 /** 555 * Create a new WifiManager instance. 556 * Applications will almost always want to use 557 * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve 558 * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. 559 * @param context the application context 560 * @param service the Binder interface 561 * @hide - hide this because it takes in a parameter of type IWifiManager, which 562 * is a system private class. 563 */ 564 public WifiManager(Context context, IWifiManager service) { 565 mContext = context; 566 mService = service; 567 init(); 568 } 569 570 /** 571 * Return a list of all the networks configured in the supplicant. 572 * Not all fields of WifiConfiguration are returned. Only the following 573 * fields are filled in: 574 * <ul> 575 * <li>networkId</li> 576 * <li>SSID</li> 577 * <li>BSSID</li> 578 * <li>priority</li> 579 * <li>allowedProtocols</li> 580 * <li>allowedKeyManagement</li> 581 * <li>allowedAuthAlgorithms</li> 582 * <li>allowedPairwiseCiphers</li> 583 * <li>allowedGroupCiphers</li> 584 * </ul> 585 * @return a list of network configurations in the form of a list 586 * of {@link WifiConfiguration} objects. Upon failure to fetch or 587 * when when Wi-Fi is turned off, it can be null. 588 */ 589 public List<WifiConfiguration> getConfiguredNetworks() { 590 try { 591 return mService.getConfiguredNetworks(); 592 } catch (RemoteException e) { 593 return null; 594 } 595 } 596 597 /** 598 * Add a new network description to the set of configured networks. 599 * The {@code networkId} field of the supplied configuration object 600 * is ignored. 601 * <p/> 602 * The new network will be marked DISABLED by default. To enable it, 603 * called {@link #enableNetwork}. 604 * 605 * @param config the set of variables that describe the configuration, 606 * contained in a {@link WifiConfiguration} object. 607 * @return the ID of the newly created network description. This is used in 608 * other operations to specified the network to be acted upon. 609 * Returns {@code -1} on failure. 610 */ 611 public int addNetwork(WifiConfiguration config) { 612 if (config == null) { 613 return -1; 614 } 615 config.networkId = -1; 616 return addOrUpdateNetwork(config); 617 } 618 619 /** 620 * Update the network description of an existing configured network. 621 * 622 * @param config the set of variables that describe the configuration, 623 * contained in a {@link WifiConfiguration} object. It may 624 * be sparse, so that only the items that are being changed 625 * are non-<code>null</code>. The {@code networkId} field 626 * must be set to the ID of the existing network being updated. 627 * @return Returns the {@code networkId} of the supplied 628 * {@code WifiConfiguration} on success. 629 * <br/> 630 * Returns {@code -1} on failure, including when the {@code networkId} 631 * field of the {@code WifiConfiguration} does not refer to an 632 * existing network. 633 */ 634 public int updateNetwork(WifiConfiguration config) { 635 if (config == null || config.networkId < 0) { 636 return -1; 637 } 638 return addOrUpdateNetwork(config); 639 } 640 641 /** 642 * Internal method for doing the RPC that creates a new network description 643 * or updates an existing one. 644 * 645 * @param config The possibly sparse object containing the variables that 646 * are to set or updated in the network description. 647 * @return the ID of the network on success, {@code -1} on failure. 648 */ 649 private int addOrUpdateNetwork(WifiConfiguration config) { 650 try { 651 return mService.addOrUpdateNetwork(config); 652 } catch (RemoteException e) { 653 return -1; 654 } 655 } 656 657 /** 658 * Remove the specified network from the list of configured networks. 659 * This may result in the asynchronous delivery of state change 660 * events. 661 * @param netId the integer that identifies the network configuration 662 * to the supplicant 663 * @return {@code true} if the operation succeeded 664 */ 665 public boolean removeNetwork(int netId) { 666 try { 667 return mService.removeNetwork(netId); 668 } catch (RemoteException e) { 669 return false; 670 } 671 } 672 673 /** 674 * Allow a previously configured network to be associated with. If 675 * <code>disableOthers</code> is true, then all other configured 676 * networks are disabled, and an attempt to connect to the selected 677 * network is initiated. This may result in the asynchronous delivery 678 * of state change events. 679 * @param netId the ID of the network in the list of configured networks 680 * @param disableOthers if true, disable all other networks. The way to 681 * select a particular network to connect to is specify {@code true} 682 * for this parameter. 683 * @return {@code true} if the operation succeeded 684 */ 685 public boolean enableNetwork(int netId, boolean disableOthers) { 686 try { 687 return mService.enableNetwork(netId, disableOthers); 688 } catch (RemoteException e) { 689 return false; 690 } 691 } 692 693 /** 694 * Disable a configured network. The specified network will not be 695 * a candidate for associating. This may result in the asynchronous 696 * delivery of state change events. 697 * @param netId the ID of the network as returned by {@link #addNetwork}. 698 * @return {@code true} if the operation succeeded 699 */ 700 public boolean disableNetwork(int netId) { 701 try { 702 return mService.disableNetwork(netId); 703 } catch (RemoteException e) { 704 return false; 705 } 706 } 707 708 /** 709 * Disassociate from the currently active access point. This may result 710 * in the asynchronous delivery of state change events. 711 * @return {@code true} if the operation succeeded 712 */ 713 public boolean disconnect() { 714 try { 715 mService.disconnect(); 716 return true; 717 } catch (RemoteException e) { 718 return false; 719 } 720 } 721 722 /** 723 * Reconnect to the currently active access point, if we are currently 724 * disconnected. This may result in the asynchronous delivery of state 725 * change events. 726 * @return {@code true} if the operation succeeded 727 */ 728 public boolean reconnect() { 729 try { 730 mService.reconnect(); 731 return true; 732 } catch (RemoteException e) { 733 return false; 734 } 735 } 736 737 /** 738 * Reconnect to the currently active access point, even if we are already 739 * connected. This may result in the asynchronous delivery of state 740 * change events. 741 * @return {@code true} if the operation succeeded 742 */ 743 public boolean reassociate() { 744 try { 745 mService.reassociate(); 746 return true; 747 } catch (RemoteException e) { 748 return false; 749 } 750 } 751 752 /** 753 * Check that the supplicant daemon is responding to requests. 754 * @return {@code true} if we were able to communicate with the supplicant and 755 * it returned the expected response to the PING message. 756 */ 757 public boolean pingSupplicant() { 758 if (mService == null) 759 return false; 760 try { 761 return mService.pingSupplicant(); 762 } catch (RemoteException e) { 763 return false; 764 } 765 } 766 767 /** 768 * Get a list of available channels for customized scan. 769 * 770 * @see {@link WifiChannel} 771 * 772 * @return the channel list, or null if not available 773 * @hide 774 */ 775 public List<WifiChannel> getChannelList() { 776 try { 777 return mService.getChannelList(); 778 } catch (RemoteException e) { 779 return null; 780 } 781 } 782 783 /** 784 * Request a scan for access points. Returns immediately. The availability 785 * of the results is made known later by means of an asynchronous event sent 786 * on completion of the scan. 787 * @return {@code true} if the operation succeeded, i.e., the scan was initiated 788 */ 789 public boolean startScan() { 790 try { 791 mService.startScan(null, null); 792 return true; 793 } catch (RemoteException e) { 794 return false; 795 } 796 } 797 798 /** @hide */ 799 public boolean startScan(WorkSource workSource) { 800 try { 801 mService.startScan(null, workSource); 802 return true; 803 } catch (RemoteException e) { 804 return false; 805 } 806 } 807 808 /** 809 * Request a scan for access points in specified channel list. Each channel is specified by its 810 * frequency in MHz, e.g. "5500" (do NOT include "DFS" even though it is). The availability of 811 * the results is made known later in the same way as {@link #startScan}. 812 * 813 * Note: 814 * 815 * 1. Customized scan is for non-connection purposes, i.e. it won't trigger a wifi connection 816 * even though it finds some known networks. 817 * 818 * 2. Customized scan result may include access points that is not specified in the channel 819 * list. An app will need to do frequency filtering if it wants to get pure results for the 820 * channel list it specified. 821 * 822 * @hide 823 */ 824 public boolean startCustomizedScan(ScanSettings requested) { 825 try { 826 mService.startScan(requested, null); 827 return true; 828 } catch (RemoteException e) { 829 return false; 830 } 831 } 832 833 /** @hide */ 834 public boolean startCustomizedScan(ScanSettings requested, WorkSource workSource) { 835 try { 836 mService.startScan(requested, workSource); 837 return true; 838 } catch (RemoteException e) { 839 return false; 840 } 841 } 842 843 /** 844 * Request a batched scan for access points. To end your requested batched scan, 845 * call stopBatchedScan with the same Settings. 846 * 847 * If there are mulitple requests for batched scans, the more demanding settings will 848 * take precidence. 849 * 850 * @param requested {@link BatchedScanSettings} the scan settings requested. 851 * @return false on known error 852 * @hide 853 */ 854 public boolean requestBatchedScan(BatchedScanSettings requested) { 855 try { 856 return mService.requestBatchedScan(requested, new Binder(), null); 857 } catch (RemoteException e) { return false; } 858 } 859 /** @hide */ 860 public boolean requestBatchedScan(BatchedScanSettings requested, WorkSource workSource) { 861 try { 862 return mService.requestBatchedScan(requested, new Binder(), workSource); 863 } catch (RemoteException e) { return false; } 864 } 865 866 /** 867 * Check if the Batched Scan feature is supported. 868 * 869 * @return false if not supported. 870 * @hide 871 */ 872 public boolean isBatchedScanSupported() { 873 try { 874 return mService.isBatchedScanSupported(); 875 } catch (RemoteException e) { return false; } 876 } 877 878 /** 879 * End a requested batch scan for this applicaiton. Note that batched scan may 880 * still occur if other apps are using them. 881 * 882 * @param requested {@link BatchedScanSettings} the scan settings you previously requested 883 * and now wish to stop. A value of null here will stop all scans requested by the 884 * calling App. 885 * @hide 886 */ 887 public void stopBatchedScan(BatchedScanSettings requested) { 888 try { 889 mService.stopBatchedScan(requested); 890 } catch (RemoteException e) {} 891 } 892 893 /** 894 * Retrieve the latest batched scan result. This should be called immediately after 895 * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received. 896 * @hide 897 */ 898 public List<BatchedScanResult> getBatchedScanResults() { 899 try { 900 return mService.getBatchedScanResults(mContext.getOpPackageName()); 901 } catch (RemoteException e) { 902 return null; 903 } 904 } 905 906 /** 907 * Force a re-reading of batched scan results. This will attempt 908 * to read more information from the chip, but will do so at the expense 909 * of previous data. Rate limited to the current scan frequency. 910 * 911 * pollBatchedScan will always wait 1 period from the start of the batch 912 * before trying to read from the chip, so if your #scans/batch == 1 this will 913 * have no effect. 914 * 915 * If you had already waited 1 period before calling, this should have 916 * immediate (though async) effect. 917 * 918 * If you call before that 1 period is up this will set up a timer and fetch 919 * results when the 1 period is up. 920 * 921 * Servicing a pollBatchedScan request (immediate or after timed delay) starts a 922 * new batch, so if you were doing 10 scans/batch and called in the 4th scan, you 923 * would get data in the 4th and then again 10 scans later. 924 * @hide 925 */ 926 public void pollBatchedScan() { 927 try { 928 mService.pollBatchedScan(); 929 } catch (RemoteException e) { } 930 } 931 932 /** 933 * Return dynamic information about the current Wi-Fi connection, if any is active. 934 * @return the Wi-Fi information, contained in {@link WifiInfo}. 935 */ 936 public WifiInfo getConnectionInfo() { 937 try { 938 return mService.getConnectionInfo(); 939 } catch (RemoteException e) { 940 return null; 941 } 942 } 943 944 /** 945 * Return the results of the latest access point scan. 946 * @return the list of access points found in the most recent scan. 947 */ 948 public List<ScanResult> getScanResults() { 949 try { 950 return mService.getScanResults(mContext.getOpPackageName()); 951 } catch (RemoteException e) { 952 return null; 953 } 954 } 955 956 /** 957 * Check if scanning is always available. 958 * 959 * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results 960 * even when Wi-Fi is turned off. 961 * 962 * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}. 963 */ 964 public boolean isScanAlwaysAvailable() { 965 try { 966 return mService.isScanAlwaysAvailable(); 967 } catch (RemoteException e) { 968 return false; 969 } 970 } 971 972 /** 973 * Tell the supplicant to persist the current list of configured networks. 974 * <p> 975 * Note: It is possible for this method to change the network IDs of 976 * existing networks. You should assume the network IDs can be different 977 * after calling this method. 978 * 979 * @return {@code true} if the operation succeeded 980 */ 981 public boolean saveConfiguration() { 982 try { 983 return mService.saveConfiguration(); 984 } catch (RemoteException e) { 985 return false; 986 } 987 } 988 989 /** 990 * Set the country code. 991 * @param countryCode country code in ISO 3166 format. 992 * @param persist {@code true} if this needs to be remembered 993 * 994 * @hide 995 */ 996 public void setCountryCode(String country, boolean persist) { 997 try { 998 mService.setCountryCode(country, persist); 999 } catch (RemoteException e) { } 1000 } 1001 1002 /** 1003 * Set the operational frequency band. 1004 * @param band One of 1005 * {@link #WIFI_FREQUENCY_BAND_AUTO}, 1006 * {@link #WIFI_FREQUENCY_BAND_5GHZ}, 1007 * {@link #WIFI_FREQUENCY_BAND_2GHZ}, 1008 * @param persist {@code true} if this needs to be remembered 1009 * @hide 1010 */ 1011 public void setFrequencyBand(int band, boolean persist) { 1012 try { 1013 mService.setFrequencyBand(band, persist); 1014 } catch (RemoteException e) { } 1015 } 1016 1017 /** 1018 * Get the operational frequency band. 1019 * @return One of 1020 * {@link #WIFI_FREQUENCY_BAND_AUTO}, 1021 * {@link #WIFI_FREQUENCY_BAND_5GHZ}, 1022 * {@link #WIFI_FREQUENCY_BAND_2GHZ} or 1023 * {@code -1} on failure. 1024 * @hide 1025 */ 1026 public int getFrequencyBand() { 1027 try { 1028 return mService.getFrequencyBand(); 1029 } catch (RemoteException e) { 1030 return -1; 1031 } 1032 } 1033 1034 /** 1035 * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz) 1036 * @return {@code true} if supported, {@code false} otherwise. 1037 * @hide 1038 */ 1039 public boolean isDualBandSupported() { 1040 try { 1041 return mService.isDualBandSupported(); 1042 } catch (RemoteException e) { 1043 return false; 1044 } 1045 } 1046 1047 /** 1048 * Return the DHCP-assigned addresses from the last successful DHCP request, 1049 * if any. 1050 * @return the DHCP information 1051 */ 1052 public DhcpInfo getDhcpInfo() { 1053 try { 1054 return mService.getDhcpInfo(); 1055 } catch (RemoteException e) { 1056 return null; 1057 } 1058 } 1059 1060 /** 1061 * Enable or disable Wi-Fi. 1062 * @param enabled {@code true} to enable, {@code false} to disable. 1063 * @return {@code true} if the operation succeeds (or if the existing state 1064 * is the same as the requested state). 1065 */ 1066 public boolean setWifiEnabled(boolean enabled) { 1067 try { 1068 return mService.setWifiEnabled(enabled); 1069 } catch (RemoteException e) { 1070 return false; 1071 } 1072 } 1073 1074 /** 1075 * Gets the Wi-Fi enabled state. 1076 * @return One of {@link #WIFI_STATE_DISABLED}, 1077 * {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED}, 1078 * {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN} 1079 * @see #isWifiEnabled() 1080 */ 1081 public int getWifiState() { 1082 try { 1083 return mService.getWifiEnabledState(); 1084 } catch (RemoteException e) { 1085 return WIFI_STATE_UNKNOWN; 1086 } 1087 } 1088 1089 /** 1090 * Return whether Wi-Fi is enabled or disabled. 1091 * @return {@code true} if Wi-Fi is enabled 1092 * @see #getWifiState() 1093 */ 1094 public boolean isWifiEnabled() { 1095 return getWifiState() == WIFI_STATE_ENABLED; 1096 } 1097 1098 /** 1099 * Return TX packet counter, for CTS test of WiFi watchdog. 1100 * @param listener is the interface to receive result 1101 * 1102 * @hide for CTS test only 1103 */ 1104 public void getTxPacketCount(TxPacketCountListener listener) { 1105 validateChannel(); 1106 sAsyncChannel.sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener)); 1107 } 1108 1109 /** 1110 * Calculates the level of the signal. This should be used any time a signal 1111 * is being shown. 1112 * 1113 * @param rssi The power of the signal measured in RSSI. 1114 * @param numLevels The number of levels to consider in the calculated 1115 * level. 1116 * @return A level of the signal, given in the range of 0 to numLevels-1 1117 * (both inclusive). 1118 */ 1119 public static int calculateSignalLevel(int rssi, int numLevels) { 1120 if (rssi <= MIN_RSSI) { 1121 return 0; 1122 } else if (rssi >= MAX_RSSI) { 1123 return numLevels - 1; 1124 } else { 1125 float inputRange = (MAX_RSSI - MIN_RSSI); 1126 float outputRange = (numLevels - 1); 1127 return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange); 1128 } 1129 } 1130 1131 /** 1132 * Compares two signal strengths. 1133 * 1134 * @param rssiA The power of the first signal measured in RSSI. 1135 * @param rssiB The power of the second signal measured in RSSI. 1136 * @return Returns <0 if the first signal is weaker than the second signal, 1137 * 0 if the two signals have the same strength, and >0 if the first 1138 * signal is stronger than the second signal. 1139 */ 1140 public static int compareSignalLevel(int rssiA, int rssiB) { 1141 return rssiA - rssiB; 1142 } 1143 1144 /** 1145 * Start AccessPoint mode with the specified 1146 * configuration. If the radio is already running in 1147 * AP mode, update the new configuration 1148 * Note that starting in access point mode disables station 1149 * mode operation 1150 * @param wifiConfig SSID, security and channel details as 1151 * part of WifiConfiguration 1152 * @return {@code true} if the operation succeeds, {@code false} otherwise 1153 * 1154 * @hide Dont open up yet 1155 */ 1156 public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { 1157 try { 1158 mService.setWifiApEnabled(wifiConfig, enabled); 1159 return true; 1160 } catch (RemoteException e) { 1161 return false; 1162 } 1163 } 1164 1165 /** 1166 * Gets the Wi-Fi enabled state. 1167 * @return One of {@link #WIFI_AP_STATE_DISABLED}, 1168 * {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED}, 1169 * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} 1170 * @see #isWifiApEnabled() 1171 * 1172 * @hide Dont open yet 1173 */ 1174 public int getWifiApState() { 1175 try { 1176 return mService.getWifiApEnabledState(); 1177 } catch (RemoteException e) { 1178 return WIFI_AP_STATE_FAILED; 1179 } 1180 } 1181 1182 /** 1183 * Return whether Wi-Fi AP is enabled or disabled. 1184 * @return {@code true} if Wi-Fi AP is enabled 1185 * @see #getWifiApState() 1186 * 1187 * @hide Dont open yet 1188 */ 1189 public boolean isWifiApEnabled() { 1190 return getWifiApState() == WIFI_AP_STATE_ENABLED; 1191 } 1192 1193 /** 1194 * Gets the Wi-Fi AP Configuration. 1195 * @return AP details in WifiConfiguration 1196 * 1197 * @hide Dont open yet 1198 */ 1199 public WifiConfiguration getWifiApConfiguration() { 1200 try { 1201 return mService.getWifiApConfiguration(); 1202 } catch (RemoteException e) { 1203 return null; 1204 } 1205 } 1206 1207 /** 1208 * Sets the Wi-Fi AP Configuration. 1209 * @return {@code true} if the operation succeeded, {@code false} otherwise 1210 * 1211 * @hide Dont open yet 1212 */ 1213 public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) { 1214 try { 1215 mService.setWifiApConfiguration(wifiConfig); 1216 return true; 1217 } catch (RemoteException e) { 1218 return false; 1219 } 1220 } 1221 1222 /** 1223 * Start the driver and connect to network. 1224 * 1225 * This function will over-ride WifiLock and device idle status. For example, 1226 * even if the device is idle or there is only a scan-only lock held, 1227 * a start wifi would mean that wifi connection is kept active until 1228 * a stopWifi() is sent. 1229 * 1230 * This API is used by WifiStateTracker 1231 * 1232 * @return {@code true} if the operation succeeds else {@code false} 1233 * @hide 1234 */ 1235 public boolean startWifi() { 1236 try { 1237 mService.startWifi(); 1238 return true; 1239 } catch (RemoteException e) { 1240 return false; 1241 } 1242 } 1243 1244 /** 1245 * Disconnect from a network (if any) and stop the driver. 1246 * 1247 * This function will over-ride WifiLock and device idle status. Wi-Fi 1248 * stays inactive until a startWifi() is issued. 1249 * 1250 * This API is used by WifiStateTracker 1251 * 1252 * @return {@code true} if the operation succeeds else {@code false} 1253 * @hide 1254 */ 1255 public boolean stopWifi() { 1256 try { 1257 mService.stopWifi(); 1258 return true; 1259 } catch (RemoteException e) { 1260 return false; 1261 } 1262 } 1263 1264 /** 1265 * Add a bssid to the supplicant blacklist 1266 * 1267 * This API is used by WifiWatchdogService 1268 * 1269 * @return {@code true} if the operation succeeds else {@code false} 1270 * @hide 1271 */ 1272 public boolean addToBlacklist(String bssid) { 1273 try { 1274 mService.addToBlacklist(bssid); 1275 return true; 1276 } catch (RemoteException e) { 1277 return false; 1278 } 1279 } 1280 1281 /** 1282 * Clear the supplicant blacklist 1283 * 1284 * This API is used by WifiWatchdogService 1285 * 1286 * @return {@code true} if the operation succeeds else {@code false} 1287 * @hide 1288 */ 1289 public boolean clearBlacklist() { 1290 try { 1291 mService.clearBlacklist(); 1292 return true; 1293 } catch (RemoteException e) { 1294 return false; 1295 } 1296 } 1297 1298 1299 /** 1300 * Enable/Disable TDLS on a specific local route. 1301 * 1302 * <p> 1303 * TDLS enables two wireless endpoints to talk to each other directly 1304 * without going through the access point that is managing the local 1305 * network. It saves bandwidth and improves quality of the link. 1306 * </p> 1307 * <p> 1308 * This API enables/disables the option of using TDLS. If enabled, the 1309 * underlying hardware is free to use TDLS or a hop through the access 1310 * point. If disabled, existing TDLS session is torn down and 1311 * hardware is restricted to use access point for transferring wireless 1312 * packets. Default value for all routes is 'disabled', meaning restricted 1313 * to use access point for transferring packets. 1314 * </p> 1315 * 1316 * @param remoteIPAddress IP address of the endpoint to setup TDLS with 1317 * @param enable true = setup and false = tear down TDLS 1318 */ 1319 public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) { 1320 try { 1321 mService.enableTdls(remoteIPAddress.getHostAddress(), enable); 1322 } catch (RemoteException e) { 1323 // Just ignore the exception 1324 } 1325 } 1326 1327 /** 1328 * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except 1329 * this version allows you to specify remote endpoint with a MAC address. 1330 * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab 1331 * @param enable true = setup and false = tear down TDLS 1332 */ 1333 public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) { 1334 try { 1335 mService.enableTdlsWithMacAddress(remoteMacAddress, enable); 1336 } catch (RemoteException e) { 1337 // Just ignore the exception 1338 } 1339 } 1340 1341 /* TODO: deprecate synchronous API and open up the following API */ 1342 1343 private static final int BASE = Protocol.BASE_WIFI_MANAGER; 1344 1345 /* Commands to WifiService */ 1346 /** @hide */ 1347 public static final int CONNECT_NETWORK = BASE + 1; 1348 /** @hide */ 1349 public static final int CONNECT_NETWORK_FAILED = BASE + 2; 1350 /** @hide */ 1351 public static final int CONNECT_NETWORK_SUCCEEDED = BASE + 3; 1352 1353 /** @hide */ 1354 public static final int FORGET_NETWORK = BASE + 4; 1355 /** @hide */ 1356 public static final int FORGET_NETWORK_FAILED = BASE + 5; 1357 /** @hide */ 1358 public static final int FORGET_NETWORK_SUCCEEDED = BASE + 6; 1359 1360 /** @hide */ 1361 public static final int SAVE_NETWORK = BASE + 7; 1362 /** @hide */ 1363 public static final int SAVE_NETWORK_FAILED = BASE + 8; 1364 /** @hide */ 1365 public static final int SAVE_NETWORK_SUCCEEDED = BASE + 9; 1366 1367 /** @hide */ 1368 public static final int START_WPS = BASE + 10; 1369 /** @hide */ 1370 public static final int START_WPS_SUCCEEDED = BASE + 11; 1371 /** @hide */ 1372 public static final int WPS_FAILED = BASE + 12; 1373 /** @hide */ 1374 public static final int WPS_COMPLETED = BASE + 13; 1375 1376 /** @hide */ 1377 public static final int CANCEL_WPS = BASE + 14; 1378 /** @hide */ 1379 public static final int CANCEL_WPS_FAILED = BASE + 15; 1380 /** @hide */ 1381 public static final int CANCEL_WPS_SUCCEDED = BASE + 16; 1382 1383 /** @hide */ 1384 public static final int DISABLE_NETWORK = BASE + 17; 1385 /** @hide */ 1386 public static final int DISABLE_NETWORK_FAILED = BASE + 18; 1387 /** @hide */ 1388 public static final int DISABLE_NETWORK_SUCCEEDED = BASE + 19; 1389 1390 /** @hide */ 1391 public static final int RSSI_PKTCNT_FETCH = BASE + 20; 1392 /** @hide */ 1393 public static final int RSSI_PKTCNT_FETCH_SUCCEEDED = BASE + 21; 1394 /** @hide */ 1395 public static final int RSSI_PKTCNT_FETCH_FAILED = BASE + 22; 1396 1397 1398 /** 1399 * Passed with {@link ActionListener#onFailure}. 1400 * Indicates that the operation failed due to an internal error. 1401 * @hide 1402 */ 1403 public static final int ERROR = 0; 1404 1405 /** 1406 * Passed with {@link ActionListener#onFailure}. 1407 * Indicates that the operation is already in progress 1408 * @hide 1409 */ 1410 public static final int IN_PROGRESS = 1; 1411 1412 /** 1413 * Passed with {@link ActionListener#onFailure}. 1414 * Indicates that the operation failed because the framework is busy and 1415 * unable to service the request 1416 * @hide 1417 */ 1418 public static final int BUSY = 2; 1419 1420 /* WPS specific errors */ 1421 /** WPS overlap detected {@hide} */ 1422 public static final int WPS_OVERLAP_ERROR = 3; 1423 /** WEP on WPS is prohibited {@hide} */ 1424 public static final int WPS_WEP_PROHIBITED = 4; 1425 /** TKIP only prohibited {@hide} */ 1426 public static final int WPS_TKIP_ONLY_PROHIBITED = 5; 1427 /** Authentication failure on WPS {@hide} */ 1428 public static final int WPS_AUTH_FAILURE = 6; 1429 /** WPS timed out {@hide} */ 1430 public static final int WPS_TIMED_OUT = 7; 1431 1432 /** 1433 * Passed with {@link ActionListener#onFailure}. 1434 * Indicates that the operation failed due to invalid inputs 1435 * @hide 1436 */ 1437 public static final int INVALID_ARGS = 8; 1438 1439 /** Interface for callback invocation on an application action {@hide} */ 1440 public interface ActionListener { 1441 /** The operation succeeded */ 1442 public void onSuccess(); 1443 /** 1444 * The operation failed 1445 * @param reason The reason for failure could be one of 1446 * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY} 1447 */ 1448 public void onFailure(int reason); 1449 } 1450 1451 /** Interface for callback invocation on a start WPS action {@hide} */ 1452 public interface WpsListener { 1453 /** WPS start succeeded */ 1454 public void onStartSuccess(String pin); 1455 1456 /** WPS operation completed succesfully */ 1457 public void onCompletion(); 1458 1459 /** 1460 * WPS operation failed 1461 * @param reason The reason for failure could be one of 1462 * {@link #IN_PROGRESS}, {@link #WPS_OVERLAP_ERROR},{@link #ERROR} or {@link #BUSY} 1463 */ 1464 public void onFailure(int reason); 1465 } 1466 1467 /** Interface for callback invocation on a TX packet count poll action {@hide} */ 1468 public interface TxPacketCountListener { 1469 /** 1470 * The operation succeeded 1471 * @param count TX packet counter 1472 */ 1473 public void onSuccess(int count); 1474 /** 1475 * The operation failed 1476 * @param reason The reason for failure could be one of 1477 * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY} 1478 */ 1479 public void onFailure(int reason); 1480 } 1481 1482 private static class ServiceHandler extends Handler { 1483 ServiceHandler(Looper looper) { 1484 super(looper); 1485 } 1486 1487 @Override 1488 public void handleMessage(Message message) { 1489 Object listener = removeListener(message.arg2); 1490 switch (message.what) { 1491 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 1492 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 1493 sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 1494 } else { 1495 Log.e(TAG, "Failed to set up channel connection"); 1496 // This will cause all further async API calls on the WifiManager 1497 // to fail and throw an exception 1498 sAsyncChannel = null; 1499 } 1500 sConnected.countDown(); 1501 break; 1502 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: 1503 // Ignore 1504 break; 1505 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 1506 Log.e(TAG, "Channel connection lost"); 1507 // This will cause all further async API calls on the WifiManager 1508 // to fail and throw an exception 1509 sAsyncChannel = null; 1510 getLooper().quit(); 1511 break; 1512 /* ActionListeners grouped together */ 1513 case WifiManager.CONNECT_NETWORK_FAILED: 1514 case WifiManager.FORGET_NETWORK_FAILED: 1515 case WifiManager.SAVE_NETWORK_FAILED: 1516 case WifiManager.CANCEL_WPS_FAILED: 1517 case WifiManager.DISABLE_NETWORK_FAILED: 1518 if (listener != null) { 1519 ((ActionListener) listener).onFailure(message.arg1); 1520 } 1521 break; 1522 /* ActionListeners grouped together */ 1523 case WifiManager.CONNECT_NETWORK_SUCCEEDED: 1524 case WifiManager.FORGET_NETWORK_SUCCEEDED: 1525 case WifiManager.SAVE_NETWORK_SUCCEEDED: 1526 case WifiManager.CANCEL_WPS_SUCCEDED: 1527 case WifiManager.DISABLE_NETWORK_SUCCEEDED: 1528 if (listener != null) { 1529 ((ActionListener) listener).onSuccess(); 1530 } 1531 break; 1532 case WifiManager.START_WPS_SUCCEEDED: 1533 if (listener != null) { 1534 WpsResult result = (WpsResult) message.obj; 1535 ((WpsListener) listener).onStartSuccess(result.pin); 1536 //Listener needs to stay until completion or failure 1537 synchronized(sListenerMapLock) { 1538 sListenerMap.put(message.arg2, listener); 1539 } 1540 } 1541 break; 1542 case WifiManager.WPS_COMPLETED: 1543 if (listener != null) { 1544 ((WpsListener) listener).onCompletion(); 1545 } 1546 break; 1547 case WifiManager.WPS_FAILED: 1548 if (listener != null) { 1549 ((WpsListener) listener).onFailure(message.arg1); 1550 } 1551 break; 1552 case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED: 1553 if (listener != null) { 1554 RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj; 1555 if (info != null) 1556 ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad); 1557 else 1558 ((TxPacketCountListener) listener).onFailure(ERROR); 1559 } 1560 break; 1561 case WifiManager.RSSI_PKTCNT_FETCH_FAILED: 1562 if (listener != null) { 1563 ((TxPacketCountListener) listener).onFailure(message.arg1); 1564 } 1565 break; 1566 default: 1567 //ignore 1568 break; 1569 } 1570 } 1571 } 1572 1573 private static int putListener(Object listener) { 1574 if (listener == null) return INVALID_KEY; 1575 int key; 1576 synchronized (sListenerMapLock) { 1577 do { 1578 key = sListenerKey++; 1579 } while (key == INVALID_KEY); 1580 sListenerMap.put(key, listener); 1581 } 1582 return key; 1583 } 1584 1585 private static Object removeListener(int key) { 1586 if (key == INVALID_KEY) return null; 1587 synchronized (sListenerMapLock) { 1588 Object listener = sListenerMap.get(key); 1589 sListenerMap.remove(key); 1590 return listener; 1591 } 1592 } 1593 1594 private void init() { 1595 synchronized (sThreadRefLock) { 1596 if (++sThreadRefCount == 1) { 1597 Messenger messenger = getWifiServiceMessenger(); 1598 if (messenger == null) { 1599 sAsyncChannel = null; 1600 return; 1601 } 1602 1603 sHandlerThread = new HandlerThread("WifiManager"); 1604 sAsyncChannel = new AsyncChannel(); 1605 sConnected = new CountDownLatch(1); 1606 1607 sHandlerThread.start(); 1608 Handler handler = new ServiceHandler(sHandlerThread.getLooper()); 1609 sAsyncChannel.connect(mContext, handler, messenger); 1610 try { 1611 sConnected.await(); 1612 } catch (InterruptedException e) { 1613 Log.e(TAG, "interrupted wait at init"); 1614 } 1615 } 1616 } 1617 } 1618 1619 private void validateChannel() { 1620 if (sAsyncChannel == null) throw new IllegalStateException( 1621 "No permission to access and change wifi or a bad initialization"); 1622 } 1623 1624 /** 1625 * Connect to a network with the given configuration. The network also 1626 * gets added to the supplicant configuration. 1627 * 1628 * For a new network, this function is used instead of a 1629 * sequence of addNetwork(), enableNetwork(), saveConfiguration() and 1630 * reconnect() 1631 * 1632 * @param config the set of variables that describe the configuration, 1633 * contained in a {@link WifiConfiguration} object. 1634 * @param listener for callbacks on success or failure. Can be null. 1635 * @throws IllegalStateException if the WifiManager instance needs to be 1636 * initialized again 1637 * 1638 * @hide 1639 */ 1640 public void connect(WifiConfiguration config, ActionListener listener) { 1641 if (config == null) throw new IllegalArgumentException("config cannot be null"); 1642 validateChannel(); 1643 // Use INVALID_NETWORK_ID for arg1 when passing a config object 1644 // arg1 is used to pass network id when the network already exists 1645 sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID, 1646 putListener(listener), config); 1647 } 1648 1649 /** 1650 * Connect to a network with the given networkId. 1651 * 1652 * This function is used instead of a enableNetwork(), saveConfiguration() and 1653 * reconnect() 1654 * 1655 * @param networkId the network id identifiying the network in the 1656 * supplicant configuration list 1657 * @param listener for callbacks on success or failure. Can be null. 1658 * @throws IllegalStateException if the WifiManager instance needs to be 1659 * initialized again 1660 * @hide 1661 */ 1662 public void connect(int networkId, ActionListener listener) { 1663 if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative"); 1664 validateChannel(); 1665 sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener)); 1666 } 1667 1668 /** 1669 * Save the given network in the supplicant config. If the network already 1670 * exists, the configuration is updated. A new network is enabled 1671 * by default. 1672 * 1673 * For a new network, this function is used instead of a 1674 * sequence of addNetwork(), enableNetwork() and saveConfiguration(). 1675 * 1676 * For an existing network, it accomplishes the task of updateNetwork() 1677 * and saveConfiguration() 1678 * 1679 * @param config the set of variables that describe the configuration, 1680 * contained in a {@link WifiConfiguration} object. 1681 * @param listener for callbacks on success or failure. Can be null. 1682 * @throws IllegalStateException if the WifiManager instance needs to be 1683 * initialized again 1684 * @hide 1685 */ 1686 public void save(WifiConfiguration config, ActionListener listener) { 1687 if (config == null) throw new IllegalArgumentException("config cannot be null"); 1688 validateChannel(); 1689 sAsyncChannel.sendMessage(SAVE_NETWORK, 0, putListener(listener), config); 1690 } 1691 1692 /** 1693 * Delete the network in the supplicant config. 1694 * 1695 * This function is used instead of a sequence of removeNetwork() 1696 * and saveConfiguration(). 1697 * 1698 * @param config the set of variables that describe the configuration, 1699 * contained in a {@link WifiConfiguration} object. 1700 * @param listener for callbacks on success or failure. Can be null. 1701 * @throws IllegalStateException if the WifiManager instance needs to be 1702 * initialized again 1703 * @hide 1704 */ 1705 public void forget(int netId, ActionListener listener) { 1706 if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative"); 1707 validateChannel(); 1708 sAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener)); 1709 } 1710 1711 /** 1712 * Disable network 1713 * 1714 * @param netId is the network Id 1715 * @param listener for callbacks on success or failure. Can be null. 1716 * @throws IllegalStateException if the WifiManager instance needs to be 1717 * initialized again 1718 * @hide 1719 */ 1720 public void disable(int netId, ActionListener listener) { 1721 if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative"); 1722 validateChannel(); 1723 sAsyncChannel.sendMessage(DISABLE_NETWORK, netId, putListener(listener)); 1724 } 1725 1726 /** 1727 * Start Wi-fi Protected Setup 1728 * 1729 * @param config WPS configuration 1730 * @param listener for callbacks on success or failure. Can be null. 1731 * @throws IllegalStateException if the WifiManager instance needs to be 1732 * initialized again 1733 * @hide 1734 */ 1735 public void startWps(WpsInfo config, WpsListener listener) { 1736 if (config == null) throw new IllegalArgumentException("config cannot be null"); 1737 validateChannel(); 1738 sAsyncChannel.sendMessage(START_WPS, 0, putListener(listener), config); 1739 } 1740 1741 /** 1742 * Cancel any ongoing Wi-fi Protected Setup 1743 * 1744 * @param listener for callbacks on success or failure. Can be null. 1745 * @throws IllegalStateException if the WifiManager instance needs to be 1746 * initialized again 1747 * @hide 1748 */ 1749 public void cancelWps(ActionListener listener) { 1750 validateChannel(); 1751 sAsyncChannel.sendMessage(CANCEL_WPS, 0, putListener(listener)); 1752 } 1753 1754 /** 1755 * Get a reference to WifiService handler. This is used by a client to establish 1756 * an AsyncChannel communication with WifiService 1757 * 1758 * @return Messenger pointing to the WifiService handler 1759 * @hide 1760 */ 1761 public Messenger getWifiServiceMessenger() { 1762 try { 1763 return mService.getWifiServiceMessenger(); 1764 } catch (RemoteException e) { 1765 return null; 1766 } catch (SecurityException e) { 1767 return null; 1768 } 1769 } 1770 1771 /** 1772 * Get a reference to WifiStateMachine handler. 1773 * @return Messenger pointing to the WifiService handler 1774 * @hide 1775 */ 1776 public Messenger getWifiStateMachineMessenger() { 1777 try { 1778 return mService.getWifiStateMachineMessenger(); 1779 } catch (RemoteException e) { 1780 return null; 1781 } 1782 } 1783 1784 /** 1785 * Returns the file in which IP and proxy configuration data is stored 1786 * @hide 1787 */ 1788 public String getConfigFile() { 1789 try { 1790 return mService.getConfigFile(); 1791 } catch (RemoteException e) { 1792 return null; 1793 } 1794 } 1795 1796 /** 1797 * Allows an application to keep the Wi-Fi radio awake. 1798 * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. 1799 * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple 1800 * applications may hold WifiLocks, and the radio will only be allowed to turn off when no 1801 * WifiLocks are held in any application. 1802 * <p> 1803 * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or 1804 * could function over a mobile network, if available. A program that needs to download large 1805 * files should hold a WifiLock to ensure that the download will complete, but a program whose 1806 * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely 1807 * affecting battery life. 1808 * <p> 1809 * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane 1810 * Mode. They simply keep the radio from turning off when Wi-Fi is already on but the device 1811 * is idle. 1812 * <p> 1813 * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK} 1814 * permission in an {@code <uses-permission>} element of the application's manifest. 1815 */ 1816 public class WifiLock { 1817 private String mTag; 1818 private final IBinder mBinder; 1819 private int mRefCount; 1820 int mLockType; 1821 private boolean mRefCounted; 1822 private boolean mHeld; 1823 private WorkSource mWorkSource; 1824 1825 private WifiLock(int lockType, String tag) { 1826 mTag = tag; 1827 mLockType = lockType; 1828 mBinder = new Binder(); 1829 mRefCount = 0; 1830 mRefCounted = true; 1831 mHeld = false; 1832 } 1833 1834 /** 1835 * Locks the Wi-Fi radio on until {@link #release} is called. 1836 * 1837 * If this WifiLock is reference-counted, each call to {@code acquire} will increment the 1838 * reference count, and the radio will remain locked as long as the reference count is 1839 * above zero. 1840 * 1841 * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock 1842 * the radio, but subsequent calls will be ignored. Only one call to {@link #release} 1843 * will be required, regardless of the number of times that {@code acquire} is called. 1844 */ 1845 public void acquire() { 1846 synchronized (mBinder) { 1847 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) { 1848 try { 1849 mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource); 1850 synchronized (WifiManager.this) { 1851 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 1852 mService.releaseWifiLock(mBinder); 1853 throw new UnsupportedOperationException( 1854 "Exceeded maximum number of wifi locks"); 1855 } 1856 mActiveLockCount++; 1857 } 1858 } catch (RemoteException ignore) { 1859 } 1860 mHeld = true; 1861 } 1862 } 1863 } 1864 1865 /** 1866 * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle. 1867 * 1868 * If this WifiLock is reference-counted, each call to {@code release} will decrement the 1869 * reference count, and the radio will be unlocked only when the reference count reaches 1870 * zero. If the reference count goes below zero (that is, if {@code release} is called 1871 * a greater number of times than {@link #acquire}), an exception is thrown. 1872 * 1873 * If this WifiLock is not reference-counted, the first call to {@code release} (after 1874 * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent 1875 * calls will be ignored. 1876 */ 1877 public void release() { 1878 synchronized (mBinder) { 1879 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 1880 try { 1881 mService.releaseWifiLock(mBinder); 1882 synchronized (WifiManager.this) { 1883 mActiveLockCount--; 1884 } 1885 } catch (RemoteException ignore) { 1886 } 1887 mHeld = false; 1888 } 1889 if (mRefCount < 0) { 1890 throw new RuntimeException("WifiLock under-locked " + mTag); 1891 } 1892 } 1893 } 1894 1895 /** 1896 * Controls whether this is a reference-counted or non-reference-counted WifiLock. 1897 * 1898 * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and 1899 * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire} 1900 * has been balanced with a call to {@link #release}. Non-reference-counted WifiLocks 1901 * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the 1902 * radio whenever {@link #release} is called and it is locked. 1903 * 1904 * @param refCounted true if this WifiLock should keep a reference count 1905 */ 1906 public void setReferenceCounted(boolean refCounted) { 1907 mRefCounted = refCounted; 1908 } 1909 1910 /** 1911 * Checks whether this WifiLock is currently held. 1912 * 1913 * @return true if this WifiLock is held, false otherwise 1914 */ 1915 public boolean isHeld() { 1916 synchronized (mBinder) { 1917 return mHeld; 1918 } 1919 } 1920 1921 public void setWorkSource(WorkSource ws) { 1922 synchronized (mBinder) { 1923 if (ws != null && ws.size() == 0) { 1924 ws = null; 1925 } 1926 boolean changed = true; 1927 if (ws == null) { 1928 mWorkSource = null; 1929 } else { 1930 ws.clearNames(); 1931 if (mWorkSource == null) { 1932 changed = mWorkSource != null; 1933 mWorkSource = new WorkSource(ws); 1934 } else { 1935 changed = mWorkSource.diff(ws); 1936 if (changed) { 1937 mWorkSource.set(ws); 1938 } 1939 } 1940 } 1941 if (changed && mHeld) { 1942 try { 1943 mService.updateWifiLockWorkSource(mBinder, mWorkSource); 1944 } catch (RemoteException e) { 1945 } 1946 } 1947 } 1948 } 1949 1950 public String toString() { 1951 String s1, s2, s3; 1952 synchronized (mBinder) { 1953 s1 = Integer.toHexString(System.identityHashCode(this)); 1954 s2 = mHeld ? "held; " : ""; 1955 if (mRefCounted) { 1956 s3 = "refcounted: refcount = " + mRefCount; 1957 } else { 1958 s3 = "not refcounted"; 1959 } 1960 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }"; 1961 } 1962 } 1963 1964 @Override 1965 protected void finalize() throws Throwable { 1966 super.finalize(); 1967 synchronized (mBinder) { 1968 if (mHeld) { 1969 try { 1970 mService.releaseWifiLock(mBinder); 1971 synchronized (WifiManager.this) { 1972 mActiveLockCount--; 1973 } 1974 } catch (RemoteException ignore) { 1975 } 1976 } 1977 } 1978 } 1979 } 1980 1981 /** 1982 * Creates a new WifiLock. 1983 * 1984 * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL}, 1985 * {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for 1986 * descriptions of the types of Wi-Fi locks. 1987 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 1988 * never shown to the user under normal conditions, but should be descriptive 1989 * enough to identify your application and the specific WifiLock within it, if it 1990 * holds multiple WifiLocks. 1991 * 1992 * @return a new, unacquired WifiLock with the given tag. 1993 * 1994 * @see WifiLock 1995 */ 1996 public WifiLock createWifiLock(int lockType, String tag) { 1997 return new WifiLock(lockType, tag); 1998 } 1999 2000 /** 2001 * Creates a new WifiLock. 2002 * 2003 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 2004 * never shown to the user under normal conditions, but should be descriptive 2005 * enough to identify your application and the specific WifiLock within it, if it 2006 * holds multiple WifiLocks. 2007 * 2008 * @return a new, unacquired WifiLock with the given tag. 2009 * 2010 * @see WifiLock 2011 */ 2012 public WifiLock createWifiLock(String tag) { 2013 return new WifiLock(WIFI_MODE_FULL, tag); 2014 } 2015 2016 2017 /** 2018 * Create a new MulticastLock 2019 * 2020 * @param tag a tag for the MulticastLock to identify it in debugging 2021 * messages. This string is never shown to the user under 2022 * normal conditions, but should be descriptive enough to 2023 * identify your application and the specific MulticastLock 2024 * within it, if it holds multiple MulticastLocks. 2025 * 2026 * @return a new, unacquired MulticastLock with the given tag. 2027 * 2028 * @see MulticastLock 2029 */ 2030 public MulticastLock createMulticastLock(String tag) { 2031 return new MulticastLock(tag); 2032 } 2033 2034 /** 2035 * Allows an application to receive Wifi Multicast packets. 2036 * Normally the Wifi stack filters out packets not explicitly 2037 * addressed to this device. Acquring a MulticastLock will 2038 * cause the stack to receive packets addressed to multicast 2039 * addresses. Processing these extra packets can cause a noticable 2040 * battery drain and should be disabled when not needed. 2041 */ 2042 public class MulticastLock { 2043 private String mTag; 2044 private final IBinder mBinder; 2045 private int mRefCount; 2046 private boolean mRefCounted; 2047 private boolean mHeld; 2048 2049 private MulticastLock(String tag) { 2050 mTag = tag; 2051 mBinder = new Binder(); 2052 mRefCount = 0; 2053 mRefCounted = true; 2054 mHeld = false; 2055 } 2056 2057 /** 2058 * Locks Wifi Multicast on until {@link #release} is called. 2059 * 2060 * If this MulticastLock is reference-counted each call to 2061 * {@code acquire} will increment the reference count, and the 2062 * wifi interface will receive multicast packets as long as the 2063 * reference count is above zero. 2064 * 2065 * If this MulticastLock is not reference-counted, the first call to 2066 * {@code acquire} will turn on the multicast packets, but subsequent 2067 * calls will be ignored. Only one call to {@link #release} will 2068 * be required, regardless of the number of times that {@code acquire} 2069 * is called. 2070 * 2071 * Note that other applications may also lock Wifi Multicast on. 2072 * Only they can relinquish their lock. 2073 * 2074 * Also note that applications cannot leave Multicast locked on. 2075 * When an app exits or crashes, any Multicast locks will be released. 2076 */ 2077 public void acquire() { 2078 synchronized (mBinder) { 2079 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) { 2080 try { 2081 mService.acquireMulticastLock(mBinder, mTag); 2082 synchronized (WifiManager.this) { 2083 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 2084 mService.releaseMulticastLock(); 2085 throw new UnsupportedOperationException( 2086 "Exceeded maximum number of wifi locks"); 2087 } 2088 mActiveLockCount++; 2089 } 2090 } catch (RemoteException ignore) { 2091 } 2092 mHeld = true; 2093 } 2094 } 2095 } 2096 2097 /** 2098 * Unlocks Wifi Multicast, restoring the filter of packets 2099 * not addressed specifically to this device and saving power. 2100 * 2101 * If this MulticastLock is reference-counted, each call to 2102 * {@code release} will decrement the reference count, and the 2103 * multicast packets will only stop being received when the reference 2104 * count reaches zero. If the reference count goes below zero (that 2105 * is, if {@code release} is called a greater number of times than 2106 * {@link #acquire}), an exception is thrown. 2107 * 2108 * If this MulticastLock is not reference-counted, the first call to 2109 * {@code release} (after the radio was multicast locked using 2110 * {@link #acquire}) will unlock the multicast, and subsequent calls 2111 * will be ignored. 2112 * 2113 * Note that if any other Wifi Multicast Locks are still outstanding 2114 * this {@code release} call will not have an immediate effect. Only 2115 * when all applications have released all their Multicast Locks will 2116 * the Multicast filter be turned back on. 2117 * 2118 * Also note that when an app exits or crashes all of its Multicast 2119 * Locks will be automatically released. 2120 */ 2121 public void release() { 2122 synchronized (mBinder) { 2123 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 2124 try { 2125 mService.releaseMulticastLock(); 2126 synchronized (WifiManager.this) { 2127 mActiveLockCount--; 2128 } 2129 } catch (RemoteException ignore) { 2130 } 2131 mHeld = false; 2132 } 2133 if (mRefCount < 0) { 2134 throw new RuntimeException("MulticastLock under-locked " 2135 + mTag); 2136 } 2137 } 2138 } 2139 2140 /** 2141 * Controls whether this is a reference-counted or non-reference- 2142 * counted MulticastLock. 2143 * 2144 * Reference-counted MulticastLocks keep track of the number of calls 2145 * to {@link #acquire} and {@link #release}, and only stop the 2146 * reception of multicast packets when every call to {@link #acquire} 2147 * has been balanced with a call to {@link #release}. Non-reference- 2148 * counted MulticastLocks allow the reception of multicast packets 2149 * whenever {@link #acquire} is called and stop accepting multicast 2150 * packets whenever {@link #release} is called. 2151 * 2152 * @param refCounted true if this MulticastLock should keep a reference 2153 * count 2154 */ 2155 public void setReferenceCounted(boolean refCounted) { 2156 mRefCounted = refCounted; 2157 } 2158 2159 /** 2160 * Checks whether this MulticastLock is currently held. 2161 * 2162 * @return true if this MulticastLock is held, false otherwise 2163 */ 2164 public boolean isHeld() { 2165 synchronized (mBinder) { 2166 return mHeld; 2167 } 2168 } 2169 2170 public String toString() { 2171 String s1, s2, s3; 2172 synchronized (mBinder) { 2173 s1 = Integer.toHexString(System.identityHashCode(this)); 2174 s2 = mHeld ? "held; " : ""; 2175 if (mRefCounted) { 2176 s3 = "refcounted: refcount = " + mRefCount; 2177 } else { 2178 s3 = "not refcounted"; 2179 } 2180 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }"; 2181 } 2182 } 2183 2184 @Override 2185 protected void finalize() throws Throwable { 2186 super.finalize(); 2187 setReferenceCounted(false); 2188 release(); 2189 } 2190 } 2191 2192 /** 2193 * Check multicast filter status. 2194 * 2195 * @return true if multicast packets are allowed. 2196 * 2197 * @hide pending API council approval 2198 */ 2199 public boolean isMulticastEnabled() { 2200 try { 2201 return mService.isMulticastEnabled(); 2202 } catch (RemoteException e) { 2203 return false; 2204 } 2205 } 2206 2207 /** 2208 * Initialize the multicast filtering to 'on' 2209 * @hide no intent to publish 2210 */ 2211 public boolean initializeMulticastFiltering() { 2212 try { 2213 mService.initializeMulticastFiltering(); 2214 return true; 2215 } catch (RemoteException e) { 2216 return false; 2217 } 2218 } 2219 2220 protected void finalize() throws Throwable { 2221 try { 2222 synchronized (sThreadRefLock) { 2223 if (--sThreadRefCount == 0 && sAsyncChannel != null) { 2224 sAsyncChannel.disconnect(); 2225 } 2226 } 2227 } finally { 2228 super.finalize(); 2229 } 2230 } 2231} 2232