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