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