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.Nullable; 20 import android.annotation.RequiresPermission; 21 import android.annotation.SdkConstant; 22 import android.annotation.SuppressLint; 23 import android.annotation.SdkConstant.SdkConstantType; 24 import android.annotation.SystemApi; 25 import android.annotation.SystemService; 26 import android.content.Context; 27 import android.content.pm.ParceledListSlice; 28 import android.net.ConnectivityManager; 29 import android.net.DhcpInfo; 30 import android.net.Network; 31 import android.net.NetworkCapabilities; 32 import android.net.NetworkRequest; 33 import android.net.wifi.hotspot2.PasspointConfiguration; 34 import android.os.Binder; 35 import android.os.Build; 36 import android.os.Handler; 37 import android.os.IBinder; 38 import android.os.Looper; 39 import android.os.Message; 40 import android.os.Messenger; 41 import android.os.RemoteException; 42 import android.os.WorkSource; 43 import android.util.Log; 44 import android.util.SparseArray; 45 46 import com.android.internal.annotations.GuardedBy; 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.internal.util.AsyncChannel; 49 import com.android.internal.util.Protocol; 50 import com.android.server.net.NetworkPinner; 51 52 import dalvik.system.CloseGuard; 53 54 import java.lang.ref.WeakReference; 55 import java.net.InetAddress; 56 import java.util.Collections; 57 import java.util.List; 58 import java.util.concurrent.CountDownLatch; 59 60 /** 61 * This class provides the primary API for managing all aspects of Wi-Fi 62 * connectivity. 63 * <p> 64 * On releases before {@link android.os.Build.VERSION_CODES#N}, this object 65 * should only be obtained from an {@linkplain Context#getApplicationContext() 66 * application context}, and not from any other derived context to avoid memory 67 * leaks within the calling process. 68 * <p> 69 * It deals with several categories of items: 70 * <ul> 71 * <li>The list of configured networks. The list can be viewed and updated, and 72 * attributes of individual entries can be modified.</li> 73 * <li>The currently active Wi-Fi network, if any. Connectivity can be 74 * established or torn down, and dynamic information about the state of the 75 * network can be queried.</li> 76 * <li>Results of access point scans, containing enough information to make 77 * decisions about what access point to connect to.</li> 78 * <li>It defines the names of various Intent actions that are broadcast upon 79 * any sort of change in Wi-Fi state. 80 * </ul> 81 * This is the API to use when performing Wi-Fi specific operations. To perform 82 * operations that pertain to network connectivity at an abstract level, use 83 * {@link android.net.ConnectivityManager}. 84 */ 85 @SystemService(Context.WIFI_SERVICE) 86 public class WifiManager { 87 88 private static final String TAG = "WifiManager"; 89 // Supplicant error codes: 90 /** 91 * The error code if there was a problem authenticating. 92 */ 93 public static final int ERROR_AUTHENTICATING = 1; 94 95 /** 96 * The reason code if there is no error during authentication. 97 * It could also imply that there no authentication in progress, 98 * this reason code also serves as a reset value. 99 * @hide 100 */ 101 public static final int ERROR_AUTH_FAILURE_NONE = 0; 102 103 /** 104 * The reason code if there was a timeout authenticating. 105 * @hide 106 */ 107 public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1; 108 109 /** 110 * The reason code if there was a wrong password while 111 * authenticating. 112 * @hide 113 */ 114 public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2; 115 116 /** 117 * The reason code if there was EAP failure while 118 * authenticating. 119 * @hide 120 */ 121 public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3; 122 123 /** 124 * Broadcast intent action indicating whether Wi-Fi scanning is allowed currently 125 * @hide 126 */ 127 public static final String WIFI_SCAN_AVAILABLE = "wifi_scan_available"; 128 129 /** 130 * Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED 131 * @hide 132 */ 133 public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled"; 134 135 /** 136 * Broadcast intent action indicating that the credential of a Wi-Fi network 137 * has been changed. One extra provides the ssid of the network. Another 138 * extra provides the event type, whether the credential is saved or forgot. 139 * @hide 140 */ 141 @SystemApi 142 public static final String WIFI_CREDENTIAL_CHANGED_ACTION = 143 "android.net.wifi.WIFI_CREDENTIAL_CHANGED"; 144 /** @hide */ 145 @SystemApi 146 public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et"; 147 /** @hide */ 148 @SystemApi 149 public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid"; 150 /** @hide */ 151 @SystemApi 152 public static final int WIFI_CREDENTIAL_SAVED = 0; 153 /** @hide */ 154 @SystemApi 155 public static final int WIFI_CREDENTIAL_FORGOT = 1; 156 157 /** 158 * Broadcast intent action indicating that a Passpoint provider icon has been received. 159 * 160 * Included extras: 161 * {@link #EXTRA_BSSID_LONG} 162 * {@link #EXTRA_FILENAME} 163 * {@link #EXTRA_ICON} 164 * 165 * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE 166 * 167 * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered 168 * components will be launched. 169 * 170 * @hide 171 */ 172 public static final String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON"; 173 /** 174 * BSSID of an AP in long representation. The {@link #EXTRA_BSSID} contains BSSID in 175 * String representation. 176 * 177 * Retrieve with {@link android.content.Intent#getLongExtra(String, long)}. 178 * 179 * @hide 180 */ 181 public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG"; 182 /** 183 * Icon data. 184 * 185 * Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into 186 * {@link android.graphics.drawable.Icon}. 187 * 188 * @hide 189 */ 190 public static final String EXTRA_ICON = "android.net.wifi.extra.ICON"; 191 /** 192 * Name of a file. 193 * 194 * Retrieve with {@link android.content.Intent#getStringExtra(String)}. 195 * 196 * @hide 197 */ 198 public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME"; 199 200 /** 201 * Broadcast intent action indicating a Passpoint OSU Providers List element has been received. 202 * 203 * Included extras: 204 * {@link #EXTRA_BSSID_LONG} 205 * {@link #EXTRA_ANQP_ELEMENT_DATA} 206 * 207 * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE 208 * 209 * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered 210 * components will be launched. 211 * 212 * @hide 213 */ 214 public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST = 215 "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST"; 216 /** 217 * Raw binary data of an ANQP (Access Network Query Protocol) element. 218 * 219 * Retrieve with {@link android.content.Intent#getByteArrayExtra(String)}. 220 * 221 * @hide 222 */ 223 public static final String EXTRA_ANQP_ELEMENT_DATA = 224 "android.net.wifi.extra.ANQP_ELEMENT_DATA"; 225 226 /** 227 * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received. 228 * 229 * Included extras: 230 * {@link #EXTRA_BSSID_LONG} 231 * {@link #EXTRA_ESS} 232 * {@link #EXTRA_DELAY} 233 * {@link #EXTRA_URL} 234 * 235 * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE 236 * 237 * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered 238 * components will be launched. 239 * 240 * @hide 241 */ 242 public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT = 243 "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT"; 244 /** 245 * Flag indicating BSS (Basic Service Set) or ESS (Extended Service Set). This will be set to 246 * {@code true} for ESS. 247 * 248 * Retrieve with {@link android.content.Intent#getBooleanExtra(String, boolean)}. 249 * 250 * @hide 251 */ 252 public static final String EXTRA_ESS = "android.net.wifi.extra.ESS"; 253 /** 254 * Delay in seconds. 255 * 256 * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}. 257 * 258 * @hide 259 */ 260 public static final String EXTRA_DELAY = "android.net.wifi.extra.DELAY"; 261 /** 262 * String representation of an URL. 263 * 264 * Retrieve with {@link android.content.Intent#getStringExtra(String)}. 265 * 266 * @hide 267 */ 268 public static final String EXTRA_URL = "android.net.wifi.extra.URL"; 269 270 /** 271 * Broadcast intent action indicating a Passpoint subscription remediation frame has been 272 * received. 273 * 274 * Included extras: 275 * {@link #EXTRA_BSSID_LONG} 276 * {@link #EXTRA_SUBSCRIPTION_REMEDIATION_METHOD} 277 * {@link #EXTRA_URL} 278 * 279 * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE 280 * 281 * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered 282 * components will be launched. 283 * 284 * @hide 285 */ 286 public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION = 287 "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION"; 288 /** 289 * The protocol supported by the subscription remediation server. The possible values are: 290 * 0 - OMA DM 291 * 1 - SOAP XML SPP 292 * 293 * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}. 294 * 295 * @hide 296 */ 297 public static final String EXTRA_SUBSCRIPTION_REMEDIATION_METHOD = 298 "android.net.wifi.extra.SUBSCRIPTION_REMEDIATION_METHOD"; 299 300 /** 301 * Broadcast intent action indicating that Wi-Fi has been enabled, disabled, 302 * enabling, disabling, or unknown. One extra provides this state as an int. 303 * Another extra provides the previous state, if available. 304 * 305 * @see #EXTRA_WIFI_STATE 306 * @see #EXTRA_PREVIOUS_WIFI_STATE 307 */ 308 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 309 public static final String WIFI_STATE_CHANGED_ACTION = 310 "android.net.wifi.WIFI_STATE_CHANGED"; 311 /** 312 * The lookup key for an int that indicates whether Wi-Fi is enabled, 313 * disabled, enabling, disabling, or unknown. Retrieve it with 314 * {@link android.content.Intent#getIntExtra(String,int)}. 315 * 316 * @see #WIFI_STATE_DISABLED 317 * @see #WIFI_STATE_DISABLING 318 * @see #WIFI_STATE_ENABLED 319 * @see #WIFI_STATE_ENABLING 320 * @see #WIFI_STATE_UNKNOWN 321 */ 322 public static final String EXTRA_WIFI_STATE = "wifi_state"; 323 /** 324 * The previous Wi-Fi state. 325 * 326 * @see #EXTRA_WIFI_STATE 327 */ 328 public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state"; 329 330 /** 331 * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if 332 * it finishes successfully. 333 * 334 * @see #WIFI_STATE_CHANGED_ACTION 335 * @see #getWifiState() 336 */ 337 public static final int WIFI_STATE_DISABLING = 0; 338 /** 339 * Wi-Fi is disabled. 340 * 341 * @see #WIFI_STATE_CHANGED_ACTION 342 * @see #getWifiState() 343 */ 344 public static final int WIFI_STATE_DISABLED = 1; 345 /** 346 * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if 347 * it finishes successfully. 348 * 349 * @see #WIFI_STATE_CHANGED_ACTION 350 * @see #getWifiState() 351 */ 352 public static final int WIFI_STATE_ENABLING = 2; 353 /** 354 * Wi-Fi is enabled. 355 * 356 * @see #WIFI_STATE_CHANGED_ACTION 357 * @see #getWifiState() 358 */ 359 public static final int WIFI_STATE_ENABLED = 3; 360 /** 361 * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling 362 * or disabling. 363 * 364 * @see #WIFI_STATE_CHANGED_ACTION 365 * @see #getWifiState() 366 */ 367 public static final int WIFI_STATE_UNKNOWN = 4; 368 369 /** 370 * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled, 371 * enabling, disabling, or failed. 372 * 373 * @hide 374 */ 375 @SystemApi 376 public static final String WIFI_AP_STATE_CHANGED_ACTION = 377 "android.net.wifi.WIFI_AP_STATE_CHANGED"; 378 379 /** 380 * The lookup key for an int that indicates whether Wi-Fi AP is enabled, 381 * disabled, enabling, disabling, or failed. Retrieve it with 382 * {@link android.content.Intent#getIntExtra(String,int)}. 383 * 384 * @see #WIFI_AP_STATE_DISABLED 385 * @see #WIFI_AP_STATE_DISABLING 386 * @see #WIFI_AP_STATE_ENABLED 387 * @see #WIFI_AP_STATE_ENABLING 388 * @see #WIFI_AP_STATE_FAILED 389 * 390 * @hide 391 */ 392 @SystemApi 393 public static final String EXTRA_WIFI_AP_STATE = "wifi_state"; 394 395 /** 396 * The look up key for an int that indicates why softAP started failed 397 * currently support general and no_channel 398 * @see #SAP_START_FAILURE_GENERIC 399 * @see #SAP_START_FAILURE_NO_CHANNEL 400 * 401 * @hide 402 */ 403 public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code"; 404 /** 405 * The previous Wi-Fi state. 406 * 407 * @see #EXTRA_WIFI_AP_STATE 408 * 409 * @hide 410 */ 411 @SystemApi 412 public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state"; 413 /** 414 * The interface used for the softap. 415 * 416 * @hide 417 */ 418 public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "wifi_ap_interface_name"; 419 /** 420 * The intended ip mode for this softap. 421 * @see #IFACE_IP_MODE_TETHERED 422 * @see #IFACE_IP_MODE_LOCAL_ONLY 423 * 424 * @hide 425 */ 426 public static final String EXTRA_WIFI_AP_MODE = "wifi_ap_mode"; 427 428 /** 429 * Wi-Fi AP is currently being disabled. The state will change to 430 * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully. 431 * 432 * @see #WIFI_AP_STATE_CHANGED_ACTION 433 * @see #getWifiApState() 434 * 435 * @hide 436 */ 437 @SystemApi 438 public static final int WIFI_AP_STATE_DISABLING = 10; 439 /** 440 * Wi-Fi AP is disabled. 441 * 442 * @see #WIFI_AP_STATE_CHANGED_ACTION 443 * @see #getWifiState() 444 * 445 * @hide 446 */ 447 @SystemApi 448 public static final int WIFI_AP_STATE_DISABLED = 11; 449 /** 450 * Wi-Fi AP is currently being enabled. The state will change to 451 * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully. 452 * 453 * @see #WIFI_AP_STATE_CHANGED_ACTION 454 * @see #getWifiApState() 455 * 456 * @hide 457 */ 458 @SystemApi 459 public static final int WIFI_AP_STATE_ENABLING = 12; 460 /** 461 * Wi-Fi AP is enabled. 462 * 463 * @see #WIFI_AP_STATE_CHANGED_ACTION 464 * @see #getWifiApState() 465 * 466 * @hide 467 */ 468 @SystemApi 469 public static final int WIFI_AP_STATE_ENABLED = 13; 470 /** 471 * Wi-Fi AP is in a failed state. This state will occur when an error occurs during 472 * enabling or disabling 473 * 474 * @see #WIFI_AP_STATE_CHANGED_ACTION 475 * @see #getWifiApState() 476 * 477 * @hide 478 */ 479 @SystemApi 480 public static final int WIFI_AP_STATE_FAILED = 14; 481 482 /** 483 * If WIFI AP start failed, this reason code means there is no legal channel exists on 484 * user selected band by regulatory 485 * 486 * @hide 487 */ 488 public static final int SAP_START_FAILURE_GENERAL= 0; 489 490 /** 491 * All other reason for AP start failed besides SAP_START_FAILURE_GENERAL 492 * 493 * @hide 494 */ 495 public static final int SAP_START_FAILURE_NO_CHANNEL = 1; 496 497 /** 498 * Interface IP mode unspecified. 499 * 500 * @see updateInterfaceIpState(String, int) 501 * 502 * @hide 503 */ 504 public static final int IFACE_IP_MODE_UNSPECIFIED = -1; 505 506 /** 507 * Interface IP mode for configuration error. 508 * 509 * @see updateInterfaceIpState(String, int) 510 * 511 * @hide 512 */ 513 public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0; 514 515 /** 516 * Interface IP mode for tethering. 517 * 518 * @see updateInterfaceIpState(String, int) 519 * 520 * @hide 521 */ 522 public static final int IFACE_IP_MODE_TETHERED = 1; 523 524 /** 525 * Interface IP mode for Local Only Hotspot. 526 * 527 * @see updateInterfaceIpState(String, int) 528 * 529 * @hide 530 */ 531 public static final int IFACE_IP_MODE_LOCAL_ONLY = 2; 532 533 /** 534 * Broadcast intent action indicating that a connection to the supplicant has 535 * been established (and it is now possible 536 * to perform Wi-Fi operations) or the connection to the supplicant has been 537 * lost. One extra provides the connection state as a boolean, where {@code true} 538 * means CONNECTED. 539 * @see #EXTRA_SUPPLICANT_CONNECTED 540 */ 541 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 542 public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION = 543 "android.net.wifi.supplicant.CONNECTION_CHANGE"; 544 /** 545 * The lookup key for a boolean that indicates whether a connection to 546 * the supplicant daemon has been gained or lost. {@code true} means 547 * a connection now exists. 548 * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. 549 */ 550 public static final String EXTRA_SUPPLICANT_CONNECTED = "connected"; 551 /** 552 * Broadcast intent action indicating that the state of Wi-Fi connectivity 553 * has changed. One extra provides the new state 554 * in the form of a {@link android.net.NetworkInfo} object. If the new 555 * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of 556 * the access point. 557 * as a {@code String}. 558 * @see #EXTRA_NETWORK_INFO 559 * @see #EXTRA_BSSID 560 * @see #EXTRA_WIFI_INFO 561 */ 562 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 563 public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"; 564 /** 565 * The lookup key for a {@link android.net.NetworkInfo} object associated with the 566 * Wi-Fi network. Retrieve with 567 * {@link android.content.Intent#getParcelableExtra(String)}. 568 */ 569 public static final String EXTRA_NETWORK_INFO = "networkInfo"; 570 /** 571 * The lookup key for a String giving the BSSID of the access point to which 572 * we are connected. Only present when the new state is CONNECTED. 573 * Retrieve with 574 * {@link android.content.Intent#getStringExtra(String)}. 575 */ 576 public static final String EXTRA_BSSID = "bssid"; 577 /** 578 * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the 579 * information about the access point to which we are connected. Only present 580 * when the new state is CONNECTED. Retrieve with 581 * {@link android.content.Intent#getParcelableExtra(String)}. 582 */ 583 public static final String EXTRA_WIFI_INFO = "wifiInfo"; 584 /** 585 * Broadcast intent action indicating that the state of establishing a connection to 586 * an access point has changed.One extra provides the new 587 * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and 588 * is not generally the most useful thing to look at if you are just interested in 589 * the overall state of connectivity. 590 * @see #EXTRA_NEW_STATE 591 * @see #EXTRA_SUPPLICANT_ERROR 592 */ 593 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 594 public static final String SUPPLICANT_STATE_CHANGED_ACTION = 595 "android.net.wifi.supplicant.STATE_CHANGE"; 596 /** 597 * The lookup key for a {@link SupplicantState} describing the new state 598 * Retrieve with 599 * {@link android.content.Intent#getParcelableExtra(String)}. 600 */ 601 public static final String EXTRA_NEW_STATE = "newState"; 602 603 /** 604 * The lookup key for a {@link SupplicantState} describing the supplicant 605 * error code if any 606 * Retrieve with 607 * {@link android.content.Intent#getIntExtra(String, int)}. 608 * @see #ERROR_AUTHENTICATING 609 */ 610 public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError"; 611 612 /** 613 * The lookup key for a {@link SupplicantState} describing the supplicant 614 * error reason if any 615 * Retrieve with 616 * {@link android.content.Intent#getIntExtra(String, int)}. 617 * @see #ERROR_AUTH_FAILURE_#REASON_CODE 618 * @hide 619 */ 620 public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason"; 621 622 /** 623 * Broadcast intent action indicating that the configured networks changed. 624 * This can be as a result of adding/updating/deleting a network. If 625 * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set to true the new configuration 626 * can be retreived with the {@link #EXTRA_WIFI_CONFIGURATION} extra. If multiple 627 * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present. 628 * @hide 629 */ 630 @SystemApi 631 public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = 632 "android.net.wifi.CONFIGURED_NETWORKS_CHANGE"; 633 /** 634 * The lookup key for a (@link android.net.wifi.WifiConfiguration} object representing 635 * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION} 636 * broadcast is sent. 637 * @hide 638 */ 639 @SystemApi 640 public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration"; 641 /** 642 * Multiple network configurations have changed. 643 * @see #CONFIGURED_NETWORKS_CHANGED_ACTION 644 * 645 * @hide 646 */ 647 @SystemApi 648 public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges"; 649 /** 650 * The lookup key for an integer indicating the reason a Wi-Fi network configuration 651 * has changed. Only present if {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is {@code false} 652 * @see #CONFIGURED_NETWORKS_CHANGED_ACTION 653 * @hide 654 */ 655 @SystemApi 656 public static final String EXTRA_CHANGE_REASON = "changeReason"; 657 /** 658 * The configuration is new and was added. 659 * @hide 660 */ 661 @SystemApi 662 public static final int CHANGE_REASON_ADDED = 0; 663 /** 664 * The configuration was removed and is no longer present in the system's list of 665 * configured networks. 666 * @hide 667 */ 668 @SystemApi 669 public static final int CHANGE_REASON_REMOVED = 1; 670 /** 671 * The configuration has changed as a result of explicit action or because the system 672 * took an automated action such as disabling a malfunctioning configuration. 673 * @hide 674 */ 675 @SystemApi 676 public static final int CHANGE_REASON_CONFIG_CHANGE = 2; 677 /** 678 * An access point scan has completed, and results are available from the supplicant. 679 * Call {@link #getScanResults()} to obtain the results. {@link #EXTRA_RESULTS_UPDATED} 680 * indicates if the scan was completed successfully. 681 */ 682 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 683 public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS"; 684 685 /** 686 * Lookup key for a {@code boolean} representing the result of previous {@link #startScan} 687 * operation, reported with {@link #SCAN_RESULTS_AVAILABLE_ACTION}. 688 * @return true scan was successful, results are updated 689 * @return false scan was not successful, results haven't been updated since previous scan 690 */ 691 public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated"; 692 693 /** 694 * A batch of access point scans has been completed and the results areavailable. 695 * Call {@link #getBatchedScanResults()} to obtain the results. 696 * @deprecated This API is nolonger supported. 697 * Use {@link android.net.wifi.WifiScanner} API 698 * @hide 699 */ 700 @Deprecated 701 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 702 public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION = 703 "android.net.wifi.BATCHED_RESULTS"; 704 /** 705 * The RSSI (signal strength) has changed. 706 * @see #EXTRA_NEW_RSSI 707 */ 708 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 709 public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED"; 710 /** 711 * The lookup key for an {@code int} giving the new RSSI in dBm. 712 */ 713 public static final String EXTRA_NEW_RSSI = "newRssi"; 714 715 /** 716 * Broadcast intent action indicating that the link configuration 717 * changed on wifi. 718 * @hide 719 */ 720 public static final String LINK_CONFIGURATION_CHANGED_ACTION = 721 "android.net.wifi.LINK_CONFIGURATION_CHANGED"; 722 723 /** 724 * The lookup key for a {@link android.net.LinkProperties} object associated with the 725 * Wi-Fi network. Retrieve with 726 * {@link android.content.Intent#getParcelableExtra(String)}. 727 * @hide 728 */ 729 public static final String EXTRA_LINK_PROPERTIES = "linkProperties"; 730 731 /** 732 * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the 733 * Wi-Fi network. Retrieve with 734 * {@link android.content.Intent#getParcelableExtra(String)}. 735 * @hide 736 */ 737 public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities"; 738 739 /** 740 * The network IDs of the configured networks could have changed. 741 */ 742 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 743 public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED"; 744 745 /** 746 * Activity Action: Show a system activity that allows the user to enable 747 * scans to be available even with Wi-Fi turned off. 748 * 749 * <p>Notification of the result of this activity is posted using the 750 * {@link android.app.Activity#onActivityResult} callback. The 751 * <code>resultCode</code> 752 * will be {@link android.app.Activity#RESULT_OK} if scan always mode has 753 * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user 754 * has rejected the request or an error has occurred. 755 */ 756 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 757 public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = 758 "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE"; 759 760 /** 761 * Activity Action: Pick a Wi-Fi network to connect to. 762 * <p>Input: Nothing. 763 * <p>Output: Nothing. 764 */ 765 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 766 public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; 767 768 /** 769 * Activity Action: Show UI to get user approval to enable WiFi. 770 * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with 771 * the name of the app requesting the action. 772 * <p>Output: Nothing. 773 * 774 * @hide 775 */ 776 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 777 public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE"; 778 779 /** 780 * Activity Action: Show UI to get user approval to disable WiFi. 781 * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with 782 * the name of the app requesting the action. 783 * <p>Output: Nothing. 784 * 785 * @hide 786 */ 787 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 788 public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE"; 789 790 /** 791 * Internally used Wi-Fi lock mode representing the case were no locks are held. 792 * @hide 793 */ 794 public static final int WIFI_MODE_NO_LOCKS_HELD = 0; 795 796 /** 797 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 798 * and will behave normally, i.e., it will attempt to automatically 799 * establish a connection to a remembered access point that is 800 * within range, and will do periodic scans if there are remembered 801 * access points but none are in range. 802 */ 803 public static final int WIFI_MODE_FULL = 1; 804 /** 805 * In this Wi-Fi lock mode, Wi-Fi will be kept active, 806 * but the only operation that will be supported is initiation of 807 * scans, and the subsequent reporting of scan results. No attempts 808 * will be made to automatically connect to remembered access points, 809 * nor will periodic scans be automatically performed looking for 810 * remembered access points. Scans must be explicitly requested by 811 * an application in this mode. 812 */ 813 public static final int WIFI_MODE_SCAN_ONLY = 2; 814 /** 815 * In this Wi-Fi lock mode, Wi-Fi will be kept active as in mode 816 * {@link #WIFI_MODE_FULL} but it operates at high performance 817 * with minimum packet loss and low packet latency even when 818 * the device screen is off. This mode will consume more power 819 * and hence should be used only when there is a need for such 820 * an active connection. 821 * <p> 822 * An example use case is when a voice connection needs to be 823 * kept active even after the device screen goes off. Holding the 824 * regular {@link #WIFI_MODE_FULL} lock will keep the wifi 825 * connection active, but the connection can be lossy. 826 * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the 827 * duration of the voice call will improve the call quality. 828 * <p> 829 * When there is no support from the hardware, this lock mode 830 * will have the same behavior as {@link #WIFI_MODE_FULL} 831 */ 832 public static final int WIFI_MODE_FULL_HIGH_PERF = 3; 833 834 /** Anything worse than or equal to this will show 0 bars. */ 835 private static final int MIN_RSSI = -100; 836 837 /** Anything better than or equal to this will show the max bars. */ 838 private static final int MAX_RSSI = -55; 839 840 /** 841 * Number of RSSI levels used in the framework to initiate 842 * {@link #RSSI_CHANGED_ACTION} broadcast 843 * @hide 844 */ 845 public static final int RSSI_LEVELS = 5; 846 847 /** 848 * Auto settings in the driver. The driver could choose to operate on both 849 * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band. 850 * @hide 851 */ 852 public static final int WIFI_FREQUENCY_BAND_AUTO = 0; 853 854 /** 855 * Operation on 5 GHz alone 856 * @hide 857 */ 858 public static final int WIFI_FREQUENCY_BAND_5GHZ = 1; 859 860 /** 861 * Operation on 2.4 GHz alone 862 * @hide 863 */ 864 public static final int WIFI_FREQUENCY_BAND_2GHZ = 2; 865 866 /** List of asyncronous notifications 867 * @hide 868 */ 869 public static final int DATA_ACTIVITY_NOTIFICATION = 1; 870 871 //Lowest bit indicates data reception and the second lowest 872 //bit indicates data transmitted 873 /** @hide */ 874 public static final int DATA_ACTIVITY_NONE = 0x00; 875 /** @hide */ 876 public static final int DATA_ACTIVITY_IN = 0x01; 877 /** @hide */ 878 public static final int DATA_ACTIVITY_OUT = 0x02; 879 /** @hide */ 880 public static final int DATA_ACTIVITY_INOUT = 0x03; 881 882 /** @hide */ 883 public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false; 884 885 /* Maximum number of active locks we allow. 886 * This limit was added to prevent apps from creating a ridiculous number 887 * of locks and crashing the system by overflowing the global ref table. 888 */ 889 private static final int MAX_ACTIVE_LOCKS = 50; 890 891 /* Number of currently active WifiLocks and MulticastLocks */ 892 private int mActiveLockCount; 893 894 private Context mContext; 895 IWifiManager mService; 896 private final int mTargetSdkVersion; 897 898 private static final int INVALID_KEY = 0; 899 private int mListenerKey = 1; 900 private final SparseArray mListenerMap = new SparseArray(); 901 private final Object mListenerMapLock = new Object(); 902 903 private AsyncChannel mAsyncChannel; 904 private CountDownLatch mConnected; 905 private Looper mLooper; 906 907 /* LocalOnlyHotspot callback message types */ 908 /** @hide */ 909 public static final int HOTSPOT_STARTED = 0; 910 /** @hide */ 911 public static final int HOTSPOT_STOPPED = 1; 912 /** @hide */ 913 public static final int HOTSPOT_FAILED = 2; 914 /** @hide */ 915 public static final int HOTSPOT_OBSERVER_REGISTERED = 3; 916 917 private final Object mLock = new Object(); // lock guarding access to the following vars 918 @GuardedBy("mLock") 919 private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy; 920 @GuardedBy("mLock") 921 private LocalOnlyHotspotObserverProxy mLOHSObserverProxy; 922 923 /** 924 * Create a new WifiManager instance. 925 * Applications will almost always want to use 926 * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve 927 * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. 928 * @param context the application context 929 * @param service the Binder interface 930 * @hide - hide this because it takes in a parameter of type IWifiManager, which 931 * is a system private class. 932 */ WifiManager(Context context, IWifiManager service, Looper looper)933 public WifiManager(Context context, IWifiManager service, Looper looper) { 934 mContext = context; 935 mService = service; 936 mLooper = looper; 937 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; 938 } 939 940 /** 941 * Return a list of all the networks configured for the current foreground 942 * user. 943 * Not all fields of WifiConfiguration are returned. Only the following 944 * fields are filled in: 945 * <ul> 946 * <li>networkId</li> 947 * <li>SSID</li> 948 * <li>BSSID</li> 949 * <li>priority</li> 950 * <li>allowedProtocols</li> 951 * <li>allowedKeyManagement</li> 952 * <li>allowedAuthAlgorithms</li> 953 * <li>allowedPairwiseCiphers</li> 954 * <li>allowedGroupCiphers</li> 955 * </ul> 956 * @return a list of network configurations in the form of a list 957 * of {@link WifiConfiguration} objects. Upon failure to fetch or 958 * when Wi-Fi is turned off, it can be null. 959 */ getConfiguredNetworks()960 public List<WifiConfiguration> getConfiguredNetworks() { 961 try { 962 ParceledListSlice<WifiConfiguration> parceledList = 963 mService.getConfiguredNetworks(); 964 if (parceledList == null) { 965 return Collections.emptyList(); 966 } 967 return parceledList.getList(); 968 } catch (RemoteException e) { 969 throw e.rethrowFromSystemServer(); 970 } 971 } 972 973 /** @hide */ 974 @SystemApi 975 @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL) getPrivilegedConfiguredNetworks()976 public List<WifiConfiguration> getPrivilegedConfiguredNetworks() { 977 try { 978 ParceledListSlice<WifiConfiguration> parceledList = 979 mService.getPrivilegedConfiguredNetworks(); 980 if (parceledList == null) { 981 return Collections.emptyList(); 982 } 983 return parceledList.getList(); 984 } catch (RemoteException e) { 985 throw e.rethrowFromSystemServer(); 986 } 987 } 988 989 /** @hide */ 990 @SystemApi 991 @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL) getConnectionStatistics()992 public WifiConnectionStatistics getConnectionStatistics() { 993 try { 994 return mService.getConnectionStatistics(); 995 } catch (RemoteException e) { 996 throw e.rethrowFromSystemServer(); 997 } 998 } 999 1000 /** 1001 * Returns a WifiConfiguration matching this ScanResult 1002 * 1003 * An {@link UnsupportedOperationException} will be thrown if Passpoint is not enabled 1004 * on the device. 1005 * 1006 * @param scanResult scanResult that represents the BSSID 1007 * @return {@link WifiConfiguration} that matches this BSSID or null 1008 * @hide 1009 */ getMatchingWifiConfig(ScanResult scanResult)1010 public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) { 1011 try { 1012 return mService.getMatchingWifiConfig(scanResult); 1013 } catch (RemoteException e) { 1014 throw e.rethrowFromSystemServer(); 1015 } 1016 } 1017 1018 /** 1019 * Add a new network description to the set of configured networks. 1020 * The {@code networkId} field of the supplied configuration object 1021 * is ignored. 1022 * <p/> 1023 * The new network will be marked DISABLED by default. To enable it, 1024 * called {@link #enableNetwork}. 1025 * 1026 * @param config the set of variables that describe the configuration, 1027 * contained in a {@link WifiConfiguration} object. 1028 * If the {@link WifiConfiguration} has an Http Proxy set 1029 * the calling app must be System, or be provisioned as the Profile or Device Owner. 1030 * @return the ID of the newly created network description. This is used in 1031 * other operations to specified the network to be acted upon. 1032 * Returns {@code -1} on failure. 1033 */ addNetwork(WifiConfiguration config)1034 public int addNetwork(WifiConfiguration config) { 1035 if (config == null) { 1036 return -1; 1037 } 1038 config.networkId = -1; 1039 return addOrUpdateNetwork(config); 1040 } 1041 1042 /** 1043 * Update the network description of an existing configured network. 1044 * 1045 * @param config the set of variables that describe the configuration, 1046 * contained in a {@link WifiConfiguration} object. It may 1047 * be sparse, so that only the items that are being changed 1048 * are non-<code>null</code>. The {@code networkId} field 1049 * must be set to the ID of the existing network being updated. 1050 * If the {@link WifiConfiguration} has an Http Proxy set 1051 * the calling app must be System, or be provisioned as the Profile or Device Owner. 1052 * @return Returns the {@code networkId} of the supplied 1053 * {@code WifiConfiguration} on success. 1054 * <br/> 1055 * Returns {@code -1} on failure, including when the {@code networkId} 1056 * field of the {@code WifiConfiguration} does not refer to an 1057 * existing network. 1058 */ updateNetwork(WifiConfiguration config)1059 public int updateNetwork(WifiConfiguration config) { 1060 if (config == null || config.networkId < 0) { 1061 return -1; 1062 } 1063 return addOrUpdateNetwork(config); 1064 } 1065 1066 /** 1067 * Internal method for doing the RPC that creates a new network description 1068 * or updates an existing one. 1069 * 1070 * @param config The possibly sparse object containing the variables that 1071 * are to set or updated in the network description. 1072 * @return the ID of the network on success, {@code -1} on failure. 1073 */ addOrUpdateNetwork(WifiConfiguration config)1074 private int addOrUpdateNetwork(WifiConfiguration config) { 1075 try { 1076 return mService.addOrUpdateNetwork(config); 1077 } catch (RemoteException e) { 1078 throw e.rethrowFromSystemServer(); 1079 } 1080 } 1081 1082 /** 1083 * Add or update a Passpoint configuration. The configuration provides a credential 1084 * for connecting to Passpoint networks that are operated by the Passpoint 1085 * service provider specified in the configuration. 1086 * 1087 * Each configuration is uniquely identified by its FQDN (Fully Qualified Domain 1088 * Name). In the case when there is an existing configuration with the same 1089 * FQDN, the new configuration will replace the existing configuration. 1090 * 1091 * @param config The Passpoint configuration to be added 1092 * @throws IllegalArgumentException if configuration is invalid 1093 * @throws UnsupportedOperationException if Passpoint is not enabled on the device. 1094 */ addOrUpdatePasspointConfiguration(PasspointConfiguration config)1095 public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) { 1096 try { 1097 if (!mService.addOrUpdatePasspointConfiguration(config)) { 1098 throw new IllegalArgumentException(); 1099 } 1100 } catch (RemoteException e) { 1101 throw e.rethrowFromSystemServer(); 1102 } 1103 } 1104 1105 /** 1106 * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name). 1107 * 1108 * @param fqdn The FQDN of the Passpoint configuration to be removed 1109 * @throws IllegalArgumentException if no configuration is associated with the given FQDN. 1110 * @throws UnsupportedOperationException if Passpoint is not enabled on the device. 1111 */ removePasspointConfiguration(String fqdn)1112 public void removePasspointConfiguration(String fqdn) { 1113 try { 1114 if (!mService.removePasspointConfiguration(fqdn)) { 1115 throw new IllegalArgumentException(); 1116 } 1117 } catch (RemoteException e) { 1118 throw e.rethrowFromSystemServer(); 1119 } 1120 } 1121 1122 /** 1123 * Return the list of installed Passpoint configurations. 1124 * 1125 * An empty list will be returned when no configurations are installed. 1126 * 1127 * @return A list of {@link PasspointConfiguration} 1128 * @throws UnsupportedOperationException if Passpoint is not enabled on the device. 1129 */ getPasspointConfigurations()1130 public List<PasspointConfiguration> getPasspointConfigurations() { 1131 try { 1132 return mService.getPasspointConfigurations(); 1133 } catch (RemoteException e) { 1134 throw e.rethrowFromSystemServer(); 1135 } 1136 } 1137 1138 /** 1139 * Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent 1140 * will be broadcasted once the request is completed. The presence of the intent extra 1141 * {@link #EXTRA_ICON} will indicate the result of the request. 1142 * A missing intent extra {@link #EXTRA_ICON} will indicate a failure. 1143 * 1144 * @param bssid The BSSID of the AP 1145 * @param fileName Name of the icon file (remote file) to query from the AP 1146 * 1147 * @throws UnsupportedOperationException if Passpoint is not enabled on the device. 1148 * @hide 1149 */ queryPasspointIcon(long bssid, String fileName)1150 public void queryPasspointIcon(long bssid, String fileName) { 1151 try { 1152 mService.queryPasspointIcon(bssid, fileName); 1153 } catch (RemoteException e) { 1154 throw e.rethrowFromSystemServer(); 1155 } 1156 } 1157 1158 /** 1159 * Match the currently associated network against the SP matching the given FQDN 1160 * @param fqdn FQDN of the SP 1161 * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined] 1162 * @hide 1163 */ matchProviderWithCurrentNetwork(String fqdn)1164 public int matchProviderWithCurrentNetwork(String fqdn) { 1165 try { 1166 return mService.matchProviderWithCurrentNetwork(fqdn); 1167 } catch (RemoteException e) { 1168 throw e.rethrowFromSystemServer(); 1169 } 1170 } 1171 1172 /** 1173 * Deauthenticate and set the re-authentication hold off time for the current network 1174 * @param holdoff hold off time in milliseconds 1175 * @param ess set if the hold off pertains to an ESS rather than a BSS 1176 * @hide 1177 */ deauthenticateNetwork(long holdoff, boolean ess)1178 public void deauthenticateNetwork(long holdoff, boolean ess) { 1179 try { 1180 mService.deauthenticateNetwork(holdoff, ess); 1181 } catch (RemoteException e) { 1182 throw e.rethrowFromSystemServer(); 1183 } 1184 } 1185 1186 /** 1187 * Remove the specified network from the list of configured networks. 1188 * This may result in the asynchronous delivery of state change 1189 * events. 1190 * 1191 * Applications are not allowed to remove networks created by other 1192 * applications. 1193 * 1194 * @param netId the ID of the network as returned by {@link #addNetwork} or {@link 1195 * #getConfiguredNetworks}. 1196 * @return {@code true} if the operation succeeded 1197 */ removeNetwork(int netId)1198 public boolean removeNetwork(int netId) { 1199 try { 1200 return mService.removeNetwork(netId); 1201 } catch (RemoteException e) { 1202 throw e.rethrowFromSystemServer(); 1203 } 1204 } 1205 1206 /** 1207 * Allow a previously configured network to be associated with. If 1208 * <code>attemptConnect</code> is true, an attempt to connect to the selected 1209 * network is initiated. This may result in the asynchronous delivery 1210 * of state change events. 1211 * <p> 1212 * <b>Note:</b> If an application's target SDK version is 1213 * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network 1214 * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may 1215 * instead be sent through another network, such as cellular data, 1216 * Bluetooth tethering, or Ethernet. For example, traffic will never use a 1217 * Wi-Fi network that does not provide Internet access (e.g. a wireless 1218 * printer), if another network that does offer Internet access (e.g. 1219 * cellular data) is available. Applications that need to ensure that their 1220 * network traffic uses Wi-Fi should use APIs such as 1221 * {@link Network#bindSocket(java.net.Socket)}, 1222 * {@link Network#openConnection(java.net.URL)}, or 1223 * {@link ConnectivityManager#bindProcessToNetwork} to do so. 1224 * 1225 * Applications are not allowed to enable networks created by other 1226 * applications. 1227 * 1228 * @param netId the ID of the network as returned by {@link #addNetwork} or {@link 1229 * #getConfiguredNetworks}. 1230 * @param attemptConnect The way to select a particular network to connect to is specify 1231 * {@code true} for this parameter. 1232 * @return {@code true} if the operation succeeded 1233 */ enableNetwork(int netId, boolean attemptConnect)1234 public boolean enableNetwork(int netId, boolean attemptConnect) { 1235 final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP; 1236 if (pin) { 1237 NetworkRequest request = new NetworkRequest.Builder() 1238 .clearCapabilities() 1239 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) 1240 .build(); 1241 NetworkPinner.pin(mContext, request); 1242 } 1243 1244 boolean success; 1245 try { 1246 success = mService.enableNetwork(netId, attemptConnect); 1247 } catch (RemoteException e) { 1248 throw e.rethrowFromSystemServer(); 1249 } 1250 1251 if (pin && !success) { 1252 NetworkPinner.unpin(); 1253 } 1254 1255 return success; 1256 } 1257 1258 /** 1259 * Disable a configured network. The specified network will not be 1260 * a candidate for associating. This may result in the asynchronous 1261 * delivery of state change events. 1262 * 1263 * Applications are not allowed to disable networks created by other 1264 * applications. 1265 * 1266 * @param netId the ID of the network as returned by {@link #addNetwork} or {@link 1267 * #getConfiguredNetworks}. 1268 * @return {@code true} if the operation succeeded 1269 */ 1270 public boolean disableNetwork(int netId) { 1271 try { 1272 return mService.disableNetwork(netId); 1273 } catch (RemoteException e) { 1274 throw e.rethrowFromSystemServer(); 1275 } 1276 } 1277 1278 /** 1279 * Disassociate from the currently active access point. This may result 1280 * in the asynchronous delivery of state change events. 1281 * @return {@code true} if the operation succeeded 1282 */ 1283 public boolean disconnect() { 1284 try { 1285 mService.disconnect(); 1286 return true; 1287 } catch (RemoteException e) { 1288 throw e.rethrowFromSystemServer(); 1289 } 1290 } 1291 1292 /** 1293 * Reconnect to the currently active access point, if we are currently 1294 * disconnected. This may result in the asynchronous delivery of state 1295 * change events. 1296 * @return {@code true} if the operation succeeded 1297 */ 1298 public boolean reconnect() { 1299 try { 1300 mService.reconnect(); 1301 return true; 1302 } catch (RemoteException e) { 1303 throw e.rethrowFromSystemServer(); 1304 } 1305 } 1306 1307 /** 1308 * Reconnect to the currently active access point, even if we are already 1309 * connected. This may result in the asynchronous delivery of state 1310 * change events. 1311 * @return {@code true} if the operation succeeded 1312 */ 1313 public boolean reassociate() { 1314 try { 1315 mService.reassociate(); 1316 return true; 1317 } catch (RemoteException e) { 1318 throw e.rethrowFromSystemServer(); 1319 } 1320 } 1321 1322 /** 1323 * Check that the supplicant daemon is responding to requests. 1324 * @return {@code true} if we were able to communicate with the supplicant and 1325 * it returned the expected response to the PING message. 1326 * @deprecated Will return the output of {@link #isWifiEnabled()} instead. 1327 */ 1328 @Deprecated 1329 public boolean pingSupplicant() { 1330 return isWifiEnabled(); 1331 } 1332 1333 /** @hide */ 1334 public static final int WIFI_FEATURE_INFRA = 0x0001; // Basic infrastructure mode 1335 /** @hide */ 1336 public static final int WIFI_FEATURE_INFRA_5G = 0x0002; // Support for 5 GHz Band 1337 /** @hide */ 1338 public static final int WIFI_FEATURE_PASSPOINT = 0x0004; // Support for GAS/ANQP 1339 /** @hide */ 1340 public static final int WIFI_FEATURE_P2P = 0x0008; // Wifi-Direct 1341 /** @hide */ 1342 public static final int WIFI_FEATURE_MOBILE_HOTSPOT = 0x0010; // Soft AP 1343 /** @hide */ 1344 public static final int WIFI_FEATURE_SCANNER = 0x0020; // WifiScanner APIs 1345 /** @hide */ 1346 public static final int WIFI_FEATURE_AWARE = 0x0040; // Wi-Fi AWare networking 1347 /** @hide */ 1348 public static final int WIFI_FEATURE_D2D_RTT = 0x0080; // Device-to-device RTT 1349 /** @hide */ 1350 public static final int WIFI_FEATURE_D2AP_RTT = 0x0100; // Device-to-AP RTT 1351 /** @hide */ 1352 public static final int WIFI_FEATURE_BATCH_SCAN = 0x0200; // Batched Scan (deprecated) 1353 /** @hide */ 1354 public static final int WIFI_FEATURE_PNO = 0x0400; // Preferred network offload 1355 /** @hide */ 1356 public static final int WIFI_FEATURE_ADDITIONAL_STA = 0x0800; // Support for two STAs 1357 /** @hide */ 1358 public static final int WIFI_FEATURE_TDLS = 0x1000; // Tunnel directed link setup 1359 /** @hide */ 1360 public static final int WIFI_FEATURE_TDLS_OFFCHANNEL = 0x2000; // Support for TDLS off channel 1361 /** @hide */ 1362 public static final int WIFI_FEATURE_EPR = 0x4000; // Enhanced power reporting 1363 /** @hide */ 1364 public static final int WIFI_FEATURE_AP_STA = 0x8000; // AP STA Concurrency 1365 /** @hide */ 1366 public static final int WIFI_FEATURE_LINK_LAYER_STATS = 0x10000; // Link layer stats collection 1367 /** @hide */ 1368 public static final int WIFI_FEATURE_LOGGER = 0x20000; // WiFi Logger 1369 /** @hide */ 1370 public static final int WIFI_FEATURE_HAL_EPNO = 0x40000; // Enhanced PNO 1371 /** @hide */ 1372 public static final int WIFI_FEATURE_RSSI_MONITOR = 0x80000; // RSSI Monitor 1373 /** @hide */ 1374 public static final int WIFI_FEATURE_MKEEP_ALIVE = 0x100000; // mkeep_alive 1375 /** @hide */ 1376 public static final int WIFI_FEATURE_CONFIG_NDO = 0x200000; // ND offload 1377 /** @hide */ 1378 public static final int WIFI_FEATURE_TRANSMIT_POWER = 0x400000; // Capture transmit power 1379 /** @hide */ 1380 public static final int WIFI_FEATURE_CONTROL_ROAMING = 0x800000; // Control firmware roaming 1381 /** @hide */ 1382 public static final int WIFI_FEATURE_IE_WHITELIST = 0x1000000; // Probe IE white listing 1383 /** @hide */ 1384 public static final int WIFI_FEATURE_SCAN_RAND = 0x2000000; // Random MAC & Probe seq 1385 1386 1387 private int getSupportedFeatures() { 1388 try { 1389 return mService.getSupportedFeatures(); 1390 } catch (RemoteException e) { 1391 throw e.rethrowFromSystemServer(); 1392 } 1393 } 1394 1395 private boolean isFeatureSupported(int feature) { 1396 return (getSupportedFeatures() & feature) == feature; 1397 } 1398 /** 1399 * @return true if this adapter supports 5 GHz band 1400 */ 1401 public boolean is5GHzBandSupported() { 1402 return isFeatureSupported(WIFI_FEATURE_INFRA_5G); 1403 } 1404 1405 /** 1406 * @return true if this adapter supports Passpoint 1407 * @hide 1408 */ 1409 public boolean isPasspointSupported() { 1410 return isFeatureSupported(WIFI_FEATURE_PASSPOINT); 1411 } 1412 1413 /** 1414 * @return true if this adapter supports WifiP2pManager (Wi-Fi Direct) 1415 */ 1416 public boolean isP2pSupported() { 1417 return isFeatureSupported(WIFI_FEATURE_P2P); 1418 } 1419 1420 /** 1421 * @return true if this adapter supports portable Wi-Fi hotspot 1422 * @hide 1423 */ 1424 @SystemApi 1425 public boolean isPortableHotspotSupported() { 1426 return isFeatureSupported(WIFI_FEATURE_MOBILE_HOTSPOT); 1427 } 1428 1429 /** 1430 * @return true if this adapter supports WifiScanner APIs 1431 * @hide 1432 */ 1433 @SystemApi 1434 public boolean isWifiScannerSupported() { 1435 return isFeatureSupported(WIFI_FEATURE_SCANNER); 1436 } 1437 1438 /** 1439 * @return true if this adapter supports Neighbour Awareness Network APIs 1440 * @hide 1441 */ 1442 public boolean isWifiAwareSupported() { 1443 return isFeatureSupported(WIFI_FEATURE_AWARE); 1444 } 1445 1446 /** 1447 * @return true if this adapter supports Device-to-device RTT 1448 * @hide 1449 */ 1450 @SystemApi 1451 public boolean isDeviceToDeviceRttSupported() { 1452 return isFeatureSupported(WIFI_FEATURE_D2D_RTT); 1453 } 1454 1455 /** 1456 * @return true if this adapter supports Device-to-AP RTT 1457 */ 1458 @SystemApi 1459 public boolean isDeviceToApRttSupported() { 1460 return isFeatureSupported(WIFI_FEATURE_D2AP_RTT); 1461 } 1462 1463 /** 1464 * @return true if this adapter supports offloaded connectivity scan 1465 */ 1466 public boolean isPreferredNetworkOffloadSupported() { 1467 return isFeatureSupported(WIFI_FEATURE_PNO); 1468 } 1469 1470 /** 1471 * @return true if this adapter supports multiple simultaneous connections 1472 * @hide 1473 */ 1474 public boolean isAdditionalStaSupported() { 1475 return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA); 1476 } 1477 1478 /** 1479 * @return true if this adapter supports Tunnel Directed Link Setup 1480 */ 1481 public boolean isTdlsSupported() { 1482 return isFeatureSupported(WIFI_FEATURE_TDLS); 1483 } 1484 1485 /** 1486 * @return true if this adapter supports Off Channel Tunnel Directed Link Setup 1487 * @hide 1488 */ 1489 public boolean isOffChannelTdlsSupported() { 1490 return isFeatureSupported(WIFI_FEATURE_TDLS_OFFCHANNEL); 1491 } 1492 1493 /** 1494 * @return true if this adapter supports advanced power/performance counters 1495 */ 1496 public boolean isEnhancedPowerReportingSupported() { 1497 return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS); 1498 } 1499 1500 /** 1501 * Return the record of {@link WifiActivityEnergyInfo} object that 1502 * has the activity and energy info. This can be used to ascertain what 1503 * the controller has been up to, since the last sample. 1504 * @param updateType Type of info, cached vs refreshed. 1505 * 1506 * @return a record with {@link WifiActivityEnergyInfo} or null if 1507 * report is unavailable or unsupported 1508 * @hide 1509 */ 1510 public WifiActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { 1511 if (mService == null) return null; 1512 try { 1513 synchronized(this) { 1514 return mService.reportActivityInfo(); 1515 } 1516 } catch (RemoteException e) { 1517 throw e.rethrowFromSystemServer(); 1518 } 1519 } 1520 1521 /** 1522 * Request a scan for access points. Returns immediately. The availability 1523 * of the results is made known later by means of an asynchronous event sent 1524 * on completion of the scan. 1525 * @return {@code true} if the operation succeeded, i.e., the scan was initiated 1526 */ 1527 public boolean startScan() { 1528 return startScan(null); 1529 } 1530 1531 /** @hide */ 1532 @SystemApi 1533 @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) 1534 public boolean startScan(WorkSource workSource) { 1535 try { 1536 String packageName = mContext.getOpPackageName(); 1537 mService.startScan(null, workSource, packageName); 1538 return true; 1539 } catch (RemoteException e) { 1540 throw e.rethrowFromSystemServer(); 1541 } 1542 } 1543 1544 /** 1545 * startLocationRestrictedScan() 1546 * Trigger a scan which will not make use of DFS channels and is thus not suitable for 1547 * establishing wifi connection. 1548 * @deprecated This API is nolonger supported. 1549 * Use {@link android.net.wifi.WifiScanner} API 1550 * @hide 1551 */ 1552 @Deprecated 1553 @SystemApi 1554 @SuppressLint("Doclava125") 1555 public boolean startLocationRestrictedScan(WorkSource workSource) { 1556 return false; 1557 } 1558 1559 /** 1560 * Check if the Batched Scan feature is supported. 1561 * 1562 * @return false if not supported. 1563 * @deprecated This API is nolonger supported. 1564 * Use {@link android.net.wifi.WifiScanner} API 1565 * @hide 1566 */ 1567 @Deprecated 1568 @SystemApi 1569 @SuppressLint("Doclava125") 1570 public boolean isBatchedScanSupported() { 1571 return false; 1572 } 1573 1574 /** 1575 * Retrieve the latest batched scan result. This should be called immediately after 1576 * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received. 1577 * @deprecated This API is nolonger supported. 1578 * Use {@link android.net.wifi.WifiScanner} API 1579 * @hide 1580 */ 1581 @Deprecated 1582 @SystemApi 1583 @SuppressLint("Doclava125") 1584 public List<BatchedScanResult> getBatchedScanResults() { 1585 return null; 1586 } 1587 1588 /** 1589 * Creates a configuration token describing the current network of MIME type 1590 * application/vnd.wfa.wsc. Can be used to configure WiFi networks via NFC. 1591 * 1592 * @return hex-string encoded configuration token or null if there is no current network 1593 * @hide 1594 */ 1595 public String getCurrentNetworkWpsNfcConfigurationToken() { 1596 try { 1597 return mService.getCurrentNetworkWpsNfcConfigurationToken(); 1598 } catch (RemoteException e) { 1599 throw e.rethrowFromSystemServer(); 1600 } 1601 } 1602 1603 /** 1604 * Return dynamic information about the current Wi-Fi connection, if any is active. 1605 * @return the Wi-Fi information, contained in {@link WifiInfo}. 1606 */ 1607 public WifiInfo getConnectionInfo() { 1608 try { 1609 return mService.getConnectionInfo(); 1610 } catch (RemoteException e) { 1611 throw e.rethrowFromSystemServer(); 1612 } 1613 } 1614 1615 /** 1616 * Return the results of the latest access point scan. 1617 * @return the list of access points found in the most recent scan. An app must hold 1618 * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or 1619 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission 1620 * in order to get valid results. If there is a remote exception (e.g., either a communication 1621 * problem with the system service or an exception within the framework) an empty list will be 1622 * returned. 1623 */ 1624 public List<ScanResult> getScanResults() { 1625 try { 1626 return mService.getScanResults(mContext.getOpPackageName()); 1627 } catch (RemoteException e) { 1628 throw e.rethrowFromSystemServer(); 1629 } 1630 } 1631 1632 /** 1633 * Check if scanning is always available. 1634 * 1635 * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results 1636 * even when Wi-Fi is turned off. 1637 * 1638 * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}. 1639 */ 1640 public boolean isScanAlwaysAvailable() { 1641 try { 1642 return mService.isScanAlwaysAvailable(); 1643 } catch (RemoteException e) { 1644 throw e.rethrowFromSystemServer(); 1645 } 1646 } 1647 1648 /** 1649 * Tell the device to persist the current list of configured networks. 1650 * <p> 1651 * Note: It is possible for this method to change the network IDs of 1652 * existing networks. You should assume the network IDs can be different 1653 * after calling this method. 1654 * 1655 * @return {@code true} if the operation succeeded 1656 * @deprecated There is no need to call this method - 1657 * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)} 1658 * and {@link #removeNetwork(int)} already persist the configurations automatically. 1659 */ 1660 @Deprecated 1661 public boolean saveConfiguration() { 1662 try { 1663 return mService.saveConfiguration(); 1664 } catch (RemoteException e) { 1665 throw e.rethrowFromSystemServer(); 1666 } 1667 } 1668 1669 /** 1670 * Set the country code. 1671 * @param countryCode country code in ISO 3166 format. 1672 * @param persist {@code true} if this needs to be remembered 1673 * 1674 * @hide 1675 */ 1676 public void setCountryCode(String country, boolean persist) { 1677 try { 1678 mService.setCountryCode(country, persist); 1679 } catch (RemoteException e) { 1680 throw e.rethrowFromSystemServer(); 1681 } 1682 } 1683 1684 /** 1685 * get the country code. 1686 * @return the country code in ISO 3166 format. 1687 * 1688 * @hide 1689 */ 1690 public String getCountryCode() { 1691 try { 1692 String country = mService.getCountryCode(); 1693 return country; 1694 } catch (RemoteException e) { 1695 throw e.rethrowFromSystemServer(); 1696 } 1697 } 1698 1699 /** 1700 * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz) 1701 * @return {@code true} if supported, {@code false} otherwise. 1702 * @hide 1703 */ 1704 public boolean isDualBandSupported() { 1705 try { 1706 return mService.isDualBandSupported(); 1707 } catch (RemoteException e) { 1708 throw e.rethrowFromSystemServer(); 1709 } 1710 } 1711 1712 /** 1713 * Return the DHCP-assigned addresses from the last successful DHCP request, 1714 * if any. 1715 * @return the DHCP information 1716 */ 1717 public DhcpInfo getDhcpInfo() { 1718 try { 1719 return mService.getDhcpInfo(); 1720 } catch (RemoteException e) { 1721 throw e.rethrowFromSystemServer(); 1722 } 1723 } 1724 1725 /** 1726 * Enable or disable Wi-Fi. 1727 * @param enabled {@code true} to enable, {@code false} to disable. 1728 * @return {@code true} if the operation succeeds (or if the existing state 1729 * is the same as the requested state). 1730 */ 1731 public boolean setWifiEnabled(boolean enabled) { 1732 try { 1733 return mService.setWifiEnabled(mContext.getOpPackageName(), enabled); 1734 } catch (RemoteException e) { 1735 throw e.rethrowFromSystemServer(); 1736 } 1737 } 1738 1739 /** 1740 * Gets the Wi-Fi enabled state. 1741 * @return One of {@link #WIFI_STATE_DISABLED}, 1742 * {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED}, 1743 * {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN} 1744 * @see #isWifiEnabled() 1745 */ 1746 public int getWifiState() { 1747 try { 1748 return mService.getWifiEnabledState(); 1749 } catch (RemoteException e) { 1750 throw e.rethrowFromSystemServer(); 1751 } 1752 } 1753 1754 /** 1755 * Return whether Wi-Fi is enabled or disabled. 1756 * @return {@code true} if Wi-Fi is enabled 1757 * @see #getWifiState() 1758 */ 1759 public boolean isWifiEnabled() { 1760 return getWifiState() == WIFI_STATE_ENABLED; 1761 } 1762 1763 /** 1764 * Return TX packet counter, for CTS test of WiFi watchdog. 1765 * @param listener is the interface to receive result 1766 * 1767 * @hide for CTS test only 1768 */ 1769 public void getTxPacketCount(TxPacketCountListener listener) { 1770 getChannel().sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener)); 1771 } 1772 1773 /** 1774 * Calculates the level of the signal. This should be used any time a signal 1775 * is being shown. 1776 * 1777 * @param rssi The power of the signal measured in RSSI. 1778 * @param numLevels The number of levels to consider in the calculated 1779 * level. 1780 * @return A level of the signal, given in the range of 0 to numLevels-1 1781 * (both inclusive). 1782 */ 1783 public static int calculateSignalLevel(int rssi, int numLevels) { 1784 if (rssi <= MIN_RSSI) { 1785 return 0; 1786 } else if (rssi >= MAX_RSSI) { 1787 return numLevels - 1; 1788 } else { 1789 float inputRange = (MAX_RSSI - MIN_RSSI); 1790 float outputRange = (numLevels - 1); 1791 return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange); 1792 } 1793 } 1794 1795 /** 1796 * Compares two signal strengths. 1797 * 1798 * @param rssiA The power of the first signal measured in RSSI. 1799 * @param rssiB The power of the second signal measured in RSSI. 1800 * @return Returns <0 if the first signal is weaker than the second signal, 1801 * 0 if the two signals have the same strength, and >0 if the first 1802 * signal is stronger than the second signal. 1803 */ 1804 public static int compareSignalLevel(int rssiA, int rssiB) { 1805 return rssiA - rssiB; 1806 } 1807 1808 /** 1809 * This call will be deprecated and removed in an upcoming release. It is no longer used to 1810 * start WiFi Tethering. Please use {@link ConnectivityManager#startTethering(int, boolean, 1811 * ConnectivityManager#OnStartTetheringCallback)} if 1812 * the caller has proper permissions. Callers can also use the LocalOnlyHotspot feature for a 1813 * hotspot capable of communicating with co-located devices {@link 1814 * WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}. 1815 * 1816 * @param wifiConfig SSID, security and channel details as 1817 * part of WifiConfiguration 1818 * @return {@code false} 1819 * 1820 * @hide 1821 */ 1822 @SystemApi 1823 @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) 1824 public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { 1825 String packageName = mContext.getOpPackageName(); 1826 1827 Log.w(TAG, packageName + " attempted call to setWifiApEnabled: enabled = " + enabled); 1828 return false; 1829 } 1830 1831 /** 1832 * Call allowing ConnectivityService to update WifiService with interface mode changes. 1833 * 1834 * The possible modes include: {@link IFACE_IP_MODE_TETHERED}, 1835 * {@link IFACE_IP_MODE_LOCAL_ONLY}, 1836 * {@link IFACE_IP_MODE_CONFIGURATION_ERROR} 1837 * 1838 * @param ifaceName String name of the updated interface 1839 * @param mode int representing the new mode 1840 * 1841 * @hide 1842 */ 1843 public void updateInterfaceIpState(String ifaceName, int mode) { 1844 try { 1845 mService.updateInterfaceIpState(ifaceName, mode); 1846 } catch (RemoteException e) { 1847 throw e.rethrowFromSystemServer(); 1848 } 1849 } 1850 1851 /** 1852 * Start SoftAp mode with the specified configuration. 1853 * Note that starting in access point mode disables station 1854 * mode operation 1855 * @param wifiConfig SSID, security and channel details as 1856 * part of WifiConfiguration 1857 * @return {@code true} if the operation succeeds, {@code false} otherwise 1858 * 1859 * @hide 1860 */ 1861 public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) { 1862 try { 1863 return mService.startSoftAp(wifiConfig); 1864 } catch (RemoteException e) { 1865 throw e.rethrowFromSystemServer(); 1866 } 1867 } 1868 1869 /** 1870 * Stop SoftAp mode. 1871 * Note that stopping softap mode will restore the previous wifi mode. 1872 * @return {@code true} if the operation succeeds, {@code false} otherwise 1873 * 1874 * @hide 1875 */ 1876 public boolean stopSoftAp() { 1877 try { 1878 return mService.stopSoftAp(); 1879 } catch (RemoteException e) { 1880 throw e.rethrowFromSystemServer(); 1881 } 1882 } 1883 1884 /** 1885 * Request a local only hotspot that an application can use to communicate between co-located 1886 * devices connected to the created WiFi hotspot. The network created by this method will not 1887 * have Internet access. Each application can make a single request for the hotspot, but 1888 * multiple applications could be requesting the hotspot at the same time. When multiple 1889 * applications have successfully registered concurrently, they will be sharing the underlying 1890 * hotspot. {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} is called 1891 * when the hotspot is ready for use by the application. 1892 * <p> 1893 * Each application can make a single active call to this method. The {@link 1894 * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} callback supplies the 1895 * requestor with a {@link LocalOnlyHotspotReservation} that contains a 1896 * {@link WifiConfiguration} with the SSID, security type and credentials needed to connect 1897 * to the hotspot. Communicating this information is up to the application. 1898 * <p> 1899 * If the LocalOnlyHotspot cannot be created, the {@link LocalOnlyHotspotCallback#onFailed(int)} 1900 * method will be called. Example failures include errors bringing up the network or if 1901 * there is an incompatible operating mode. For example, if the user is currently using Wifi 1902 * Tethering to provide an upstream to another device, LocalOnlyHotspot will not start due to 1903 * an incompatible mode. The possible error codes include: 1904 * {@link LocalOnlyHotspotCallback#ERROR_NO_CHANNEL}, 1905 * {@link LocalOnlyHotspotCallback#ERROR_GENERIC}, 1906 * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE} and 1907 * {@link LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED}. 1908 * <p> 1909 * Internally, requests will be tracked to prevent the hotspot from being torn down while apps 1910 * are still using it. The {@link LocalOnlyHotspotReservation} object passed in the {@link 1911 * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call should be closed when 1912 * the LocalOnlyHotspot is no longer needed using {@link LocalOnlyHotspotReservation#close()}. 1913 * Since the hotspot may be shared among multiple applications, removing the final registered 1914 * application request will trigger the hotspot teardown. This means that applications should 1915 * not listen to broadcasts containing wifi state to determine if the hotspot was stopped after 1916 * they are done using it. Additionally, once {@link LocalOnlyHotspotReservation#close()} is 1917 * called, applications will not receive callbacks of any kind. 1918 * <p> 1919 * Applications should be aware that the user may also stop the LocalOnlyHotspot through the 1920 * Settings UI; it is not guaranteed to stay up as long as there is a requesting application. 1921 * The requestors will be notified of this case via 1922 * {@link LocalOnlyHotspotCallback#onStopped()}. Other cases may arise where the hotspot is 1923 * torn down (Emergency mode, etc). Application developers should be aware that it can stop 1924 * unexpectedly, but they will receive a notification if they have properly registered. 1925 * <p> 1926 * Applications should also be aware that this network will be shared with other applications. 1927 * Applications are responsible for protecting their data on this network (e.g., TLS). 1928 * <p> 1929 * Applications need to have the following permissions to start LocalOnlyHotspot: {@link 1930 * android.Manifest.permission#CHANGE_WIFI_STATE} and {@link 1931 * android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}. Callers without 1932 * the permissions will trigger a {@link java.lang.SecurityException}. 1933 * <p> 1934 * @param callback LocalOnlyHotspotCallback for the application to receive updates about 1935 * operating status. 1936 * @param handler Handler to be used for callbacks. If the caller passes a null Handler, the 1937 * main thread will be used. 1938 */ 1939 public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback, 1940 @Nullable Handler handler) { 1941 synchronized (mLock) { 1942 Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); 1943 LocalOnlyHotspotCallbackProxy proxy = 1944 new LocalOnlyHotspotCallbackProxy(this, looper, callback); 1945 try { 1946 String packageName = mContext.getOpPackageName(); 1947 int returnCode = mService.startLocalOnlyHotspot( 1948 proxy.getMessenger(), new Binder(), packageName); 1949 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) { 1950 // Send message to the proxy to make sure we call back on the correct thread 1951 proxy.notifyFailed(returnCode); 1952 return; 1953 } 1954 mLOHSCallbackProxy = proxy; 1955 } catch (RemoteException e) { 1956 throw e.rethrowFromSystemServer(); 1957 } 1958 } 1959 } 1960 1961 /** 1962 * Cancels a pending local only hotspot request. This can be used by the calling application to 1963 * cancel the existing request if the provided callback has not been triggered. Calling this 1964 * method will be equivalent to closing the returned LocalOnlyHotspotReservation, but it is not 1965 * explicitly required. 1966 * <p> 1967 * When cancelling this request, application developers should be aware that there may still be 1968 * outstanding local only hotspot requests and the hotspot may still start, or continue running. 1969 * Additionally, if a callback was registered, it will no longer be triggered after calling 1970 * cancel. 1971 * 1972 * @hide 1973 */ 1974 public void cancelLocalOnlyHotspotRequest() { 1975 synchronized (mLock) { 1976 stopLocalOnlyHotspot(); 1977 } 1978 } 1979 1980 /** 1981 * Method used to inform WifiService that the LocalOnlyHotspot is no longer needed. This 1982 * method is used by WifiManager to release LocalOnlyHotspotReservations held by calling 1983 * applications and removes the internal tracking for the hotspot request. When all requesting 1984 * applications are finished using the hotspot, it will be stopped and WiFi will return to the 1985 * previous operational mode. 1986 * 1987 * This method should not be called by applications. Instead, they should call the close() 1988 * method on their LocalOnlyHotspotReservation. 1989 */ 1990 private void stopLocalOnlyHotspot() { 1991 synchronized (mLock) { 1992 if (mLOHSCallbackProxy == null) { 1993 // nothing to do, the callback was already cleaned up. 1994 return; 1995 } 1996 mLOHSCallbackProxy = null; 1997 try { 1998 mService.stopLocalOnlyHotspot(); 1999 } catch (RemoteException e) { 2000 throw e.rethrowFromSystemServer(); 2001 } 2002 } 2003 } 2004 2005 /** 2006 * Allow callers (Settings UI) to watch LocalOnlyHotspot state changes. Callers will 2007 * receive a {@link LocalOnlyHotspotSubscription} object as a parameter of the 2008 * {@link LocalOnlyHotspotObserver#onRegistered(LocalOnlyHotspotSubscription)}. The registered 2009 * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(WifiConfiguration)} and 2010 * {@link LocalOnlyHotspotObserver#onStopped()} callbacks. 2011 * <p> 2012 * Applications should have the 2013 * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} 2014 * permission. Callers without the permission will trigger a 2015 * {@link java.lang.SecurityException}. 2016 * <p> 2017 * @param observer LocalOnlyHotspotObserver callback. 2018 * @param handler Handler to use for callbacks 2019 * 2020 * @hide 2021 */ 2022 public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer, 2023 @Nullable Handler handler) { 2024 synchronized (mLock) { 2025 Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); 2026 mLOHSObserverProxy = new LocalOnlyHotspotObserverProxy(this, looper, observer); 2027 try { 2028 mService.startWatchLocalOnlyHotspot( 2029 mLOHSObserverProxy.getMessenger(), new Binder()); 2030 mLOHSObserverProxy.registered(); 2031 } catch (RemoteException e) { 2032 mLOHSObserverProxy = null; 2033 throw e.rethrowFromSystemServer(); 2034 } 2035 } 2036 } 2037 2038 /** 2039 * Allow callers to stop watching LocalOnlyHotspot state changes. After calling this method, 2040 * applications will no longer receive callbacks. 2041 * 2042 * @hide 2043 */ 2044 public void unregisterLocalOnlyHotspotObserver() { 2045 synchronized (mLock) { 2046 if (mLOHSObserverProxy == null) { 2047 // nothing to do, the callback was already cleaned up 2048 return; 2049 } 2050 mLOHSObserverProxy = null; 2051 try { 2052 mService.stopWatchLocalOnlyHotspot(); 2053 } catch (RemoteException e) { 2054 throw e.rethrowFromSystemServer(); 2055 } 2056 } 2057 } 2058 2059 /** 2060 * Gets the Wi-Fi enabled state. 2061 * @return One of {@link #WIFI_AP_STATE_DISABLED}, 2062 * {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED}, 2063 * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} 2064 * @see #isWifiApEnabled() 2065 * 2066 * @hide 2067 */ 2068 @SystemApi 2069 @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) 2070 public int getWifiApState() { 2071 try { 2072 return mService.getWifiApEnabledState(); 2073 } catch (RemoteException e) { 2074 throw e.rethrowFromSystemServer(); 2075 } 2076 } 2077 2078 /** 2079 * Return whether Wi-Fi AP is enabled or disabled. 2080 * @return {@code true} if Wi-Fi AP is enabled 2081 * @see #getWifiApState() 2082 * 2083 * @hide 2084 */ 2085 @SystemApi 2086 @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) 2087 public boolean isWifiApEnabled() { 2088 return getWifiApState() == WIFI_AP_STATE_ENABLED; 2089 } 2090 2091 /** 2092 * Gets the Wi-Fi AP Configuration. 2093 * @return AP details in WifiConfiguration 2094 * 2095 * @hide 2096 */ 2097 @SystemApi 2098 @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) 2099 public WifiConfiguration getWifiApConfiguration() { 2100 try { 2101 return mService.getWifiApConfiguration(); 2102 } catch (RemoteException e) { 2103 throw e.rethrowFromSystemServer(); 2104 } 2105 } 2106 2107 /** 2108 * Sets the Wi-Fi AP Configuration. 2109 * @return {@code true} if the operation succeeded, {@code false} otherwise 2110 * 2111 * @hide 2112 */ 2113 @SystemApi 2114 @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) 2115 public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) { 2116 try { 2117 mService.setWifiApConfiguration(wifiConfig); 2118 return true; 2119 } catch (RemoteException e) { 2120 throw e.rethrowFromSystemServer(); 2121 } 2122 } 2123 2124 /** 2125 * Enable/Disable TDLS on a specific local route. 2126 * 2127 * <p> 2128 * TDLS enables two wireless endpoints to talk to each other directly 2129 * without going through the access point that is managing the local 2130 * network. It saves bandwidth and improves quality of the link. 2131 * </p> 2132 * <p> 2133 * This API enables/disables the option of using TDLS. If enabled, the 2134 * underlying hardware is free to use TDLS or a hop through the access 2135 * point. If disabled, existing TDLS session is torn down and 2136 * hardware is restricted to use access point for transferring wireless 2137 * packets. Default value for all routes is 'disabled', meaning restricted 2138 * to use access point for transferring packets. 2139 * </p> 2140 * 2141 * @param remoteIPAddress IP address of the endpoint to setup TDLS with 2142 * @param enable true = setup and false = tear down TDLS 2143 */ 2144 public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) { 2145 try { 2146 mService.enableTdls(remoteIPAddress.getHostAddress(), enable); 2147 } catch (RemoteException e) { 2148 throw e.rethrowFromSystemServer(); 2149 } 2150 } 2151 2152 /** 2153 * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except 2154 * this version allows you to specify remote endpoint with a MAC address. 2155 * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab 2156 * @param enable true = setup and false = tear down TDLS 2157 */ 2158 public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) { 2159 try { 2160 mService.enableTdlsWithMacAddress(remoteMacAddress, enable); 2161 } catch (RemoteException e) { 2162 throw e.rethrowFromSystemServer(); 2163 } 2164 } 2165 2166 /* TODO: deprecate synchronous API and open up the following API */ 2167 2168 private static final int BASE = Protocol.BASE_WIFI_MANAGER; 2169 2170 /* Commands to WifiService */ 2171 /** @hide */ 2172 public static final int CONNECT_NETWORK = BASE + 1; 2173 /** @hide */ 2174 public static final int CONNECT_NETWORK_FAILED = BASE + 2; 2175 /** @hide */ 2176 public static final int CONNECT_NETWORK_SUCCEEDED = BASE + 3; 2177 2178 /** @hide */ 2179 public static final int FORGET_NETWORK = BASE + 4; 2180 /** @hide */ 2181 public static final int FORGET_NETWORK_FAILED = BASE + 5; 2182 /** @hide */ 2183 public static final int FORGET_NETWORK_SUCCEEDED = BASE + 6; 2184 2185 /** @hide */ 2186 public static final int SAVE_NETWORK = BASE + 7; 2187 /** @hide */ 2188 public static final int SAVE_NETWORK_FAILED = BASE + 8; 2189 /** @hide */ 2190 public static final int SAVE_NETWORK_SUCCEEDED = BASE + 9; 2191 2192 /** @hide */ 2193 public static final int START_WPS = BASE + 10; 2194 /** @hide */ 2195 public static final int START_WPS_SUCCEEDED = BASE + 11; 2196 /** @hide */ 2197 public static final int WPS_FAILED = BASE + 12; 2198 /** @hide */ 2199 public static final int WPS_COMPLETED = BASE + 13; 2200 2201 /** @hide */ 2202 public static final int CANCEL_WPS = BASE + 14; 2203 /** @hide */ 2204 public static final int CANCEL_WPS_FAILED = BASE + 15; 2205 /** @hide */ 2206 public static final int CANCEL_WPS_SUCCEDED = BASE + 16; 2207 2208 /** @hide */ 2209 public static final int DISABLE_NETWORK = BASE + 17; 2210 /** @hide */ 2211 public static final int DISABLE_NETWORK_FAILED = BASE + 18; 2212 /** @hide */ 2213 public static final int DISABLE_NETWORK_SUCCEEDED = BASE + 19; 2214 2215 /** @hide */ 2216 public static final int RSSI_PKTCNT_FETCH = BASE + 20; 2217 /** @hide */ 2218 public static final int RSSI_PKTCNT_FETCH_SUCCEEDED = BASE + 21; 2219 /** @hide */ 2220 public static final int RSSI_PKTCNT_FETCH_FAILED = BASE + 22; 2221 2222 /** 2223 * Passed with {@link ActionListener#onFailure}. 2224 * Indicates that the operation failed due to an internal error. 2225 * @hide 2226 */ 2227 public static final int ERROR = 0; 2228 2229 /** 2230 * Passed with {@link ActionListener#onFailure}. 2231 * Indicates that the operation is already in progress 2232 * @hide 2233 */ 2234 public static final int IN_PROGRESS = 1; 2235 2236 /** 2237 * Passed with {@link ActionListener#onFailure}. 2238 * Indicates that the operation failed because the framework is busy and 2239 * unable to service the request 2240 * @hide 2241 */ 2242 public static final int BUSY = 2; 2243 2244 /* WPS specific errors */ 2245 /** WPS overlap detected */ 2246 public static final int WPS_OVERLAP_ERROR = 3; 2247 /** WEP on WPS is prohibited */ 2248 public static final int WPS_WEP_PROHIBITED = 4; 2249 /** TKIP only prohibited */ 2250 public static final int WPS_TKIP_ONLY_PROHIBITED = 5; 2251 /** Authentication failure on WPS */ 2252 public static final int WPS_AUTH_FAILURE = 6; 2253 /** WPS timed out */ 2254 public static final int WPS_TIMED_OUT = 7; 2255 2256 /** 2257 * Passed with {@link ActionListener#onFailure}. 2258 * Indicates that the operation failed due to invalid inputs 2259 * @hide 2260 */ 2261 public static final int INVALID_ARGS = 8; 2262 2263 /** 2264 * Passed with {@link ActionListener#onFailure}. 2265 * Indicates that the operation failed due to user permissions. 2266 * @hide 2267 */ 2268 public static final int NOT_AUTHORIZED = 9; 2269 2270 /** 2271 * Interface for callback invocation on an application action 2272 * @hide 2273 */ 2274 @SystemApi 2275 public interface ActionListener { 2276 /** The operation succeeded */ 2277 public void onSuccess(); 2278 /** 2279 * The operation failed 2280 * @param reason The reason for failure could be one of 2281 * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY} 2282 */ 2283 public void onFailure(int reason); 2284 } 2285 2286 /** Interface for callback invocation on a start WPS action */ 2287 public static abstract class WpsCallback { 2288 /** WPS start succeeded */ 2289 public abstract void onStarted(String pin); 2290 2291 /** WPS operation completed succesfully */ 2292 public abstract void onSucceeded(); 2293 2294 /** 2295 * WPS operation failed 2296 * @param reason The reason for failure could be one of 2297 * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR}, 2298 * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE} 2299 * and some generic errors. 2300 */ 2301 public abstract void onFailed(int reason); 2302 } 2303 2304 /** Interface for callback invocation on a TX packet count poll action {@hide} */ 2305 public interface TxPacketCountListener { 2306 /** 2307 * The operation succeeded 2308 * @param count TX packet counter 2309 */ 2310 public void onSuccess(int count); 2311 /** 2312 * The operation failed 2313 * @param reason The reason for failure could be one of 2314 * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY} 2315 */ 2316 public void onFailure(int reason); 2317 } 2318 2319 /** 2320 * LocalOnlyHotspotReservation that contains the {@link WifiConfiguration} for the active 2321 * LocalOnlyHotspot request. 2322 * <p> 2323 * Applications requesting LocalOnlyHotspot for sharing will receive an instance of the 2324 * LocalOnlyHotspotReservation in the 2325 * {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call. This 2326 * reservation contains the relevant {@link WifiConfiguration}. 2327 * When an application is done with the LocalOnlyHotspot, they should call {@link 2328 * LocalOnlyHotspotReservation#close()}. Once this happens, the application will not receive 2329 * any further callbacks. If the LocalOnlyHotspot is stopped due to a 2330 * user triggered mode change, applications will be notified via the {@link 2331 * LocalOnlyHotspotCallback#onStopped()} callback. 2332 */ 2333 public class LocalOnlyHotspotReservation implements AutoCloseable { 2334 2335 private final CloseGuard mCloseGuard = CloseGuard.get(); 2336 private final WifiConfiguration mConfig; 2337 2338 /** @hide */ 2339 @VisibleForTesting 2340 public LocalOnlyHotspotReservation(WifiConfiguration config) { 2341 mConfig = config; 2342 mCloseGuard.open("close"); 2343 } 2344 2345 public WifiConfiguration getWifiConfiguration() { 2346 return mConfig; 2347 } 2348 2349 @Override 2350 public void close() { 2351 try { 2352 stopLocalOnlyHotspot(); 2353 mCloseGuard.close(); 2354 } catch (Exception e) { 2355 Log.e(TAG, "Failed to stop Local Only Hotspot."); 2356 } 2357 } 2358 2359 @Override 2360 protected void finalize() throws Throwable { 2361 try { 2362 if (mCloseGuard != null) { 2363 mCloseGuard.warnIfOpen(); 2364 } 2365 close(); 2366 } finally { 2367 super.finalize(); 2368 } 2369 } 2370 } 2371 2372 /** 2373 * Callback class for applications to receive updates about the LocalOnlyHotspot status. 2374 */ 2375 public static class LocalOnlyHotspotCallback { 2376 /** @hide */ 2377 public static final int REQUEST_REGISTERED = 0; 2378 2379 public static final int ERROR_NO_CHANNEL = 1; 2380 public static final int ERROR_GENERIC = 2; 2381 public static final int ERROR_INCOMPATIBLE_MODE = 3; 2382 public static final int ERROR_TETHERING_DISALLOWED = 4; 2383 2384 /** LocalOnlyHotspot start succeeded. */ 2385 public void onStarted(LocalOnlyHotspotReservation reservation) {}; 2386 2387 /** 2388 * LocalOnlyHotspot stopped. 2389 * <p> 2390 * The LocalOnlyHotspot can be disabled at any time by the user. When this happens, 2391 * applications will be notified that it was stopped. This will not be invoked when an 2392 * application calls {@link LocalOnlyHotspotReservation#close()}. 2393 */ 2394 public void onStopped() {}; 2395 2396 /** 2397 * LocalOnlyHotspot failed to start. 2398 * <p> 2399 * Applications can attempt to call 2400 * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)} again at 2401 * a later time. 2402 * <p> 2403 * @param reason The reason for failure could be one of: {@link 2404 * #ERROR_TETHERING_DISALLOWED}, {@link #ERROR_INCOMPATIBLE_MODE}, 2405 * {@link #ERROR_NO_CHANNEL}, or {@link #ERROR_GENERIC}. 2406 */ 2407 public void onFailed(int reason) { }; 2408 } 2409 2410 /** 2411 * Callback proxy for LocalOnlyHotspotCallback objects. 2412 */ 2413 private static class LocalOnlyHotspotCallbackProxy { 2414 private final Handler mHandler; 2415 private final WeakReference<WifiManager> mWifiManager; 2416 private final Looper mLooper; 2417 private final Messenger mMessenger; 2418 2419 /** 2420 * Constructs a {@link LocalOnlyHotspotCallback} using the specified looper. All callbacks 2421 * will be delivered on the thread of the specified looper. 2422 * 2423 * @param manager WifiManager 2424 * @param looper Looper for delivering callbacks 2425 * @param callback LocalOnlyHotspotCallback to notify the calling application. 2426 */ 2427 LocalOnlyHotspotCallbackProxy(WifiManager manager, Looper looper, 2428 final LocalOnlyHotspotCallback callback) { 2429 mWifiManager = new WeakReference<>(manager); 2430 mLooper = looper; 2431 2432 mHandler = new Handler(looper) { 2433 @Override 2434 public void handleMessage(Message msg) { 2435 Log.d(TAG, "LocalOnlyHotspotCallbackProxy: handle message what: " 2436 + msg.what + " msg: " + msg); 2437 2438 WifiManager manager = mWifiManager.get(); 2439 if (manager == null) { 2440 Log.w(TAG, "LocalOnlyHotspotCallbackProxy: handle message post GC"); 2441 return; 2442 } 2443 2444 switch (msg.what) { 2445 case HOTSPOT_STARTED: 2446 WifiConfiguration config = (WifiConfiguration) msg.obj; 2447 if (config == null) { 2448 Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null."); 2449 callback.onFailed(LocalOnlyHotspotCallback.ERROR_GENERIC); 2450 return; 2451 } 2452 callback.onStarted(manager.new LocalOnlyHotspotReservation(config)); 2453 break; 2454 case HOTSPOT_STOPPED: 2455 Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped"); 2456 callback.onStopped(); 2457 break; 2458 case HOTSPOT_FAILED: 2459 int reasonCode = msg.arg1; 2460 Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start. reason: " 2461 + reasonCode); 2462 callback.onFailed(reasonCode); 2463 Log.w(TAG, "done with the callback..."); 2464 break; 2465 default: 2466 Log.e(TAG, "LocalOnlyHotspotCallbackProxy unhandled message. type: " 2467 + msg.what); 2468 } 2469 } 2470 }; 2471 mMessenger = new Messenger(mHandler); 2472 } 2473 2474 public Messenger getMessenger() { 2475 return mMessenger; 2476 } 2477 2478 /** 2479 * Helper method allowing the the incoming application call to move the onFailed callback 2480 * over to the desired callback thread. 2481 * 2482 * @param reason int representing the error type 2483 */ 2484 public void notifyFailed(int reason) throws RemoteException { 2485 Message msg = Message.obtain(); 2486 msg.what = HOTSPOT_FAILED; 2487 msg.arg1 = reason; 2488 mMessenger.send(msg); 2489 } 2490 } 2491 2492 /** 2493 * LocalOnlyHotspotSubscription that is an AutoCloseable object for tracking applications 2494 * watching for LocalOnlyHotspot changes. 2495 * 2496 * @hide 2497 */ 2498 public class LocalOnlyHotspotSubscription implements AutoCloseable { 2499 private final CloseGuard mCloseGuard = CloseGuard.get(); 2500 2501 /** @hide */ 2502 @VisibleForTesting 2503 public LocalOnlyHotspotSubscription() { 2504 mCloseGuard.open("close"); 2505 } 2506 2507 @Override 2508 public void close() { 2509 try { 2510 unregisterLocalOnlyHotspotObserver(); 2511 mCloseGuard.close(); 2512 } catch (Exception e) { 2513 Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver."); 2514 } 2515 } 2516 2517 @Override 2518 protected void finalize() throws Throwable { 2519 try { 2520 if (mCloseGuard != null) { 2521 mCloseGuard.warnIfOpen(); 2522 } 2523 close(); 2524 } finally { 2525 super.finalize(); 2526 } 2527 } 2528 } 2529 2530 /** 2531 * Class to notify calling applications that watch for changes in LocalOnlyHotspot of updates. 2532 * 2533 * @hide 2534 */ 2535 public static class LocalOnlyHotspotObserver { 2536 /** 2537 * Confirm registration for LocalOnlyHotspotChanges by returning a 2538 * LocalOnlyHotspotSubscription. 2539 */ 2540 public void onRegistered(LocalOnlyHotspotSubscription subscription) {}; 2541 2542 /** 2543 * LocalOnlyHotspot started with the supplied config. 2544 */ 2545 public void onStarted(WifiConfiguration config) {}; 2546 2547 /** 2548 * LocalOnlyHotspot stopped. 2549 */ 2550 public void onStopped() {}; 2551 } 2552 2553 /** 2554 * Callback proxy for LocalOnlyHotspotObserver objects. 2555 */ 2556 private static class LocalOnlyHotspotObserverProxy { 2557 private final Handler mHandler; 2558 private final WeakReference<WifiManager> mWifiManager; 2559 private final Looper mLooper; 2560 private final Messenger mMessenger; 2561 2562 /** 2563 * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper. 2564 * All callbacks will be delivered on the thread of the specified looper. 2565 * 2566 * @param manager WifiManager 2567 * @param looper Looper for delivering callbacks 2568 * @param observer LocalOnlyHotspotObserver to notify the calling application. 2569 */ 2570 LocalOnlyHotspotObserverProxy(WifiManager manager, Looper looper, 2571 final LocalOnlyHotspotObserver observer) { 2572 mWifiManager = new WeakReference<>(manager); 2573 mLooper = looper; 2574 2575 mHandler = new Handler(looper) { 2576 @Override 2577 public void handleMessage(Message msg) { 2578 Log.d(TAG, "LocalOnlyHotspotObserverProxy: handle message what: " 2579 + msg.what + " msg: " + msg); 2580 2581 WifiManager manager = mWifiManager.get(); 2582 if (manager == null) { 2583 Log.w(TAG, "LocalOnlyHotspotObserverProxy: handle message post GC"); 2584 return; 2585 } 2586 2587 switch (msg.what) { 2588 case HOTSPOT_OBSERVER_REGISTERED: 2589 observer.onRegistered(manager.new LocalOnlyHotspotSubscription()); 2590 break; 2591 case HOTSPOT_STARTED: 2592 WifiConfiguration config = (WifiConfiguration) msg.obj; 2593 if (config == null) { 2594 Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null."); 2595 return; 2596 } 2597 observer.onStarted(config); 2598 break; 2599 case HOTSPOT_STOPPED: 2600 observer.onStopped(); 2601 break; 2602 default: 2603 Log.e(TAG, "LocalOnlyHotspotObserverProxy unhandled message. type: " 2604 + msg.what); 2605 } 2606 } 2607 }; 2608 mMessenger = new Messenger(mHandler); 2609 } 2610 2611 public Messenger getMessenger() { 2612 return mMessenger; 2613 } 2614 2615 public void registered() throws RemoteException { 2616 Message msg = Message.obtain(); 2617 msg.what = HOTSPOT_OBSERVER_REGISTERED; 2618 mMessenger.send(msg); 2619 } 2620 } 2621 2622 // Ensure that multiple ServiceHandler threads do not interleave message dispatch. 2623 private static final Object sServiceHandlerDispatchLock = new Object(); 2624 2625 private class ServiceHandler extends Handler { 2626 ServiceHandler(Looper looper) { 2627 super(looper); 2628 } 2629 2630 @Override 2631 public void handleMessage(Message message) { 2632 synchronized (sServiceHandlerDispatchLock) { 2633 dispatchMessageToListeners(message); 2634 } 2635 } 2636 2637 private void dispatchMessageToListeners(Message message) { 2638 Object listener = removeListener(message.arg2); 2639 switch (message.what) { 2640 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 2641 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 2642 mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 2643 } else { 2644 Log.e(TAG, "Failed to set up channel connection"); 2645 // This will cause all further async API calls on the WifiManager 2646 // to fail and throw an exception 2647 mAsyncChannel = null; 2648 } 2649 mConnected.countDown(); 2650 break; 2651 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: 2652 // Ignore 2653 break; 2654 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 2655 Log.e(TAG, "Channel connection lost"); 2656 // This will cause all further async API calls on the WifiManager 2657 // to fail and throw an exception 2658 mAsyncChannel = null; 2659 getLooper().quit(); 2660 break; 2661 /* ActionListeners grouped together */ 2662 case WifiManager.CONNECT_NETWORK_FAILED: 2663 case WifiManager.FORGET_NETWORK_FAILED: 2664 case WifiManager.SAVE_NETWORK_FAILED: 2665 case WifiManager.DISABLE_NETWORK_FAILED: 2666 if (listener != null) { 2667 ((ActionListener) listener).onFailure(message.arg1); 2668 } 2669 break; 2670 /* ActionListeners grouped together */ 2671 case WifiManager.CONNECT_NETWORK_SUCCEEDED: 2672 case WifiManager.FORGET_NETWORK_SUCCEEDED: 2673 case WifiManager.SAVE_NETWORK_SUCCEEDED: 2674 case WifiManager.DISABLE_NETWORK_SUCCEEDED: 2675 if (listener != null) { 2676 ((ActionListener) listener).onSuccess(); 2677 } 2678 break; 2679 case WifiManager.START_WPS_SUCCEEDED: 2680 if (listener != null) { 2681 WpsResult result = (WpsResult) message.obj; 2682 ((WpsCallback) listener).onStarted(result.pin); 2683 //Listener needs to stay until completion or failure 2684 synchronized (mListenerMapLock) { 2685 mListenerMap.put(message.arg2, listener); 2686 } 2687 } 2688 break; 2689 case WifiManager.WPS_COMPLETED: 2690 if (listener != null) { 2691 ((WpsCallback) listener).onSucceeded(); 2692 } 2693 break; 2694 case WifiManager.WPS_FAILED: 2695 if (listener != null) { 2696 ((WpsCallback) listener).onFailed(message.arg1); 2697 } 2698 break; 2699 case WifiManager.CANCEL_WPS_SUCCEDED: 2700 if (listener != null) { 2701 ((WpsCallback) listener).onSucceeded(); 2702 } 2703 break; 2704 case WifiManager.CANCEL_WPS_FAILED: 2705 if (listener != null) { 2706 ((WpsCallback) listener).onFailed(message.arg1); 2707 } 2708 break; 2709 case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED: 2710 if (listener != null) { 2711 RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj; 2712 if (info != null) 2713 ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad); 2714 else 2715 ((TxPacketCountListener) listener).onFailure(ERROR); 2716 } 2717 break; 2718 case WifiManager.RSSI_PKTCNT_FETCH_FAILED: 2719 if (listener != null) { 2720 ((TxPacketCountListener) listener).onFailure(message.arg1); 2721 } 2722 break; 2723 default: 2724 //ignore 2725 break; 2726 } 2727 } 2728 } 2729 2730 private int putListener(Object listener) { 2731 if (listener == null) return INVALID_KEY; 2732 int key; 2733 synchronized (mListenerMapLock) { 2734 do { 2735 key = mListenerKey++; 2736 } while (key == INVALID_KEY); 2737 mListenerMap.put(key, listener); 2738 } 2739 return key; 2740 } 2741 2742 private Object removeListener(int key) { 2743 if (key == INVALID_KEY) return null; 2744 synchronized (mListenerMapLock) { 2745 Object listener = mListenerMap.get(key); 2746 mListenerMap.remove(key); 2747 return listener; 2748 } 2749 } 2750 2751 private synchronized AsyncChannel getChannel() { 2752 if (mAsyncChannel == null) { 2753 Messenger messenger = getWifiServiceMessenger(); 2754 if (messenger == null) { 2755 throw new IllegalStateException( 2756 "getWifiServiceMessenger() returned null! This is invalid."); 2757 } 2758 2759 mAsyncChannel = new AsyncChannel(); 2760 mConnected = new CountDownLatch(1); 2761 2762 Handler handler = new ServiceHandler(mLooper); 2763 mAsyncChannel.connect(mContext, handler, messenger); 2764 try { 2765 mConnected.await(); 2766 } catch (InterruptedException e) { 2767 Log.e(TAG, "interrupted wait at init"); 2768 } 2769 } 2770 return mAsyncChannel; 2771 } 2772 2773 /** 2774 * Connect to a network with the given configuration. The network also 2775 * gets added to the list of configured networks for the foreground user. 2776 * 2777 * For a new network, this function is used instead of a 2778 * sequence of addNetwork(), enableNetwork(), saveConfiguration() and 2779 * reconnect() 2780 * 2781 * @param config the set of variables that describe the configuration, 2782 * contained in a {@link WifiConfiguration} object. 2783 * @param listener for callbacks on success or failure. Can be null. 2784 * @throws IllegalStateException if the WifiManager instance needs to be 2785 * initialized again 2786 * 2787 * @hide 2788 */ 2789 @SystemApi 2790 public void connect(WifiConfiguration config, ActionListener listener) { 2791 if (config == null) throw new IllegalArgumentException("config cannot be null"); 2792 // Use INVALID_NETWORK_ID for arg1 when passing a config object 2793 // arg1 is used to pass network id when the network already exists 2794 getChannel().sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID, 2795 putListener(listener), config); 2796 } 2797 2798 /** 2799 * Connect to a network with the given networkId. 2800 * 2801 * This function is used instead of a enableNetwork(), saveConfiguration() and 2802 * reconnect() 2803 * 2804 * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link 2805 * getConfiguredNetworks}. 2806 * @param listener for callbacks on success or failure. Can be null. 2807 * @throws IllegalStateException if the WifiManager instance needs to be 2808 * initialized again 2809 * @hide 2810 */ 2811 public void connect(int networkId, ActionListener listener) { 2812 if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative"); 2813 getChannel().sendMessage(CONNECT_NETWORK, networkId, putListener(listener)); 2814 } 2815 2816 /** 2817 * Save the given network to the list of configured networks for the 2818 * foreground user. If the network already exists, the configuration 2819 * is updated. Any new network is enabled by default. 2820 * 2821 * For a new network, this function is used instead of a 2822 * sequence of addNetwork(), enableNetwork() and saveConfiguration(). 2823 * 2824 * For an existing network, it accomplishes the task of updateNetwork() 2825 * and saveConfiguration() 2826 * 2827 * @param config the set of variables that describe the configuration, 2828 * contained in a {@link WifiConfiguration} object. 2829 * @param listener for callbacks on success or failure. Can be null. 2830 * @throws IllegalStateException if the WifiManager instance needs to be 2831 * initialized again 2832 * @hide 2833 */ 2834 public void save(WifiConfiguration config, ActionListener listener) { 2835 if (config == null) throw new IllegalArgumentException("config cannot be null"); 2836 getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config); 2837 } 2838 2839 /** 2840 * Delete the network from the list of configured networks for the 2841 * foreground user. 2842 * 2843 * This function is used instead of a sequence of removeNetwork() 2844 * and saveConfiguration(). 2845 * 2846 * @param config the set of variables that describe the configuration, 2847 * contained in a {@link WifiConfiguration} object. 2848 * @param listener for callbacks on success or failure. Can be null. 2849 * @throws IllegalStateException if the WifiManager instance needs to be 2850 * initialized again 2851 * @hide 2852 */ 2853 public void forget(int netId, ActionListener listener) { 2854 if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative"); 2855 getChannel().sendMessage(FORGET_NETWORK, netId, putListener(listener)); 2856 } 2857 2858 /** 2859 * Disable network 2860 * 2861 * @param netId is the network Id 2862 * @param listener for callbacks on success or failure. Can be null. 2863 * @throws IllegalStateException if the WifiManager instance needs to be 2864 * initialized again 2865 * @hide 2866 */ 2867 public void disable(int netId, ActionListener listener) { 2868 if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative"); 2869 getChannel().sendMessage(DISABLE_NETWORK, netId, putListener(listener)); 2870 } 2871 2872 /** 2873 * Disable ephemeral Network 2874 * 2875 * @param SSID, in the format of WifiConfiguration's SSID. 2876 * @hide 2877 */ 2878 public void disableEphemeralNetwork(String SSID) { 2879 if (SSID == null) throw new IllegalArgumentException("SSID cannot be null"); 2880 try { 2881 mService.disableEphemeralNetwork(SSID); 2882 } catch (RemoteException e) { 2883 throw e.rethrowFromSystemServer(); 2884 } 2885 } 2886 2887 /** 2888 * Start Wi-fi Protected Setup 2889 * 2890 * @param config WPS configuration (does not support {@link WpsInfo#LABEL}) 2891 * @param listener for callbacks on success or failure. Can be null. 2892 * @throws IllegalStateException if the WifiManager instance needs to be 2893 * initialized again 2894 */ 2895 public void startWps(WpsInfo config, WpsCallback listener) { 2896 if (config == null) throw new IllegalArgumentException("config cannot be null"); 2897 getChannel().sendMessage(START_WPS, 0, putListener(listener), config); 2898 } 2899 2900 /** 2901 * Cancel any ongoing Wi-fi Protected Setup 2902 * 2903 * @param listener for callbacks on success or failure. Can be null. 2904 * @throws IllegalStateException if the WifiManager instance needs to be 2905 * initialized again 2906 */ 2907 public void cancelWps(WpsCallback listener) { 2908 getChannel().sendMessage(CANCEL_WPS, 0, putListener(listener)); 2909 } 2910 2911 /** 2912 * Get a reference to WifiService handler. This is used by a client to establish 2913 * an AsyncChannel communication with WifiService 2914 * 2915 * @return Messenger pointing to the WifiService handler 2916 * @hide 2917 */ 2918 public Messenger getWifiServiceMessenger() { 2919 try { 2920 return mService.getWifiServiceMessenger(); 2921 } catch (RemoteException e) { 2922 throw e.rethrowFromSystemServer(); 2923 } 2924 } 2925 2926 2927 /** 2928 * Allows an application to keep the Wi-Fi radio awake. 2929 * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. 2930 * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple 2931 * applications may hold WifiLocks, and the radio will only be allowed to turn off when no 2932 * WifiLocks are held in any application. 2933 * <p> 2934 * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or 2935 * could function over a mobile network, if available. A program that needs to download large 2936 * files should hold a WifiLock to ensure that the download will complete, but a program whose 2937 * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely 2938 * affecting battery life. 2939 * <p> 2940 * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane 2941 * Mode. They simply keep the radio from turning off when Wi-Fi is already on but the device 2942 * is idle. 2943 * <p> 2944 * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK} 2945 * permission in an {@code <uses-permission>} element of the application's manifest. 2946 */ 2947 public class WifiLock { 2948 private String mTag; 2949 private final IBinder mBinder; 2950 private int mRefCount; 2951 int mLockType; 2952 private boolean mRefCounted; 2953 private boolean mHeld; 2954 private WorkSource mWorkSource; 2955 2956 private WifiLock(int lockType, String tag) { 2957 mTag = tag; 2958 mLockType = lockType; 2959 mBinder = new Binder(); 2960 mRefCount = 0; 2961 mRefCounted = true; 2962 mHeld = false; 2963 } 2964 2965 /** 2966 * Locks the Wi-Fi radio on until {@link #release} is called. 2967 * 2968 * If this WifiLock is reference-counted, each call to {@code acquire} will increment the 2969 * reference count, and the radio will remain locked as long as the reference count is 2970 * above zero. 2971 * 2972 * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock 2973 * the radio, but subsequent calls will be ignored. Only one call to {@link #release} 2974 * will be required, regardless of the number of times that {@code acquire} is called. 2975 */ 2976 public void acquire() { 2977 synchronized (mBinder) { 2978 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) { 2979 try { 2980 mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource); 2981 synchronized (WifiManager.this) { 2982 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 2983 mService.releaseWifiLock(mBinder); 2984 throw new UnsupportedOperationException( 2985 "Exceeded maximum number of wifi locks"); 2986 } 2987 mActiveLockCount++; 2988 } 2989 } catch (RemoteException e) { 2990 throw e.rethrowFromSystemServer(); 2991 } 2992 mHeld = true; 2993 } 2994 } 2995 } 2996 2997 /** 2998 * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle. 2999 * 3000 * If this WifiLock is reference-counted, each call to {@code release} will decrement the 3001 * reference count, and the radio will be unlocked only when the reference count reaches 3002 * zero. If the reference count goes below zero (that is, if {@code release} is called 3003 * a greater number of times than {@link #acquire}), an exception is thrown. 3004 * 3005 * If this WifiLock is not reference-counted, the first call to {@code release} (after 3006 * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent 3007 * calls will be ignored. 3008 */ 3009 public void release() { 3010 synchronized (mBinder) { 3011 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 3012 try { 3013 mService.releaseWifiLock(mBinder); 3014 synchronized (WifiManager.this) { 3015 mActiveLockCount--; 3016 } 3017 } catch (RemoteException e) { 3018 throw e.rethrowFromSystemServer(); 3019 } 3020 mHeld = false; 3021 } 3022 if (mRefCount < 0) { 3023 throw new RuntimeException("WifiLock under-locked " + mTag); 3024 } 3025 } 3026 } 3027 3028 /** 3029 * Controls whether this is a reference-counted or non-reference-counted WifiLock. 3030 * 3031 * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and 3032 * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire} 3033 * has been balanced with a call to {@link #release}. Non-reference-counted WifiLocks 3034 * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the 3035 * radio whenever {@link #release} is called and it is locked. 3036 * 3037 * @param refCounted true if this WifiLock should keep a reference count 3038 */ 3039 public void setReferenceCounted(boolean refCounted) { 3040 mRefCounted = refCounted; 3041 } 3042 3043 /** 3044 * Checks whether this WifiLock is currently held. 3045 * 3046 * @return true if this WifiLock is held, false otherwise 3047 */ 3048 public boolean isHeld() { 3049 synchronized (mBinder) { 3050 return mHeld; 3051 } 3052 } 3053 3054 public void setWorkSource(WorkSource ws) { 3055 synchronized (mBinder) { 3056 if (ws != null && ws.size() == 0) { 3057 ws = null; 3058 } 3059 boolean changed = true; 3060 if (ws == null) { 3061 mWorkSource = null; 3062 } else { 3063 ws.clearNames(); 3064 if (mWorkSource == null) { 3065 changed = mWorkSource != null; 3066 mWorkSource = new WorkSource(ws); 3067 } else { 3068 changed = mWorkSource.diff(ws); 3069 if (changed) { 3070 mWorkSource.set(ws); 3071 } 3072 } 3073 } 3074 if (changed && mHeld) { 3075 try { 3076 mService.updateWifiLockWorkSource(mBinder, mWorkSource); 3077 } catch (RemoteException e) { 3078 throw e.rethrowFromSystemServer(); 3079 } 3080 } 3081 } 3082 } 3083 3084 public String toString() { 3085 String s1, s2, s3; 3086 synchronized (mBinder) { 3087 s1 = Integer.toHexString(System.identityHashCode(this)); 3088 s2 = mHeld ? "held; " : ""; 3089 if (mRefCounted) { 3090 s3 = "refcounted: refcount = " + mRefCount; 3091 } else { 3092 s3 = "not refcounted"; 3093 } 3094 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }"; 3095 } 3096 } 3097 3098 @Override 3099 protected void finalize() throws Throwable { 3100 super.finalize(); 3101 synchronized (mBinder) { 3102 if (mHeld) { 3103 try { 3104 mService.releaseWifiLock(mBinder); 3105 synchronized (WifiManager.this) { 3106 mActiveLockCount--; 3107 } 3108 } catch (RemoteException e) { 3109 throw e.rethrowFromSystemServer(); 3110 } 3111 } 3112 } 3113 } 3114 } 3115 3116 /** 3117 * Creates a new WifiLock. 3118 * 3119 * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL}, 3120 * {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for 3121 * descriptions of the types of Wi-Fi locks. 3122 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 3123 * never shown to the user under normal conditions, but should be descriptive 3124 * enough to identify your application and the specific WifiLock within it, if it 3125 * holds multiple WifiLocks. 3126 * 3127 * @return a new, unacquired WifiLock with the given tag. 3128 * 3129 * @see WifiLock 3130 */ 3131 public WifiLock createWifiLock(int lockType, String tag) { 3132 return new WifiLock(lockType, tag); 3133 } 3134 3135 /** 3136 * Creates a new WifiLock. 3137 * 3138 * @param tag a tag for the WifiLock to identify it in debugging messages. This string is 3139 * never shown to the user under normal conditions, but should be descriptive 3140 * enough to identify your application and the specific WifiLock within it, if it 3141 * holds multiple WifiLocks. 3142 * 3143 * @return a new, unacquired WifiLock with the given tag. 3144 * 3145 * @see WifiLock 3146 */ 3147 public WifiLock createWifiLock(String tag) { 3148 return new WifiLock(WIFI_MODE_FULL, tag); 3149 } 3150 3151 3152 /** 3153 * Create a new MulticastLock 3154 * 3155 * @param tag a tag for the MulticastLock to identify it in debugging 3156 * messages. This string is never shown to the user under 3157 * normal conditions, but should be descriptive enough to 3158 * identify your application and the specific MulticastLock 3159 * within it, if it holds multiple MulticastLocks. 3160 * 3161 * @return a new, unacquired MulticastLock with the given tag. 3162 * 3163 * @see MulticastLock 3164 */ 3165 public MulticastLock createMulticastLock(String tag) { 3166 return new MulticastLock(tag); 3167 } 3168 3169 /** 3170 * Allows an application to receive Wifi Multicast packets. 3171 * Normally the Wifi stack filters out packets not explicitly 3172 * addressed to this device. Acquring a MulticastLock will 3173 * cause the stack to receive packets addressed to multicast 3174 * addresses. Processing these extra packets can cause a noticable 3175 * battery drain and should be disabled when not needed. 3176 */ 3177 public class MulticastLock { 3178 private String mTag; 3179 private final IBinder mBinder; 3180 private int mRefCount; 3181 private boolean mRefCounted; 3182 private boolean mHeld; 3183 3184 private MulticastLock(String tag) { 3185 mTag = tag; 3186 mBinder = new Binder(); 3187 mRefCount = 0; 3188 mRefCounted = true; 3189 mHeld = false; 3190 } 3191 3192 /** 3193 * Locks Wifi Multicast on until {@link #release} is called. 3194 * 3195 * If this MulticastLock is reference-counted each call to 3196 * {@code acquire} will increment the reference count, and the 3197 * wifi interface will receive multicast packets as long as the 3198 * reference count is above zero. 3199 * 3200 * If this MulticastLock is not reference-counted, the first call to 3201 * {@code acquire} will turn on the multicast packets, but subsequent 3202 * calls will be ignored. Only one call to {@link #release} will 3203 * be required, regardless of the number of times that {@code acquire} 3204 * is called. 3205 * 3206 * Note that other applications may also lock Wifi Multicast on. 3207 * Only they can relinquish their lock. 3208 * 3209 * Also note that applications cannot leave Multicast locked on. 3210 * When an app exits or crashes, any Multicast locks will be released. 3211 */ 3212 public void acquire() { 3213 synchronized (mBinder) { 3214 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) { 3215 try { 3216 mService.acquireMulticastLock(mBinder, mTag); 3217 synchronized (WifiManager.this) { 3218 if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { 3219 mService.releaseMulticastLock(); 3220 throw new UnsupportedOperationException( 3221 "Exceeded maximum number of wifi locks"); 3222 } 3223 mActiveLockCount++; 3224 } 3225 } catch (RemoteException e) { 3226 throw e.rethrowFromSystemServer(); 3227 } 3228 mHeld = true; 3229 } 3230 } 3231 } 3232 3233 /** 3234 * Unlocks Wifi Multicast, restoring the filter of packets 3235 * not addressed specifically to this device and saving power. 3236 * 3237 * If this MulticastLock is reference-counted, each call to 3238 * {@code release} will decrement the reference count, and the 3239 * multicast packets will only stop being received when the reference 3240 * count reaches zero. If the reference count goes below zero (that 3241 * is, if {@code release} is called a greater number of times than 3242 * {@link #acquire}), an exception is thrown. 3243 * 3244 * If this MulticastLock is not reference-counted, the first call to 3245 * {@code release} (after the radio was multicast locked using 3246 * {@link #acquire}) will unlock the multicast, and subsequent calls 3247 * will be ignored. 3248 * 3249 * Note that if any other Wifi Multicast Locks are still outstanding 3250 * this {@code release} call will not have an immediate effect. Only 3251 * when all applications have released all their Multicast Locks will 3252 * the Multicast filter be turned back on. 3253 * 3254 * Also note that when an app exits or crashes all of its Multicast 3255 * Locks will be automatically released. 3256 */ 3257 public void release() { 3258 synchronized (mBinder) { 3259 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { 3260 try { 3261 mService.releaseMulticastLock(); 3262 synchronized (WifiManager.this) { 3263 mActiveLockCount--; 3264 } 3265 } catch (RemoteException e) { 3266 throw e.rethrowFromSystemServer(); 3267 } 3268 mHeld = false; 3269 } 3270 if (mRefCount < 0) { 3271 throw new RuntimeException("MulticastLock under-locked " 3272 + mTag); 3273 } 3274 } 3275 } 3276 3277 /** 3278 * Controls whether this is a reference-counted or non-reference- 3279 * counted MulticastLock. 3280 * 3281 * Reference-counted MulticastLocks keep track of the number of calls 3282 * to {@link #acquire} and {@link #release}, and only stop the 3283 * reception of multicast packets when every call to {@link #acquire} 3284 * has been balanced with a call to {@link #release}. Non-reference- 3285 * counted MulticastLocks allow the reception of multicast packets 3286 * whenever {@link #acquire} is called and stop accepting multicast 3287 * packets whenever {@link #release} is called. 3288 * 3289 * @param refCounted true if this MulticastLock should keep a reference 3290 * count 3291 */ 3292 public void setReferenceCounted(boolean refCounted) { 3293 mRefCounted = refCounted; 3294 } 3295 3296 /** 3297 * Checks whether this MulticastLock is currently held. 3298 * 3299 * @return true if this MulticastLock is held, false otherwise 3300 */ 3301 public boolean isHeld() { 3302 synchronized (mBinder) { 3303 return mHeld; 3304 } 3305 } 3306 3307 public String toString() { 3308 String s1, s2, s3; 3309 synchronized (mBinder) { 3310 s1 = Integer.toHexString(System.identityHashCode(this)); 3311 s2 = mHeld ? "held; " : ""; 3312 if (mRefCounted) { 3313 s3 = "refcounted: refcount = " + mRefCount; 3314 } else { 3315 s3 = "not refcounted"; 3316 } 3317 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }"; 3318 } 3319 } 3320 3321 @Override 3322 protected void finalize() throws Throwable { 3323 super.finalize(); 3324 setReferenceCounted(false); 3325 release(); 3326 } 3327 } 3328 3329 /** 3330 * Check multicast filter status. 3331 * 3332 * @return true if multicast packets are allowed. 3333 * 3334 * @hide pending API council approval 3335 */ 3336 public boolean isMulticastEnabled() { 3337 try { 3338 return mService.isMulticastEnabled(); 3339 } catch (RemoteException e) { 3340 throw e.rethrowFromSystemServer(); 3341 } 3342 } 3343 3344 /** 3345 * Initialize the multicast filtering to 'on' 3346 * @hide no intent to publish 3347 */ 3348 public boolean initializeMulticastFiltering() { 3349 try { 3350 mService.initializeMulticastFiltering(); 3351 return true; 3352 } catch (RemoteException e) { 3353 throw e.rethrowFromSystemServer(); 3354 } 3355 } 3356 3357 protected void finalize() throws Throwable { 3358 try { 3359 if (mAsyncChannel != null) { 3360 mAsyncChannel.disconnect(); 3361 } 3362 } finally { 3363 super.finalize(); 3364 } 3365 } 3366 3367 /** 3368 * Set wifi verbose log. Called from developer settings. 3369 * @hide 3370 */ 3371 public void enableVerboseLogging (int verbose) { 3372 try { 3373 mService.enableVerboseLogging(verbose); 3374 } catch (Exception e) { 3375 //ignore any failure here 3376 Log.e(TAG, "enableVerboseLogging " + e.toString()); 3377 } 3378 } 3379 3380 /** 3381 * Get the WiFi verbose logging level.This is used by settings 3382 * to decide what to show within the picker. 3383 * @hide 3384 */ 3385 public int getVerboseLoggingLevel() { 3386 try { 3387 return mService.getVerboseLoggingLevel(); 3388 } catch (RemoteException e) { 3389 throw e.rethrowFromSystemServer(); 3390 } 3391 } 3392 3393 /** 3394 * Set wifi Aggressive Handover. Called from developer settings. 3395 * @hide 3396 */ 3397 public void enableAggressiveHandover(int enabled) { 3398 try { 3399 mService.enableAggressiveHandover(enabled); 3400 } catch (RemoteException e) { 3401 throw e.rethrowFromSystemServer(); 3402 } 3403 } 3404 3405 /** 3406 * Get the WiFi Handover aggressiveness.This is used by settings 3407 * to decide what to show within the picker. 3408 * @hide 3409 */ 3410 public int getAggressiveHandover() { 3411 try { 3412 return mService.getAggressiveHandover(); 3413 } catch (RemoteException e) { 3414 throw e.rethrowFromSystemServer(); 3415 } 3416 } 3417 3418 /** 3419 * Set setting for allowing Scans when traffic is ongoing. 3420 * @hide 3421 */ 3422 public void setAllowScansWithTraffic(int enabled) { 3423 try { 3424 mService.setAllowScansWithTraffic(enabled); 3425 } catch (RemoteException e) { 3426 throw e.rethrowFromSystemServer(); 3427 } 3428 } 3429 3430 /** 3431 * Get setting for allowing Scans when traffic is ongoing. 3432 * @hide 3433 */ 3434 public int getAllowScansWithTraffic() { 3435 try { 3436 return mService.getAllowScansWithTraffic(); 3437 } catch (RemoteException e) { 3438 throw e.rethrowFromSystemServer(); 3439 } 3440 } 3441 3442 /** 3443 * Resets all wifi manager settings back to factory defaults. 3444 * 3445 * @hide 3446 */ 3447 public void factoryReset() { 3448 try { 3449 mService.factoryReset(); 3450 } catch (RemoteException e) { 3451 throw e.rethrowFromSystemServer(); 3452 } 3453 } 3454 3455 /** 3456 * Get Network object of current wifi network 3457 * @return Get Network object of current wifi network 3458 * @hide 3459 */ 3460 public Network getCurrentNetwork() { 3461 try { 3462 return mService.getCurrentNetwork(); 3463 } catch (RemoteException e) { 3464 throw e.rethrowFromSystemServer(); 3465 } 3466 } 3467 3468 /** 3469 * Framework layer autojoin enable/disable when device is associated 3470 * this will enable/disable autojoin scan and switch network when connected 3471 * @return true -- if set successful false -- if set failed 3472 * @hide 3473 */ 3474 public boolean setEnableAutoJoinWhenAssociated(boolean enabled) { 3475 try { 3476 return mService.setEnableAutoJoinWhenAssociated(enabled); 3477 } catch (RemoteException e) { 3478 throw e.rethrowFromSystemServer(); 3479 } 3480 } 3481 3482 /** 3483 * Get setting for Framework layer autojoin enable status 3484 * @hide 3485 */ 3486 public boolean getEnableAutoJoinWhenAssociated() { 3487 try { 3488 return mService.getEnableAutoJoinWhenAssociated(); 3489 } catch (RemoteException e) { 3490 throw e.rethrowFromSystemServer(); 3491 } 3492 } 3493 3494 /** 3495 * Enable/disable WifiConnectivityManager 3496 * @hide 3497 */ 3498 public void enableWifiConnectivityManager(boolean enabled) { 3499 try { 3500 mService.enableWifiConnectivityManager(enabled); 3501 } catch (RemoteException e) { 3502 throw e.rethrowFromSystemServer(); 3503 } 3504 } 3505 3506 /** 3507 * Retrieve the data to be backed to save the current state. 3508 * @hide 3509 */ 3510 public byte[] retrieveBackupData() { 3511 try { 3512 return mService.retrieveBackupData(); 3513 } catch (RemoteException e) { 3514 throw e.rethrowFromSystemServer(); 3515 } 3516 } 3517 3518 /** 3519 * Restore state from the backed up data. 3520 * @hide 3521 */ 3522 public void restoreBackupData(byte[] data) { 3523 try { 3524 mService.restoreBackupData(data); 3525 } catch (RemoteException e) { 3526 throw e.rethrowFromSystemServer(); 3527 } 3528 } 3529 3530 /** 3531 * Restore state from the older version of back up data. 3532 * The old backup data was essentially a backup of wpa_supplicant.conf 3533 * and ipconfig.txt file. 3534 * @hide 3535 */ 3536 public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) { 3537 try { 3538 mService.restoreSupplicantBackupData(supplicantData, ipConfigData); 3539 } catch (RemoteException e) { 3540 throw e.rethrowFromSystemServer(); 3541 } 3542 } 3543 } 3544