summaryrefslogtreecommitdiff
path: root/wifi
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2020-08-31 21:21:38 -0700
committerXin Li <delphij@google.com>2020-08-31 21:21:38 -0700
commit628590d7ec80e10a3fc24b1c18a1afb55cca10a8 (patch)
tree4b1c3f52d86d7fb53afbe9e9438468588fa489f8 /wifi
parentb11b8ec3aec8bb42f2c07e1c5ac7942da293baa8 (diff)
parentd2d3a20624d968199353ccf6ddbae6f3ac39c9af (diff)
Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)
Bug: 166295507 Merged-In: I3d92a6de21a938f6b352ec26dc23420c0fe02b27 Change-Id: Ifdb80563ef042738778ebb8a7581a97c4e3d96e2
Diffstat (limited to 'wifi')
-rw-r--r--wifi/Android.bp172
-rw-r--r--wifi/aidl-export/android/net/wifi/SoftApCapability.aidl (renamed from wifi/java/android/net/wifi/WifiActivityEnergyInfo.aidl)4
-rw-r--r--wifi/aidl-export/android/net/wifi/SoftApConfiguration.aidl (renamed from wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.aidl)6
-rw-r--r--wifi/aidl-export/android/net/wifi/SoftApInfo.aidl (renamed from wifi/java/android/net/wifi/WpsResult.aidl)5
-rw-r--r--wifi/api/current.txt1199
-rw-r--r--wifi/api/lint-baseline.txt13
-rw-r--r--wifi/api/module-lib-current.txt1
-rw-r--r--wifi/api/module-lib-removed.txt1
-rw-r--r--wifi/api/removed.txt1
-rw-r--r--wifi/api/system-current.txt939
-rw-r--r--wifi/api/system-lint-baseline.txt6
-rw-r--r--wifi/api/system-removed.txt16
-rw-r--r--wifi/jarjar-rules.txt126
-rw-r--r--wifi/java/android/net/wifi/EasyConnectStatusCallback.java134
-rw-r--r--wifi/java/android/net/wifi/IActionListener.aidl27
-rw-r--r--wifi/java/android/net/wifi/IDppCallback.aidl2
-rw-r--r--wifi/java/android/net/wifi/ILocalOnlyHotspotCallback.aidl (renamed from wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl)17
-rw-r--r--wifi/java/android/net/wifi/IOnWifiActivityEnergyInfoListener.aidl33
-rw-r--r--wifi/java/android/net/wifi/IScanResultsCallback.aidl27
-rw-r--r--wifi/java/android/net/wifi/IScanResultsListener.aidl (renamed from wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl)13
-rw-r--r--wifi/java/android/net/wifi/IScoreUpdateObserver.aidl29
-rw-r--r--wifi/java/android/net/wifi/ISoftApCallback.aidl25
-rw-r--r--wifi/java/android/net/wifi/ISuggestionConnectionStatusListener.aidl29
-rw-r--r--wifi/java/android/net/wifi/ITxPacketCountListener.aidl28
-rw-r--r--wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl33
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl112
-rw-r--r--wifi/java/android/net/wifi/IWifiScanner.aidl2
-rw-r--r--wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java81
-rw-r--r--wifi/java/android/net/wifi/RssiPacketCountInfo.java75
-rw-r--r--wifi/java/android/net/wifi/RttManager.java2
-rw-r--r--wifi/java/android/net/wifi/ScanResult.java407
-rw-r--r--wifi/java/android/net/wifi/SoftApCapability.java186
-rwxr-xr-xwifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java284
-rw-r--r--wifi/java/android/net/wifi/SoftApConfiguration.java972
-rw-r--r--wifi/java/android/net/wifi/SoftApInfo.java194
-rw-r--r--wifi/java/android/net/wifi/SynchronousExecutor.java29
-rw-r--r--wifi/java/android/net/wifi/WifiActivityEnergyInfo.java205
-rw-r--r--wifi/java/android/net/wifi/WifiAnnotations.java124
-rw-r--r--wifi/java/android/net/wifi/WifiClient.java4
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java1338
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java304
-rw-r--r--wifi/java/android/net/wifi/WifiFrameworkInitializer.java121
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java354
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java2647
-rwxr-xr-xwifi/java/android/net/wifi/WifiMigration.java558
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java53
-rwxr-xr-xwifi/java/android/net/wifi/WifiNetworkScoreCache.java23
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSpecifier.java68
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java517
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java586
-rw-r--r--wifi/java/android/net/wifi/WifiSsid.java60
-rw-r--r--wifi/java/android/net/wifi/WpsResult.java90
-rw-r--r--wifi/java/android/net/wifi/aware/Characteristics.java37
-rw-r--r--wifi/java/android/net/wifi/aware/ConfigRequest.java74
-rw-r--r--wifi/java/android/net/wifi/aware/DiscoverySession.java7
-rw-r--r--wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl13
-rw-r--r--wifi/java/android/net/wifi/aware/PublishConfig.java3
-rw-r--r--wifi/java/android/net/wifi/aware/SubscribeConfig.java3
-rw-r--r--wifi/java/android/net/wifi/aware/TlvBufferUtils.java66
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java7
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareManager.java32
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java2
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java39
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareSession.java7
-rw-r--r--wifi/java/android/net/wifi/hotspot2/ConfigParser.java6
-rw-r--r--wifi/java/android/net/wifi/hotspot2/OsuProvider.java43
-rw-r--r--wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java255
-rw-r--r--wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java153
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/Credential.java50
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java22
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl19
-rw-r--r--wifi/java/android/net/wifi/migration_samples/README.txt35
-rw-r--r--wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStore.xml200
-rw-r--r--wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStoreSoftAp.xml22
-rw-r--r--wifi/java/android/net/wifi/migration_samples/User_WifiConfigStore.xml81
-rw-r--r--wifi/java/android/net/wifi/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml155
-rw-r--r--wifi/java/android/net/wifi/nl80211/ChannelSettings.java95
-rw-r--r--wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java283
-rw-r--r--wifi/java/android/net/wifi/nl80211/HiddenNetwork.java87
-rw-r--r--wifi/java/android/net/wifi/nl80211/NativeScanResult.java310
-rw-r--r--wifi/java/android/net/wifi/nl80211/NativeWifiClient.java103
-rw-r--r--wifi/java/android/net/wifi/nl80211/PnoNetwork.java171
-rw-r--r--wifi/java/android/net/wifi/nl80211/PnoSettings.java209
-rw-r--r--wifi/java/android/net/wifi/nl80211/RadioChainInfo.java125
-rw-r--r--wifi/java/android/net/wifi/nl80211/SingleScanSettings.java118
-rw-r--r--wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java1287
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pConfig.java87
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pDevice.java21
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pGroup.java46
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl19
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java25
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pManager.java197
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java197
-rw-r--r--wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl4
-rw-r--r--wifi/java/android/net/wifi/rtt/ResponderConfig.java17
-rw-r--r--wifi/java/android/net/wifi/rtt/ResponderLocation.java4
-rw-r--r--wifi/java/android/net/wifi/rtt/WifiRttManager.java6
-rw-r--r--wifi/java/android/net/wifi/util/HexEncoding.java183
-rw-r--r--wifi/java/com/android/server/wifi/BaseWifiService.java484
-rw-r--r--wifi/tests/Android.bp50
-rw-r--r--wifi/tests/Android.mk64
-rw-r--r--wifi/tests/AndroidTest.xml8
-rw-r--r--wifi/tests/README.md21
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64142
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf62
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64171
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64171
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64171
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithUpdateIdentifier.base6488
-rw-r--r--wifi/tests/assets/hsr1/README.txt3
-rw-r--r--wifi/tests/assets/pps/PerProviderSubscription.xml24
-rwxr-xr-xwifi/tests/runtests.sh26
-rw-r--r--wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java84
-rw-r--r--wifi/tests/src/android/net/wifi/ScanResultTest.java134
-rw-r--r--wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java73
-rw-r--r--wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java199
-rw-r--r--wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java334
-rw-r--r--wifi/tests/src/android/net/wifi/SoftApInfoTest.java71
-rw-r--r--wifi/tests/src/android/net/wifi/WifiConfigurationTest.java295
-rw-r--r--wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java87
-rw-r--r--wifi/tests/src/android/net/wifi/WifiInfoTest.java79
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java1137
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java87
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java85
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java520
-rw-r--r--wifi/tests/src/android/net/wifi/WifiScannerTest.java260
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java2
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java77
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java33
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java13
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java293
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java172
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java3
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java163
-rw-r--r--wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java88
-rw-r--r--wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java87
-rw-r--r--wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java112
-rw-r--r--wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java116
-rw-r--r--wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java1265
-rw-r--r--wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java2
-rw-r--r--wifi/tests/src/android/net/wifi/p2p/WifiP2pWfdInfoTest.java22
-rw-r--r--wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java25
-rw-r--r--wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java10
-rw-r--r--wifi/tests/src/android/net/wifi/util/HexEncodingTest.java130
144 files changed, 20366 insertions, 4384 deletions
diff --git a/wifi/Android.bp b/wifi/Android.bp
new file mode 100644
index 000000000000..941ff61b3ba5
--- /dev/null
+++ b/wifi/Android.bp
@@ -0,0 +1,172 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_defaults {
+ name: "wifi-module-sdk-version-defaults",
+ min_sdk_version: "30",
+ target_sdk_version: "30",
+}
+
+filegroup {
+ name: "framework-wifi-updatable-exported-aidl-sources",
+ srcs: ["aidl-export/**/*.aidl"],
+ path: "aidl-export",
+ visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "framework-wifi-updatable-java-sources",
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.aidl",
+ ],
+ exclude_srcs: [
+ ":framework-wifi-non-updatable-sources"
+ ],
+ path: "java",
+ visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "framework-wifi-updatable-sources",
+ srcs: [
+ ":framework-wifi-updatable-java-sources",
+ ":framework-wifi-updatable-exported-aidl-sources",
+ ],
+}
+
+filegroup {
+ name: "framework-wifi-non-updatable-sources",
+ srcs: [
+ // TODO(b/146011398) package android.net.wifi is now split amongst 2 jars: framework.jar and
+ // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
+ // to a separate package.
+ "java/android/net/wifi/SoftApConfToXmlMigrationUtil.java",
+ "java/android/net/wifi/WifiNetworkScoreCache.java",
+ "java/android/net/wifi/WifiMigration.java",
+ "java/android/net/wifi/nl80211/*.java",
+ ":libwificond_ipc_aidl",
+ ],
+}
+
+filegroup {
+ name: "framework-wifi-annotations",
+ srcs: ["java/android/net/wifi/WifiAnnotations.java"],
+}
+
+// list of tests that are allowed to access @hide APIs from framework-wifi
+test_access_hidden_api_whitelist = [
+ "//frameworks/base/wifi/tests",
+ "//frameworks/opt/net/wifi/tests/wifitests:__subpackages__",
+
+ "//external/robolectric-shadows:__subpackages__",
+ "//frameworks/base/packages/SettingsLib/tests/integ",
+ "//external/sl4a:__subpackages__",
+]
+
+// wifi-service needs pre-jarjared version of framework-wifi so it can reference copied utility
+// classes before they are renamed.
+java_library {
+ name: "framework-wifi-pre-jarjar",
+ defaults: ["wifi-module-sdk-version-defaults"],
+ sdk_version: "module_current",
+ static_libs: [
+ "framework-wifi-util-lib",
+ "android.hardware.wifi-V1.0-java-constants",
+ ],
+ libs: [
+ "framework-annotations-lib",
+ "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
+ ],
+ srcs: [
+ ":framework-wifi-updatable-sources",
+ ":framework-wifi-util-lib-aidls",
+ ],
+ // java_api_finder must accompany `srcs`
+ plugins: ["java_api_finder"],
+ installable: false,
+ visibility: [
+ "//frameworks/opt/net/wifi/service",
+ "//frameworks/opt/net/wifi/tests/wifitests",
+ ],
+}
+
+// post-jarjar version of framework-wifi
+java_sdk_library {
+ name: "framework-wifi",
+ defaults: [
+ "framework-module-defaults",
+ "wifi-module-sdk-version-defaults",
+ ],
+ static_libs: [
+ "framework-wifi-util-lib",
+ "android.hardware.wifi-V1.0-java-constants",
+ ],
+ libs: [
+ "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
+ ],
+ srcs: [
+ ":framework-wifi-updatable-sources",
+ ":framework-wifi-util-lib-aidls",
+ ],
+
+ jarjar_rules: ":wifi-jarjar-rules",
+
+ installable: true,
+ optimize: {
+ enabled: false
+ },
+ hostdex: true, // for hiddenapi check
+
+ // Allow access to the stubs from anywhere.
+ visibility: ["//visibility:public"],
+
+ // Restrict access to implementation library.
+ impl_library_visibility: [
+ "//visibility:override", // Ignore the visibility property.
+ "//frameworks/opt/net/wifi/service:__subpackages__",
+ ] + test_access_hidden_api_whitelist,
+
+ apex_available: [
+ "com.android.wifi",
+ "test_com.android.wifi",
+ ],
+ permitted_packages: [
+ "android.hardware.wifi",
+ "android.net.wifi",
+ // Created by jarjar rules.
+ "com.android.wifi.x",
+ ],
+}
+
+// defaults for tests that need to build against framework-wifi's @hide APIs
+java_defaults {
+ name: "framework-wifi-test-defaults",
+ sdk_version: "core_platform", // tests can use @CorePlatformApi's
+ libs: [
+ // order matters: classes in framework-wifi are resolved before framework, meaning
+ // @hide APIs in framework-wifi are resolved before @SystemApi stubs in framework
+ "framework-wifi.impl",
+ "framework",
+
+ // if sdk_version="" this gets automatically included, but here we need to add manually.
+ "framework-res",
+ ],
+ visibility: test_access_hidden_api_whitelist,
+}
+
+filegroup {
+ name: "wifi-jarjar-rules",
+ srcs: ["jarjar-rules.txt"],
+}
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.aidl b/wifi/aidl-export/android/net/wifi/SoftApCapability.aidl
index 007ec94378fd..bf30709f15d1 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.aidl
+++ b/wifi/aidl-export/android/net/wifi/SoftApCapability.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2014, The Android Open Source Project
+ * Copyright (c) 2019, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,4 +16,4 @@
package android.net.wifi;
-parcelable WifiActivityEnergyInfo;
+parcelable SoftApCapability;
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.aidl b/wifi/aidl-export/android/net/wifi/SoftApConfiguration.aidl
index c81d1f98422d..1d06f458318f 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.aidl
+++ b/wifi/aidl-export/android/net/wifi/SoftApConfiguration.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.net.wifi.p2p.servicediscovery;
+package android.net.wifi;
-parcelable WifiP2pServiceResponse;
+parcelable SoftApConfiguration; \ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WpsResult.aidl b/wifi/aidl-export/android/net/wifi/SoftApInfo.aidl
index eb4c4f5539ba..d4551cfac044 100644
--- a/wifi/java/android/net/wifi/WpsResult.aidl
+++ b/wifi/aidl-export/android/net/wifi/SoftApInfo.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2010, The Android Open Source Project
+ * Copyright (c) 2019, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,4 +16,5 @@
package android.net.wifi;
-parcelable WpsResult;
+parcelable SoftApInfo;
+
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
new file mode 100644
index 000000000000..53c3b33d9845
--- /dev/null
+++ b/wifi/api/current.txt
@@ -0,0 +1,1199 @@
+// Signature format: 2.0
+package android.net.wifi {
+
+ public abstract class EasyConnectStatusCallback {
+ field public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
+ field public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
+ field public static final int EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK = -10; // 0xfffffff6
+ field public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
+ field public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION = -11; // 0xfffffff5
+ field public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION = -12; // 0xfffffff4
+ field public static final int EASY_CONNECT_EVENT_FAILURE_GENERIC = -7; // 0xfffffff9
+ field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
+ field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
+ field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
+ field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
+ field public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+ }
+
+ public final class ScanResult implements android.os.Parcelable {
+ ctor public ScanResult(@NonNull android.net.wifi.ScanResult);
+ ctor public ScanResult();
+ method public int describeContents();
+ method @NonNull public java.util.List<android.net.wifi.ScanResult.InformationElement> getInformationElements();
+ method public int getWifiStandard();
+ method public boolean is80211mcResponder();
+ method public boolean isPasspointNetwork();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public String BSSID;
+ field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
+ field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0
+ field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
+ field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
+ field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.ScanResult> CREATOR;
+ field public String SSID;
+ field public static final int WIFI_STANDARD_11AC = 5; // 0x5
+ field public static final int WIFI_STANDARD_11AX = 6; // 0x6
+ field public static final int WIFI_STANDARD_11N = 4; // 0x4
+ field public static final int WIFI_STANDARD_LEGACY = 1; // 0x1
+ field public static final int WIFI_STANDARD_UNKNOWN = 0; // 0x0
+ field public String capabilities;
+ field public int centerFreq0;
+ field public int centerFreq1;
+ field public int channelWidth;
+ field public int frequency;
+ field public int level;
+ field public CharSequence operatorFriendlyName;
+ field public long timestamp;
+ field public CharSequence venueName;
+ }
+
+ public static class ScanResult.InformationElement {
+ ctor public ScanResult.InformationElement(@NonNull android.net.wifi.ScanResult.InformationElement);
+ method @NonNull public java.nio.ByteBuffer getBytes();
+ method public int getId();
+ method public int getIdExt();
+ }
+
+ public final class SoftApConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.net.MacAddress getBssid();
+ method @Nullable public String getPassphrase();
+ method public int getSecurityType();
+ method @Nullable public String getSsid();
+ method public boolean isHiddenSsid();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApConfiguration> CREATOR;
+ field public static final int SECURITY_TYPE_OPEN = 0; // 0x0
+ field public static final int SECURITY_TYPE_WPA2_PSK = 1; // 0x1
+ field public static final int SECURITY_TYPE_WPA3_SAE = 3; // 0x3
+ field public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2; // 0x2
+ }
+
+ public enum SupplicantState implements android.os.Parcelable {
+ method public int describeContents();
+ method public static boolean isValidState(android.net.wifi.SupplicantState);
+ method public void writeToParcel(android.os.Parcel, int);
+ enum_constant public static final android.net.wifi.SupplicantState ASSOCIATED;
+ enum_constant public static final android.net.wifi.SupplicantState ASSOCIATING;
+ enum_constant public static final android.net.wifi.SupplicantState AUTHENTICATING;
+ enum_constant public static final android.net.wifi.SupplicantState COMPLETED;
+ enum_constant public static final android.net.wifi.SupplicantState DISCONNECTED;
+ enum_constant public static final android.net.wifi.SupplicantState DORMANT;
+ enum_constant public static final android.net.wifi.SupplicantState FOUR_WAY_HANDSHAKE;
+ enum_constant public static final android.net.wifi.SupplicantState GROUP_HANDSHAKE;
+ enum_constant public static final android.net.wifi.SupplicantState INACTIVE;
+ enum_constant public static final android.net.wifi.SupplicantState INTERFACE_DISABLED;
+ enum_constant public static final android.net.wifi.SupplicantState INVALID;
+ enum_constant public static final android.net.wifi.SupplicantState SCANNING;
+ enum_constant public static final android.net.wifi.SupplicantState UNINITIALIZED;
+ }
+
+ @Deprecated public class WifiConfiguration implements android.os.Parcelable {
+ ctor @Deprecated public WifiConfiguration();
+ ctor @Deprecated public WifiConfiguration(@NonNull android.net.wifi.WifiConfiguration);
+ method public int describeContents();
+ method @Deprecated public android.net.ProxyInfo getHttpProxy();
+ method @Deprecated @NonNull public String getKey();
+ method @Deprecated @NonNull public android.net.MacAddress getRandomizedMacAddress();
+ method @Deprecated public boolean isPasspoint();
+ method @Deprecated public void setHttpProxy(android.net.ProxyInfo);
+ method @Deprecated public void setSecurityParams(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated public String BSSID;
+ field @Deprecated public String FQDN;
+ field @Deprecated public static final int SECURITY_TYPE_EAP = 3; // 0x3
+ field @Deprecated public static final int SECURITY_TYPE_EAP_SUITE_B = 5; // 0x5
+ field @Deprecated public static final int SECURITY_TYPE_OPEN = 0; // 0x0
+ field @Deprecated public static final int SECURITY_TYPE_OWE = 6; // 0x6
+ field @Deprecated public static final int SECURITY_TYPE_PSK = 2; // 0x2
+ field @Deprecated public static final int SECURITY_TYPE_SAE = 4; // 0x4
+ field @Deprecated public static final int SECURITY_TYPE_WAPI_CERT = 8; // 0x8
+ field @Deprecated public static final int SECURITY_TYPE_WAPI_PSK = 7; // 0x7
+ field @Deprecated public static final int SECURITY_TYPE_WEP = 1; // 0x1
+ field @Deprecated public String SSID;
+ field @Deprecated @NonNull public java.util.BitSet allowedAuthAlgorithms;
+ field @Deprecated @NonNull public java.util.BitSet allowedGroupCiphers;
+ field @Deprecated @NonNull public java.util.BitSet allowedGroupManagementCiphers;
+ field @Deprecated @NonNull public java.util.BitSet allowedKeyManagement;
+ field @Deprecated @NonNull public java.util.BitSet allowedPairwiseCiphers;
+ field @Deprecated @NonNull public java.util.BitSet allowedProtocols;
+ field @Deprecated @NonNull public java.util.BitSet allowedSuiteBCiphers;
+ field @Deprecated public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
+ field @Deprecated public boolean hiddenSSID;
+ field @Deprecated public boolean isHomeProviderNetwork;
+ field @Deprecated public int networkId;
+ field @Deprecated public String preSharedKey;
+ field @Deprecated public int priority;
+ field @Deprecated public String providerFriendlyName;
+ field @Deprecated public long[] roamingConsortiumIds;
+ field @Deprecated public int status;
+ field @Deprecated public String[] wepKeys;
+ field @Deprecated public int wepTxKeyIndex;
+ }
+
+ @Deprecated public static class WifiConfiguration.AuthAlgorithm {
+ field @Deprecated public static final int LEAP = 2; // 0x2
+ field @Deprecated public static final int OPEN = 0; // 0x0
+ field @Deprecated public static final int SAE = 3; // 0x3
+ field @Deprecated public static final int SHARED = 1; // 0x1
+ field @Deprecated public static final String[] strings;
+ field @Deprecated public static final String varName = "auth_alg";
+ }
+
+ @Deprecated public static class WifiConfiguration.GroupCipher {
+ field @Deprecated public static final int CCMP = 3; // 0x3
+ field @Deprecated public static final int GCMP_256 = 5; // 0x5
+ field @Deprecated public static final int SMS4 = 6; // 0x6
+ field @Deprecated public static final int TKIP = 2; // 0x2
+ field @Deprecated public static final int WEP104 = 1; // 0x1
+ field @Deprecated public static final int WEP40 = 0; // 0x0
+ field @Deprecated public static final String[] strings;
+ field @Deprecated public static final String varName = "group";
+ }
+
+ @Deprecated public static class WifiConfiguration.GroupMgmtCipher {
+ field @Deprecated public static final int BIP_CMAC_256 = 0; // 0x0
+ field @Deprecated public static final int BIP_GMAC_128 = 1; // 0x1
+ field @Deprecated public static final int BIP_GMAC_256 = 2; // 0x2
+ }
+
+ @Deprecated public static class WifiConfiguration.KeyMgmt {
+ field @Deprecated public static final int IEEE8021X = 3; // 0x3
+ field @Deprecated public static final int NONE = 0; // 0x0
+ field @Deprecated public static final int OWE = 9; // 0x9
+ field @Deprecated public static final int SAE = 8; // 0x8
+ field @Deprecated public static final int SUITE_B_192 = 10; // 0xa
+ field @Deprecated public static final int WPA_EAP = 2; // 0x2
+ field @Deprecated public static final int WPA_PSK = 1; // 0x1
+ field @Deprecated public static final String[] strings;
+ field @Deprecated public static final String varName = "key_mgmt";
+ }
+
+ @Deprecated public static class WifiConfiguration.PairwiseCipher {
+ field @Deprecated public static final int CCMP = 2; // 0x2
+ field @Deprecated public static final int GCMP_256 = 3; // 0x3
+ field @Deprecated public static final int NONE = 0; // 0x0
+ field @Deprecated public static final int SMS4 = 4; // 0x4
+ field @Deprecated public static final int TKIP = 1; // 0x1
+ field @Deprecated public static final String[] strings;
+ field @Deprecated public static final String varName = "pairwise";
+ }
+
+ @Deprecated public static class WifiConfiguration.Protocol {
+ field @Deprecated public static final int RSN = 1; // 0x1
+ field @Deprecated public static final int WAPI = 3; // 0x3
+ field @Deprecated public static final int WPA = 0; // 0x0
+ field @Deprecated public static final String[] strings;
+ field @Deprecated public static final String varName = "proto";
+ }
+
+ @Deprecated public static class WifiConfiguration.Status {
+ field @Deprecated public static final int CURRENT = 0; // 0x0
+ field @Deprecated public static final int DISABLED = 1; // 0x1
+ field @Deprecated public static final int ENABLED = 2; // 0x2
+ field @Deprecated public static final String[] strings;
+ }
+
+ public class WifiEnterpriseConfig implements android.os.Parcelable {
+ ctor public WifiEnterpriseConfig();
+ ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
+ method public int describeContents();
+ method public String getAltSubjectMatch();
+ method public String getAnonymousIdentity();
+ method @Nullable public java.security.cert.X509Certificate getCaCertificate();
+ method @Nullable public java.security.cert.X509Certificate[] getCaCertificates();
+ method public java.security.cert.X509Certificate getClientCertificate();
+ method @Nullable public java.security.cert.X509Certificate[] getClientCertificateChain();
+ method @Nullable public java.security.PrivateKey getClientPrivateKey();
+ method public String getDomainSuffixMatch();
+ method public int getEapMethod();
+ method public String getIdentity();
+ method public String getPassword();
+ method public int getPhase2Method();
+ method public String getPlmn();
+ method public String getRealm();
+ method @Deprecated public String getSubjectMatch();
+ method public boolean isAuthenticationSimBased();
+ method public void setAltSubjectMatch(String);
+ method public void setAnonymousIdentity(String);
+ method public void setCaCertificate(@Nullable java.security.cert.X509Certificate);
+ method public void setCaCertificates(@Nullable java.security.cert.X509Certificate[]);
+ method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+ method public void setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]);
+ method public void setDomainSuffixMatch(String);
+ method public void setEapMethod(int);
+ method public void setIdentity(String);
+ method public void setPassword(String);
+ method public void setPhase2Method(int);
+ method public void setPlmn(String);
+ method public void setRealm(String);
+ method @Deprecated public void setSubjectMatch(String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiEnterpriseConfig> CREATOR;
+ field public static final String EXTRA_WAPI_AS_CERTIFICATE_DATA = "android.net.wifi.extra.WAPI_AS_CERTIFICATE_DATA";
+ field public static final String EXTRA_WAPI_AS_CERTIFICATE_NAME = "android.net.wifi.extra.WAPI_AS_CERTIFICATE_NAME";
+ field public static final String EXTRA_WAPI_USER_CERTIFICATE_DATA = "android.net.wifi.extra.WAPI_USER_CERTIFICATE_DATA";
+ field public static final String EXTRA_WAPI_USER_CERTIFICATE_NAME = "android.net.wifi.extra.WAPI_USER_CERTIFICATE_NAME";
+ field public static final String WAPI_AS_CERTIFICATE = "WAPIAS_";
+ field public static final String WAPI_USER_CERTIFICATE = "WAPIUSR_";
+ }
+
+ public static final class WifiEnterpriseConfig.Eap {
+ field public static final int AKA = 5; // 0x5
+ field public static final int AKA_PRIME = 6; // 0x6
+ field public static final int NONE = -1; // 0xffffffff
+ field public static final int PEAP = 0; // 0x0
+ field public static final int PWD = 3; // 0x3
+ field public static final int SIM = 4; // 0x4
+ field public static final int TLS = 1; // 0x1
+ field public static final int TTLS = 2; // 0x2
+ field public static final int UNAUTH_TLS = 7; // 0x7
+ field public static final int WAPI_CERT = 8; // 0x8
+ }
+
+ public static final class WifiEnterpriseConfig.Phase2 {
+ field public static final int AKA = 6; // 0x6
+ field public static final int AKA_PRIME = 7; // 0x7
+ field public static final int GTC = 4; // 0x4
+ field public static final int MSCHAP = 2; // 0x2
+ field public static final int MSCHAPV2 = 3; // 0x3
+ field public static final int NONE = 0; // 0x0
+ field public static final int PAP = 1; // 0x1
+ field public static final int SIM = 5; // 0x5
+ }
+
+ public class WifiInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public String getBSSID();
+ method public static android.net.NetworkInfo.DetailedState getDetailedStateOf(android.net.wifi.SupplicantState);
+ method public int getFrequency();
+ method public boolean getHiddenSSID();
+ method public int getIpAddress();
+ method public int getLinkSpeed();
+ method public String getMacAddress();
+ method public int getMaxSupportedRxLinkSpeedMbps();
+ method public int getMaxSupportedTxLinkSpeedMbps();
+ method public int getNetworkId();
+ method @Nullable public String getPasspointFqdn();
+ method @Nullable public String getPasspointProviderFriendlyName();
+ method public int getRssi();
+ method @IntRange(from=0xffffffff) public int getRxLinkSpeedMbps();
+ method public String getSSID();
+ method public android.net.wifi.SupplicantState getSupplicantState();
+ method @IntRange(from=0xffffffff) public int getTxLinkSpeedMbps();
+ method public int getWifiStandard();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final String FREQUENCY_UNITS = "MHz";
+ field public static final String LINK_SPEED_UNITS = "Mbps";
+ field public static final int LINK_SPEED_UNKNOWN = -1; // 0xffffffff
+ }
+
+ public static final class WifiInfo.Builder {
+ ctor public WifiInfo.Builder();
+ method @NonNull public android.net.wifi.WifiInfo build();
+ method @NonNull public android.net.wifi.WifiInfo.Builder setBssid(@NonNull String);
+ method @NonNull public android.net.wifi.WifiInfo.Builder setNetworkId(int);
+ method @NonNull public android.net.wifi.WifiInfo.Builder setRssi(int);
+ method @NonNull public android.net.wifi.WifiInfo.Builder setSsid(@NonNull byte[]);
+ }
+
+ public class WifiManager {
+ method @Deprecated public int addNetwork(android.net.wifi.WifiConfiguration);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int addNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>);
+ method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+ method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public void addSuggestionConnectionStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SuggestionConnectionStatusListener);
+ method @Deprecated public static int calculateSignalLevel(int, int);
+ method @IntRange(from=0) public int calculateSignalLevel(int);
+ method @Deprecated public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
+ method public static int compareSignalLevel(int, int);
+ method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(String);
+ method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, String);
+ method @Deprecated public android.net.wifi.WifiManager.WifiLock createWifiLock(String);
+ method @Deprecated public boolean disableNetwork(int);
+ method @Deprecated public boolean disconnect();
+ method @Deprecated public boolean enableNetwork(int, boolean);
+ method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
+ method public android.net.wifi.WifiInfo getConnectionInfo();
+ method public android.net.DhcpInfo getDhcpInfo();
+ method public int getMaxNumberOfNetworkSuggestionsPerApp();
+ method @IntRange(from=0) public int getMaxSignalLevel();
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions();
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
+ method public java.util.List<android.net.wifi.ScanResult> getScanResults();
+ method public int getWifiState();
+ method public boolean is5GHzBandSupported();
+ method public boolean is6GHzBandSupported();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isAutoWakeupEnabled();
+ method @Deprecated public boolean isDeviceToApRttSupported();
+ method public boolean isEasyConnectSupported();
+ method public boolean isEnhancedOpenSupported();
+ method public boolean isEnhancedPowerReportingSupported();
+ method public boolean isP2pSupported();
+ method public boolean isPreferredNetworkOffloadSupported();
+ method @Deprecated public boolean isScanAlwaysAvailable();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isScanThrottleEnabled();
+ method public boolean isStaApConcurrencySupported();
+ method public boolean isTdlsSupported();
+ method public boolean isWapiSupported();
+ method public boolean isWifiEnabled();
+ method public boolean isWifiStandardSupported(int);
+ method public boolean isWpa3SaeSupported();
+ method public boolean isWpa3SuiteBSupported();
+ method @Deprecated public boolean pingSupplicant();
+ method @Deprecated public boolean reassociate();
+ method @Deprecated public boolean reconnect();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void registerScanResultsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.ScanResultsCallback);
+ method @Deprecated public boolean removeNetwork(int);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int removeNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_CARRIER_PROVISIONING}) public void removePasspointConfiguration(String);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void removeSuggestionConnectionStatusListener(@NonNull android.net.wifi.WifiManager.SuggestionConnectionStatusListener);
+ method @Deprecated public boolean saveConfiguration();
+ method public void setTdlsEnabled(java.net.InetAddress, boolean);
+ method public void setTdlsEnabledWithMacAddress(String, boolean);
+ method @Deprecated public boolean setWifiEnabled(boolean);
+ method @RequiresPermission(allOf={android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, @Nullable android.os.Handler);
+ method @Deprecated public boolean startScan();
+ method @Deprecated public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void unregisterScanResultsCallback(@NonNull android.net.wifi.WifiManager.ScanResultsCallback);
+ method @Deprecated public int updateNetwork(android.net.wifi.WifiConfiguration);
+ field public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
+ field public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
+ field public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION = "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
+ field public static final String ACTION_WIFI_SCAN_AVAILABILITY_CHANGED = "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED";
+ field @Deprecated public static final int ERROR_AUTHENTICATING = 1; // 0x1
+ field @Deprecated public static final String EXTRA_BSSID = "bssid";
+ field public static final String EXTRA_NETWORK_INFO = "networkInfo";
+ field public static final String EXTRA_NETWORK_SUGGESTION = "android.net.wifi.extra.NETWORK_SUGGESTION";
+ field public static final String EXTRA_NEW_RSSI = "newRssi";
+ field @Deprecated public static final String EXTRA_NEW_STATE = "newState";
+ field public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
+ field public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
+ field public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE";
+ field @Deprecated public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
+ field @Deprecated public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
+ field @Deprecated public static final String EXTRA_WIFI_INFO = "wifiInfo";
+ field public static final String EXTRA_WIFI_STATE = "wifi_state";
+ field public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
+ field public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
+ field public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
+ field public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3; // 0x3
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4; // 0x4
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID = 7; // 0x7
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED = 6; // 0x6
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2; // 0x2
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1; // 0x1
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5; // 0x5
+ field public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1; // 0x1
+ field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2; // 0x2
+ field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3; // 0x3
+ field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN = 0; // 0x0
+ field @Deprecated public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
+ field @Deprecated public static final String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
+ field public static final String UNKNOWN_SSID = "<unknown ssid>";
+ field @Deprecated public static final int WIFI_MODE_FULL = 1; // 0x1
+ field public static final int WIFI_MODE_FULL_HIGH_PERF = 3; // 0x3
+ field public static final int WIFI_MODE_FULL_LOW_LATENCY = 4; // 0x4
+ field @Deprecated public static final int WIFI_MODE_SCAN_ONLY = 2; // 0x2
+ field public static final String WIFI_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_STATE_CHANGED";
+ field public static final int WIFI_STATE_DISABLED = 1; // 0x1
+ field public static final int WIFI_STATE_DISABLING = 0; // 0x0
+ field public static final int WIFI_STATE_ENABLED = 3; // 0x3
+ field public static final int WIFI_STATE_ENABLING = 2; // 0x2
+ field public static final int WIFI_STATE_UNKNOWN = 4; // 0x4
+ field @Deprecated public static final int WPS_AUTH_FAILURE = 6; // 0x6
+ field @Deprecated public static final int WPS_OVERLAP_ERROR = 3; // 0x3
+ field @Deprecated public static final int WPS_TIMED_OUT = 7; // 0x7
+ field @Deprecated public static final int WPS_TKIP_ONLY_PROHIBITED = 5; // 0x5
+ field @Deprecated public static final int WPS_WEP_PROHIBITED = 4; // 0x4
+ }
+
+ public static class WifiManager.LocalOnlyHotspotCallback {
+ ctor public WifiManager.LocalOnlyHotspotCallback();
+ method public void onFailed(int);
+ method public void onStarted(android.net.wifi.WifiManager.LocalOnlyHotspotReservation);
+ method public void onStopped();
+ field public static final int ERROR_GENERIC = 2; // 0x2
+ field public static final int ERROR_INCOMPATIBLE_MODE = 3; // 0x3
+ field public static final int ERROR_NO_CHANNEL = 1; // 0x1
+ field public static final int ERROR_TETHERING_DISALLOWED = 4; // 0x4
+ }
+
+ public class WifiManager.LocalOnlyHotspotReservation implements java.lang.AutoCloseable {
+ method public void close();
+ method @NonNull public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
+ method @Deprecated @Nullable public android.net.wifi.WifiConfiguration getWifiConfiguration();
+ }
+
+ public class WifiManager.MulticastLock {
+ method public void acquire();
+ method public boolean isHeld();
+ method public void release();
+ method public void setReferenceCounted(boolean);
+ }
+
+ public abstract static class WifiManager.ScanResultsCallback {
+ ctor public WifiManager.ScanResultsCallback();
+ method public abstract void onScanResultsAvailable();
+ }
+
+ public static interface WifiManager.SuggestionConnectionStatusListener {
+ method public void onConnectionStatus(@NonNull android.net.wifi.WifiNetworkSuggestion, int);
+ }
+
+ public class WifiManager.WifiLock {
+ method public void acquire();
+ method public boolean isHeld();
+ method public void release();
+ method public void setReferenceCounted(boolean);
+ method public void setWorkSource(android.os.WorkSource);
+ }
+
+ @Deprecated public abstract static class WifiManager.WpsCallback {
+ ctor @Deprecated public WifiManager.WpsCallback();
+ method @Deprecated public abstract void onFailed(int);
+ method @Deprecated public abstract void onStarted(String);
+ method @Deprecated public abstract void onSucceeded();
+ }
+
+ public final class WifiNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSpecifier> CREATOR;
+ }
+
+ public static final class WifiNetworkSpecifier.Builder {
+ ctor public WifiNetworkSpecifier.Builder();
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier build();
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setBssid(@NonNull android.net.MacAddress);
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setBssidPattern(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setIsEnhancedOpen(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setIsHiddenSsid(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setSsid(@NonNull String);
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setSsidPattern(@NonNull android.os.PatternMatcher);
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa2EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa2Passphrase(@NonNull String);
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa3EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+ method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa3Passphrase(@NonNull String);
+ }
+
+ public final class WifiNetworkSuggestion implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.net.MacAddress getBssid();
+ method @Nullable public android.net.wifi.WifiEnterpriseConfig getEnterpriseConfig();
+ method @Nullable public String getPassphrase();
+ method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig();
+ method @IntRange(from=0) public int getPriority();
+ method @Nullable public String getSsid();
+ method public boolean isAppInteractionRequired();
+ method public boolean isCredentialSharedWithUser();
+ method public boolean isEnhancedOpen();
+ method public boolean isHiddenSsid();
+ method public boolean isInitialAutojoinEnabled();
+ method public boolean isMetered();
+ method public boolean isUntrusted();
+ method public boolean isUserInteractionRequired();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSuggestion> CREATOR;
+ }
+
+ public static final class WifiNetworkSuggestion.Builder {
+ ctor public WifiNetworkSuggestion.Builder();
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion build();
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setBssid(@NonNull android.net.MacAddress);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setCredentialSharedWithUser(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsInitialAutojoinEnabled(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsMetered(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiPassphrase(@NonNull String);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2Passphrase(@NonNull String);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa3EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa3Passphrase(@NonNull String);
+ }
+
+ public class WpsInfo implements android.os.Parcelable {
+ ctor public WpsInfo();
+ ctor public WpsInfo(android.net.wifi.WpsInfo);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public String BSSID;
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WpsInfo> CREATOR;
+ field public static final int DISPLAY = 1; // 0x1
+ field public static final int INVALID = 4; // 0x4
+ field public static final int KEYPAD = 2; // 0x2
+ field public static final int LABEL = 3; // 0x3
+ field public static final int PBC = 0; // 0x0
+ field public String pin;
+ field public int setup;
+ }
+
+}
+
+package android.net.wifi.aware {
+
+ public class AttachCallback {
+ ctor public AttachCallback();
+ method public void onAttachFailed();
+ method public void onAttached(android.net.wifi.aware.WifiAwareSession);
+ }
+
+ public final class Characteristics implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getMaxMatchFilterLength();
+ method public int getMaxServiceNameLength();
+ method public int getMaxServiceSpecificInfoLength();
+ method public int getSupportedCipherSuites();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.Characteristics> CREATOR;
+ field public static final int WIFI_AWARE_CIPHER_SUITE_NCS_SK_128 = 1; // 0x1
+ field public static final int WIFI_AWARE_CIPHER_SUITE_NCS_SK_256 = 2; // 0x2
+ }
+
+ public class DiscoverySession implements java.lang.AutoCloseable {
+ method public void close();
+ method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierOpen(@NonNull android.net.wifi.aware.PeerHandle);
+ method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(@NonNull android.net.wifi.aware.PeerHandle, @NonNull String);
+ method public void sendMessage(@NonNull android.net.wifi.aware.PeerHandle, int, @Nullable byte[]);
+ }
+
+ public class DiscoverySessionCallback {
+ ctor public DiscoverySessionCallback();
+ method public void onMessageReceived(android.net.wifi.aware.PeerHandle, byte[]);
+ method public void onMessageSendFailed(int);
+ method public void onMessageSendSucceeded(int);
+ method public void onPublishStarted(@NonNull android.net.wifi.aware.PublishDiscoverySession);
+ method public void onServiceDiscovered(android.net.wifi.aware.PeerHandle, byte[], java.util.List<byte[]>);
+ method public void onServiceDiscoveredWithinRange(android.net.wifi.aware.PeerHandle, byte[], java.util.List<byte[]>, int);
+ method public void onSessionConfigFailed();
+ method public void onSessionConfigUpdated();
+ method public void onSessionTerminated();
+ method public void onSubscribeStarted(@NonNull android.net.wifi.aware.SubscribeDiscoverySession);
+ }
+
+ public class IdentityChangedListener {
+ ctor public IdentityChangedListener();
+ method public void onIdentityChanged(byte[]);
+ }
+
+ public final class ParcelablePeerHandle extends android.net.wifi.aware.PeerHandle implements android.os.Parcelable {
+ ctor public ParcelablePeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.ParcelablePeerHandle> CREATOR;
+ }
+
+ public class PeerHandle {
+ }
+
+ public final class PublishConfig implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.PublishConfig> CREATOR;
+ field public static final int PUBLISH_TYPE_SOLICITED = 1; // 0x1
+ field public static final int PUBLISH_TYPE_UNSOLICITED = 0; // 0x0
+ }
+
+ public static final class PublishConfig.Builder {
+ ctor public PublishConfig.Builder();
+ method public android.net.wifi.aware.PublishConfig build();
+ method public android.net.wifi.aware.PublishConfig.Builder setMatchFilter(@Nullable java.util.List<byte[]>);
+ method public android.net.wifi.aware.PublishConfig.Builder setPublishType(int);
+ method public android.net.wifi.aware.PublishConfig.Builder setRangingEnabled(boolean);
+ method public android.net.wifi.aware.PublishConfig.Builder setServiceName(@NonNull String);
+ method public android.net.wifi.aware.PublishConfig.Builder setServiceSpecificInfo(@Nullable byte[]);
+ method public android.net.wifi.aware.PublishConfig.Builder setTerminateNotificationEnabled(boolean);
+ method public android.net.wifi.aware.PublishConfig.Builder setTtlSec(int);
+ }
+
+ public class PublishDiscoverySession extends android.net.wifi.aware.DiscoverySession {
+ method public void updatePublish(@NonNull android.net.wifi.aware.PublishConfig);
+ }
+
+ public final class SubscribeConfig implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.SubscribeConfig> CREATOR;
+ field public static final int SUBSCRIBE_TYPE_ACTIVE = 1; // 0x1
+ field public static final int SUBSCRIBE_TYPE_PASSIVE = 0; // 0x0
+ }
+
+ public static final class SubscribeConfig.Builder {
+ ctor public SubscribeConfig.Builder();
+ method public android.net.wifi.aware.SubscribeConfig build();
+ method public android.net.wifi.aware.SubscribeConfig.Builder setMatchFilter(@Nullable java.util.List<byte[]>);
+ method public android.net.wifi.aware.SubscribeConfig.Builder setMaxDistanceMm(int);
+ method public android.net.wifi.aware.SubscribeConfig.Builder setMinDistanceMm(int);
+ method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(@NonNull String);
+ method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(@Nullable byte[]);
+ method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
+ method public android.net.wifi.aware.SubscribeConfig.Builder setTerminateNotificationEnabled(boolean);
+ method public android.net.wifi.aware.SubscribeConfig.Builder setTtlSec(int);
+ }
+
+ public class SubscribeDiscoverySession extends android.net.wifi.aware.DiscoverySession {
+ method public void updateSubscribe(@NonNull android.net.wifi.aware.SubscribeConfig);
+ }
+
+ public class WifiAwareManager {
+ method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @Nullable android.os.Handler);
+ method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @NonNull android.net.wifi.aware.IdentityChangedListener, @Nullable android.os.Handler);
+ method public android.net.wifi.aware.Characteristics getCharacteristics();
+ method public boolean isAvailable();
+ field public static final String ACTION_WIFI_AWARE_STATE_CHANGED = "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED";
+ field public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0; // 0x0
+ field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
+ }
+
+ public final class WifiAwareNetworkInfo implements android.os.Parcelable android.net.TransportInfo {
+ method public int describeContents();
+ method @Nullable public java.net.Inet6Address getPeerIpv6Addr();
+ method public int getPort();
+ method public int getTransportProtocol();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.WifiAwareNetworkInfo> CREATOR;
+ }
+
+ public final class WifiAwareNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.WifiAwareNetworkSpecifier> CREATOR;
+ }
+
+ public static final class WifiAwareNetworkSpecifier.Builder {
+ ctor public WifiAwareNetworkSpecifier.Builder(@NonNull android.net.wifi.aware.DiscoverySession, @NonNull android.net.wifi.aware.PeerHandle);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier build();
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPmk(@NonNull byte[]);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPort(@IntRange(from=0, to=65535) int);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPskPassphrase(@NonNull String);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setTransportProtocol(@IntRange(from=0, to=255) int);
+ }
+
+ public class WifiAwareSession implements java.lang.AutoCloseable {
+ method public void close();
+ method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, @NonNull byte[]);
+ method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, @NonNull byte[], @NonNull String);
+ method public void publish(@NonNull android.net.wifi.aware.PublishConfig, @NonNull android.net.wifi.aware.DiscoverySessionCallback, @Nullable android.os.Handler);
+ method public void subscribe(@NonNull android.net.wifi.aware.SubscribeConfig, @NonNull android.net.wifi.aware.DiscoverySessionCallback, @Nullable android.os.Handler);
+ }
+
+}
+
+package android.net.wifi.hotspot2 {
+
+ public final class ConfigParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(String, byte[]);
+ }
+
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ ctor public PasspointConfiguration();
+ ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+ method public int describeContents();
+ method public android.net.wifi.hotspot2.pps.Credential getCredential();
+ method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+ method public long getSubscriptionExpirationTimeMillis();
+ method @NonNull public String getUniqueId();
+ method public boolean isOsuProvisioned();
+ method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+ method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+ }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+ public final class PpsMoParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(String);
+ }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+ public final class Credential implements android.os.Parcelable {
+ ctor public Credential();
+ ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+ method public int describeContents();
+ method public java.security.cert.X509Certificate getCaCertificate();
+ method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
+ method public java.security.PrivateKey getClientPrivateKey();
+ method public String getRealm();
+ method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+ method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+ method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+ method public void setClientPrivateKey(java.security.PrivateKey);
+ method public void setRealm(String);
+ method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+ }
+
+ public static final class Credential.CertificateCredential implements android.os.Parcelable {
+ ctor public Credential.CertificateCredential();
+ ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public int describeContents();
+ method public byte[] getCertSha256Fingerprint();
+ method public String getCertType();
+ method public void setCertSha256Fingerprint(byte[]);
+ method public void setCertType(String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+ }
+
+ public static final class Credential.SimCredential implements android.os.Parcelable {
+ ctor public Credential.SimCredential();
+ ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public int describeContents();
+ method public int getEapType();
+ method public String getImsi();
+ method public void setEapType(int);
+ method public void setImsi(String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+ }
+
+ public static final class Credential.UserCredential implements android.os.Parcelable {
+ ctor public Credential.UserCredential();
+ ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public int describeContents();
+ method public int getEapType();
+ method public String getNonEapInnerMethod();
+ method public String getPassword();
+ method public String getUsername();
+ method public void setEapType(int);
+ method public void setNonEapInnerMethod(String);
+ method public void setPassword(String);
+ method public void setUsername(String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+ }
+
+ public final class HomeSp implements android.os.Parcelable {
+ ctor public HomeSp();
+ ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public int describeContents();
+ method public String getFqdn();
+ method public String getFriendlyName();
+ method public long[] getRoamingConsortiumOis();
+ method public void setFqdn(String);
+ method public void setFriendlyName(String);
+ method public void setRoamingConsortiumOis(long[]);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+ }
+
+}
+
+package android.net.wifi.p2p {
+
+ public class WifiP2pConfig implements android.os.Parcelable {
+ ctor public WifiP2pConfig();
+ ctor public WifiP2pConfig(android.net.wifi.p2p.WifiP2pConfig);
+ method public int describeContents();
+ method public int getGroupOwnerBand();
+ method public int getNetworkId();
+ method @Nullable public String getNetworkName();
+ method @Nullable public String getPassphrase();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pConfig> CREATOR;
+ field public static final int GROUP_OWNER_BAND_2GHZ = 1; // 0x1
+ field public static final int GROUP_OWNER_BAND_5GHZ = 2; // 0x2
+ field public static final int GROUP_OWNER_BAND_AUTO = 0; // 0x0
+ field public static final int GROUP_OWNER_INTENT_AUTO = -1; // 0xffffffff
+ field public static final int GROUP_OWNER_INTENT_MAX = 15; // 0xf
+ field public static final int GROUP_OWNER_INTENT_MIN = 0; // 0x0
+ field public String deviceAddress;
+ field @IntRange(from=0, to=15) public int groupOwnerIntent;
+ field public android.net.wifi.WpsInfo wps;
+ }
+
+ public static final class WifiP2pConfig.Builder {
+ ctor public WifiP2pConfig.Builder();
+ method @NonNull public android.net.wifi.p2p.WifiP2pConfig build();
+ method @NonNull public android.net.wifi.p2p.WifiP2pConfig.Builder enablePersistentMode(boolean);
+ method @NonNull public android.net.wifi.p2p.WifiP2pConfig.Builder setDeviceAddress(@Nullable android.net.MacAddress);
+ method @NonNull public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOperatingBand(int);
+ method @NonNull public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOperatingFrequency(int);
+ method @NonNull public android.net.wifi.p2p.WifiP2pConfig.Builder setNetworkName(@NonNull String);
+ method @NonNull public android.net.wifi.p2p.WifiP2pConfig.Builder setPassphrase(@NonNull String);
+ }
+
+ public class WifiP2pDevice implements android.os.Parcelable {
+ ctor public WifiP2pDevice();
+ ctor public WifiP2pDevice(android.net.wifi.p2p.WifiP2pDevice);
+ method public int describeContents();
+ method @Nullable public android.net.wifi.p2p.WifiP2pWfdInfo getWfdInfo();
+ method public boolean isGroupOwner();
+ method public boolean isServiceDiscoveryCapable();
+ method public void update(@NonNull android.net.wifi.p2p.WifiP2pDevice);
+ method public boolean wpsDisplaySupported();
+ method public boolean wpsKeypadSupported();
+ method public boolean wpsPbcSupported();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int AVAILABLE = 3; // 0x3
+ field public static final int CONNECTED = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pDevice> CREATOR;
+ field public static final int FAILED = 2; // 0x2
+ field public static final int INVITED = 1; // 0x1
+ field public static final int UNAVAILABLE = 4; // 0x4
+ field public String deviceAddress;
+ field public String deviceName;
+ field public String primaryDeviceType;
+ field public String secondaryDeviceType;
+ field public int status;
+ }
+
+ public class WifiP2pDeviceList implements android.os.Parcelable {
+ ctor public WifiP2pDeviceList();
+ ctor public WifiP2pDeviceList(android.net.wifi.p2p.WifiP2pDeviceList);
+ method public int describeContents();
+ method public android.net.wifi.p2p.WifiP2pDevice get(String);
+ method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getDeviceList();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pDeviceList> CREATOR;
+ }
+
+ public class WifiP2pGroup implements android.os.Parcelable {
+ ctor public WifiP2pGroup();
+ ctor public WifiP2pGroup(android.net.wifi.p2p.WifiP2pGroup);
+ method public int describeContents();
+ method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getClientList();
+ method public int getFrequency();
+ method public String getInterface();
+ method public int getNetworkId();
+ method public String getNetworkName();
+ method public android.net.wifi.p2p.WifiP2pDevice getOwner();
+ method public String getPassphrase();
+ method public boolean isGroupOwner();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroup> CREATOR;
+ field public static final int NETWORK_ID_PERSISTENT = -2; // 0xfffffffe
+ field public static final int NETWORK_ID_TEMPORARY = -1; // 0xffffffff
+ }
+
+ public class WifiP2pInfo implements android.os.Parcelable {
+ ctor public WifiP2pInfo();
+ ctor public WifiP2pInfo(android.net.wifi.p2p.WifiP2pInfo);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pInfo> CREATOR;
+ field public boolean groupFormed;
+ field public java.net.InetAddress groupOwnerAddress;
+ field public boolean isGroupOwner;
+ }
+
+ public class WifiP2pManager {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void addLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void addServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void cancelConnect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void clearLocalServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void clearServiceRequests(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void createGroup(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pConfig, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void discoverServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public android.net.wifi.p2p.WifiP2pManager.Channel initialize(android.content.Context, android.os.Looper, android.net.wifi.p2p.WifiP2pManager.ChannelListener);
+ method public void removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void removeLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void removeServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestDeviceInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.DeviceInfoListener);
+ method public void requestDiscoveryState(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.DiscoveryStateListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener);
+ method public void requestNetworkInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.NetworkInfoListener);
+ method public void requestP2pState(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.P2pStateListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener);
+ method public void setDnsSdResponseListeners(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener, android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener);
+ method public void setServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ServiceResponseListener);
+ method public void setUpnpServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.UpnpServiceResponseListener);
+ method public void stopPeerDiscovery(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ field public static final int BUSY = 2; // 0x2
+ field public static final int ERROR = 0; // 0x0
+ field public static final String EXTRA_DISCOVERY_STATE = "discoveryState";
+ field public static final String EXTRA_NETWORK_INFO = "networkInfo";
+ field public static final String EXTRA_P2P_DEVICE_LIST = "wifiP2pDeviceList";
+ field public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
+ field public static final String EXTRA_WIFI_P2P_GROUP = "p2pGroupInfo";
+ field public static final String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo";
+ field public static final String EXTRA_WIFI_STATE = "wifi_p2p_state";
+ field public static final int NO_SERVICE_REQUESTS = 3; // 0x3
+ field public static final int P2P_UNSUPPORTED = 1; // 0x1
+ field public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION = "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
+ field public static final String WIFI_P2P_DISCOVERY_CHANGED_ACTION = "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE";
+ field public static final int WIFI_P2P_DISCOVERY_STARTED = 2; // 0x2
+ field public static final int WIFI_P2P_DISCOVERY_STOPPED = 1; // 0x1
+ field public static final String WIFI_P2P_PEERS_CHANGED_ACTION = "android.net.wifi.p2p.PEERS_CHANGED";
+ field public static final String WIFI_P2P_STATE_CHANGED_ACTION = "android.net.wifi.p2p.STATE_CHANGED";
+ field public static final int WIFI_P2P_STATE_DISABLED = 1; // 0x1
+ field public static final int WIFI_P2P_STATE_ENABLED = 2; // 0x2
+ field public static final String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION = "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
+ }
+
+ public static interface WifiP2pManager.ActionListener {
+ method public void onFailure(int);
+ method public void onSuccess();
+ }
+
+ public static class WifiP2pManager.Channel implements java.lang.AutoCloseable {
+ method public void close();
+ }
+
+ public static interface WifiP2pManager.ChannelListener {
+ method public void onChannelDisconnected();
+ }
+
+ public static interface WifiP2pManager.ConnectionInfoListener {
+ method public void onConnectionInfoAvailable(android.net.wifi.p2p.WifiP2pInfo);
+ }
+
+ public static interface WifiP2pManager.DeviceInfoListener {
+ method public void onDeviceInfoAvailable(@Nullable android.net.wifi.p2p.WifiP2pDevice);
+ }
+
+ public static interface WifiP2pManager.DiscoveryStateListener {
+ method public void onDiscoveryStateAvailable(int);
+ }
+
+ public static interface WifiP2pManager.DnsSdServiceResponseListener {
+ method public void onDnsSdServiceAvailable(String, String, android.net.wifi.p2p.WifiP2pDevice);
+ }
+
+ public static interface WifiP2pManager.DnsSdTxtRecordListener {
+ method public void onDnsSdTxtRecordAvailable(String, java.util.Map<java.lang.String,java.lang.String>, android.net.wifi.p2p.WifiP2pDevice);
+ }
+
+ public static interface WifiP2pManager.GroupInfoListener {
+ method public void onGroupInfoAvailable(android.net.wifi.p2p.WifiP2pGroup);
+ }
+
+ public static interface WifiP2pManager.NetworkInfoListener {
+ method public void onNetworkInfoAvailable(@NonNull android.net.NetworkInfo);
+ }
+
+ public static interface WifiP2pManager.P2pStateListener {
+ method public void onP2pStateAvailable(int);
+ }
+
+ public static interface WifiP2pManager.PeerListListener {
+ method public void onPeersAvailable(android.net.wifi.p2p.WifiP2pDeviceList);
+ }
+
+ public static interface WifiP2pManager.ServiceResponseListener {
+ method public void onServiceAvailable(int, byte[], android.net.wifi.p2p.WifiP2pDevice);
+ }
+
+ public static interface WifiP2pManager.UpnpServiceResponseListener {
+ method public void onUpnpServiceAvailable(java.util.List<java.lang.String>, android.net.wifi.p2p.WifiP2pDevice);
+ }
+
+ public final class WifiP2pWfdInfo implements android.os.Parcelable {
+ ctor public WifiP2pWfdInfo();
+ ctor public WifiP2pWfdInfo(@Nullable android.net.wifi.p2p.WifiP2pWfdInfo);
+ method public int describeContents();
+ method public int getControlPort();
+ method public int getDeviceType();
+ method public int getMaxThroughput();
+ method public boolean isContentProtectionSupported();
+ method public boolean isEnabled();
+ method public boolean isSessionAvailable();
+ method public void setContentProtectionSupported(boolean);
+ method public void setControlPort(@IntRange(from=0) int);
+ method public boolean setDeviceType(int);
+ method public void setEnabled(boolean);
+ method public void setMaxThroughput(@IntRange(from=0) int);
+ method public void setSessionAvailable(boolean);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pWfdInfo> CREATOR;
+ field public static final int DEVICE_TYPE_PRIMARY_SINK = 1; // 0x1
+ field public static final int DEVICE_TYPE_SECONDARY_SINK = 2; // 0x2
+ field public static final int DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK = 3; // 0x3
+ field public static final int DEVICE_TYPE_WFD_SOURCE = 0; // 0x0
+ }
+
+}
+
+package android.net.wifi.p2p.nsd {
+
+ public class WifiP2pDnsSdServiceInfo extends android.net.wifi.p2p.nsd.WifiP2pServiceInfo {
+ method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo newInstance(String, String, java.util.Map<java.lang.String,java.lang.String>);
+ }
+
+ public class WifiP2pDnsSdServiceRequest extends android.net.wifi.p2p.nsd.WifiP2pServiceRequest {
+ method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance();
+ method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(String);
+ method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(String, String);
+ }
+
+ public class WifiP2pServiceInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int SERVICE_TYPE_ALL = 0; // 0x0
+ field public static final int SERVICE_TYPE_BONJOUR = 1; // 0x1
+ field public static final int SERVICE_TYPE_UPNP = 2; // 0x2
+ field public static final int SERVICE_TYPE_VENDOR_SPECIFIC = 255; // 0xff
+ }
+
+ public class WifiP2pServiceRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.net.wifi.p2p.nsd.WifiP2pServiceRequest newInstance(int, String);
+ method public static android.net.wifi.p2p.nsd.WifiP2pServiceRequest newInstance(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
+ public class WifiP2pUpnpServiceInfo extends android.net.wifi.p2p.nsd.WifiP2pServiceInfo {
+ method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo newInstance(String, String, java.util.List<java.lang.String>);
+ }
+
+ public class WifiP2pUpnpServiceRequest extends android.net.wifi.p2p.nsd.WifiP2pServiceRequest {
+ method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest newInstance();
+ method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest newInstance(String);
+ }
+
+}
+
+package android.net.wifi.rtt {
+
+ public class CivicLocationKeys {
+ field public static final int ADDITIONAL_CODE = 32; // 0x20
+ field public static final int APT = 26; // 0x1a
+ field public static final int BOROUGH = 4; // 0x4
+ field public static final int BRANCH_ROAD_NAME = 36; // 0x24
+ field public static final int BUILDING = 25; // 0x19
+ field public static final int CITY = 3; // 0x3
+ field public static final int COUNTY = 2; // 0x2
+ field public static final int DESK = 33; // 0x21
+ field public static final int FLOOR = 27; // 0x1b
+ field public static final int GROUP_OF_STREETS = 6; // 0x6
+ field public static final int HNO = 19; // 0x13
+ field public static final int HNS = 20; // 0x14
+ field public static final int LANGUAGE = 0; // 0x0
+ field public static final int LMK = 21; // 0x15
+ field public static final int LOC = 22; // 0x16
+ field public static final int NAM = 23; // 0x17
+ field public static final int NEIGHBORHOOD = 5; // 0x5
+ field public static final int PCN = 30; // 0x1e
+ field public static final int POD = 17; // 0x11
+ field public static final int POSTAL_CODE = 24; // 0x18
+ field public static final int PO_BOX = 31; // 0x1f
+ field public static final int PRD = 16; // 0x10
+ field public static final int PRIMARY_ROAD_NAME = 34; // 0x22
+ field public static final int ROAD_SECTION = 35; // 0x23
+ field public static final int ROOM = 28; // 0x1c
+ field public static final int SCRIPT = 128; // 0x80
+ field public static final int STATE = 1; // 0x1
+ field public static final int STREET_NAME_POST_MODIFIER = 39; // 0x27
+ field public static final int STREET_NAME_PRE_MODIFIER = 38; // 0x26
+ field public static final int STS = 18; // 0x12
+ field public static final int SUBBRANCH_ROAD_NAME = 37; // 0x25
+ field public static final int TYPE_OF_PLACE = 29; // 0x1d
+ }
+
+ public final class RangingRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public static int getMaxPeers();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.RangingRequest> CREATOR;
+ }
+
+ public static final class RangingRequest.Builder {
+ ctor public RangingRequest.Builder();
+ method public android.net.wifi.rtt.RangingRequest.Builder addAccessPoint(@NonNull android.net.wifi.ScanResult);
+ method public android.net.wifi.rtt.RangingRequest.Builder addAccessPoints(@NonNull java.util.List<android.net.wifi.ScanResult>);
+ method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(@NonNull android.net.MacAddress);
+ method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(@NonNull android.net.wifi.aware.PeerHandle);
+ method public android.net.wifi.rtt.RangingRequest build();
+ }
+
+ public final class RangingResult implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDistanceMm();
+ method public int getDistanceStdDevMm();
+ method @Nullable public android.net.MacAddress getMacAddress();
+ method public int getNumAttemptedMeasurements();
+ method public int getNumSuccessfulMeasurements();
+ method @Nullable public android.net.wifi.aware.PeerHandle getPeerHandle();
+ method public long getRangingTimestampMillis();
+ method public int getRssi();
+ method public int getStatus();
+ method @Nullable public android.net.wifi.rtt.ResponderLocation getUnverifiedResponderLocation();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.RangingResult> CREATOR;
+ field public static final int STATUS_FAIL = 1; // 0x1
+ field public static final int STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC = 2; // 0x2
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ }
+
+ public abstract class RangingResultCallback {
+ ctor public RangingResultCallback();
+ method public abstract void onRangingFailure(int);
+ method public abstract void onRangingResults(@NonNull java.util.List<android.net.wifi.rtt.RangingResult>);
+ field public static final int STATUS_CODE_FAIL = 1; // 0x1
+ field public static final int STATUS_CODE_FAIL_RTT_NOT_AVAILABLE = 2; // 0x2
+ }
+
+ public final class ResponderLocation implements android.os.Parcelable {
+ method public int describeContents();
+ method public double getAltitude();
+ method public int getAltitudeType();
+ method public double getAltitudeUncertainty();
+ method public java.util.List<android.net.MacAddress> getColocatedBssids();
+ method public int getDatum();
+ method public int getExpectedToMove();
+ method public double getFloorNumber();
+ method public double getHeightAboveFloorMeters();
+ method public double getHeightAboveFloorUncertaintyMeters();
+ method public double getLatitude();
+ method public double getLatitudeUncertainty();
+ method public int getLciVersion();
+ method public double getLongitude();
+ method public double getLongitudeUncertainty();
+ method @Nullable public String getMapImageMimeType();
+ method @Nullable public android.net.Uri getMapImageUri();
+ method public boolean getRegisteredLocationAgreementIndication();
+ method public boolean isLciSubelementValid();
+ method public boolean isZaxisSubelementValid();
+ method @Nullable public android.location.Address toCivicLocationAddress();
+ method @Nullable public android.util.SparseArray<java.lang.String> toCivicLocationSparseArray();
+ method @NonNull public android.location.Location toLocation();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ALTITUDE_FLOORS = 2; // 0x2
+ field public static final int ALTITUDE_METERS = 1; // 0x1
+ field public static final int ALTITUDE_UNDEFINED = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.ResponderLocation> CREATOR;
+ field public static final int DATUM_NAD83_MLLW = 3; // 0x3
+ field public static final int DATUM_NAD83_NAV88 = 2; // 0x2
+ field public static final int DATUM_UNDEFINED = 0; // 0x0
+ field public static final int DATUM_WGS84 = 1; // 0x1
+ field public static final int LCI_VERSION_1 = 1; // 0x1
+ field public static final int LOCATION_FIXED = 0; // 0x0
+ field public static final int LOCATION_MOVEMENT_UNKNOWN = 2; // 0x2
+ field public static final int LOCATION_RESERVED = 3; // 0x3
+ field public static final int LOCATION_VARIABLE = 1; // 0x1
+ }
+
+ public class WifiRttManager {
+ method public boolean isAvailable();
+ method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_WIFI_STATE}) public void startRanging(@NonNull android.net.wifi.rtt.RangingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.rtt.RangingResultCallback);
+ field public static final String ACTION_WIFI_RTT_STATE_CHANGED = "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED";
+ }
+
+}
+
diff --git a/wifi/api/lint-baseline.txt b/wifi/api/lint-baseline.txt
new file mode 100644
index 000000000000..892411f8c3a1
--- /dev/null
+++ b/wifi/api/lint-baseline.txt
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+GenericException: android.net.wifi.WifiManager.LocalOnlyHotspotReservation#finalize():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.net.wifi.WifiManager.MulticastLock#finalize():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.net.wifi.WifiManager.WifiLock#finalize():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+
+
+VisiblySynchronized: PsiThisExpression:WifiManager.this:
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.net.wifi.WifiManager.WifiLock.finalize()
+VisiblySynchronized: android.net.wifi.WifiManager.WifiLock#finalize():
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.net.wifi.WifiManager.WifiLock.finalize()
diff --git a/wifi/api/module-lib-current.txt b/wifi/api/module-lib-current.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/wifi/api/module-lib-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/wifi/api/module-lib-removed.txt b/wifi/api/module-lib-removed.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/wifi/api/module-lib-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/wifi/api/removed.txt b/wifi/api/removed.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/wifi/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
new file mode 100644
index 000000000000..07793c1eb02a
--- /dev/null
+++ b/wifi/api/system-current.txt
@@ -0,0 +1,939 @@
+// Signature format: 2.0
+package android.net.wifi {
+
+ public abstract class EasyConnectStatusCallback {
+ ctor public EasyConnectStatusCallback();
+ method public abstract void onConfiguratorSuccess(int);
+ method public abstract void onEnrolleeSuccess(int);
+ method public void onFailure(int);
+ method public void onFailure(int, @Nullable String, @NonNull android.util.SparseArray<int[]>, @NonNull int[]);
+ method public abstract void onProgress(int);
+ field public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
+ field public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED = 3; // 0x3
+ field public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE = 2; // 0x2
+ field public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
+ field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED = 1; // 0x1
+ field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
+ }
+
+ @Deprecated public class RttManager {
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
+ method @Deprecated public android.net.wifi.RttManager.Capabilities getCapabilities();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.net.wifi.RttManager.RttCapabilities getRttCapabilities();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startRanging(android.net.wifi.RttManager.RttParams[], android.net.wifi.RttManager.RttListener);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopRanging(android.net.wifi.RttManager.RttListener);
+ field @Deprecated public static final int BASE = 160256; // 0x27200
+ field @Deprecated public static final int CMD_OP_ABORTED = 160260; // 0x27204
+ field @Deprecated public static final int CMD_OP_DISABLE_RESPONDER = 160262; // 0x27206
+ field @Deprecated public static final int CMD_OP_ENABLE_RESPONDER = 160261; // 0x27205
+ field @Deprecated public static final int CMD_OP_ENALBE_RESPONDER_FAILED = 160264; // 0x27208
+ field @Deprecated public static final int CMD_OP_ENALBE_RESPONDER_SUCCEEDED = 160263; // 0x27207
+ field @Deprecated public static final int CMD_OP_FAILED = 160258; // 0x27202
+ field @Deprecated public static final int CMD_OP_START_RANGING = 160256; // 0x27200
+ field @Deprecated public static final int CMD_OP_STOP_RANGING = 160257; // 0x27201
+ field @Deprecated public static final int CMD_OP_SUCCEEDED = 160259; // 0x27203
+ field @Deprecated public static final String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
+ field @Deprecated public static final int PREAMBLE_HT = 2; // 0x2
+ field @Deprecated public static final int PREAMBLE_LEGACY = 1; // 0x1
+ field @Deprecated public static final int PREAMBLE_VHT = 4; // 0x4
+ field @Deprecated public static final int REASON_INITIATOR_NOT_ALLOWED_WHEN_RESPONDER_ON = -6; // 0xfffffffa
+ field @Deprecated public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
+ field @Deprecated public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
+ field @Deprecated public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
+ field @Deprecated public static final int REASON_PERMISSION_DENIED = -5; // 0xfffffffb
+ field @Deprecated public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
+ field @Deprecated public static final int RTT_BW_10_SUPPORT = 2; // 0x2
+ field @Deprecated public static final int RTT_BW_160_SUPPORT = 32; // 0x20
+ field @Deprecated public static final int RTT_BW_20_SUPPORT = 4; // 0x4
+ field @Deprecated public static final int RTT_BW_40_SUPPORT = 8; // 0x8
+ field @Deprecated public static final int RTT_BW_5_SUPPORT = 1; // 0x1
+ field @Deprecated public static final int RTT_BW_80_SUPPORT = 16; // 0x10
+ field @Deprecated public static final int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
+ field @Deprecated public static final int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
+ field @Deprecated public static final int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
+ field @Deprecated public static final int RTT_CHANNEL_WIDTH_40 = 1; // 0x1
+ field @Deprecated public static final int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
+ field @Deprecated public static final int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
+ field @Deprecated public static final int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
+ field @Deprecated public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
+ field @Deprecated public static final int RTT_PEER_NAN = 5; // 0x5
+ field @Deprecated public static final int RTT_PEER_P2P_CLIENT = 4; // 0x4
+ field @Deprecated public static final int RTT_PEER_P2P_GO = 3; // 0x3
+ field @Deprecated public static final int RTT_PEER_TYPE_AP = 1; // 0x1
+ field @Deprecated public static final int RTT_PEER_TYPE_STA = 2; // 0x2
+ field @Deprecated public static final int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
+ field @Deprecated public static final int RTT_STATUS_ABORTED = 8; // 0x8
+ field @Deprecated public static final int RTT_STATUS_FAILURE = 1; // 0x1
+ field @Deprecated public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6; // 0x6
+ field @Deprecated public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12; // 0xc
+ field @Deprecated public static final int RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15; // 0xf
+ field @Deprecated public static final int RTT_STATUS_FAIL_INVALID_TS = 9; // 0x9
+ field @Deprecated public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4; // 0x4
+ field @Deprecated public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7; // 0x7
+ field @Deprecated public static final int RTT_STATUS_FAIL_NO_RSP = 2; // 0x2
+ field @Deprecated public static final int RTT_STATUS_FAIL_PROTOCOL = 10; // 0xa
+ field @Deprecated public static final int RTT_STATUS_FAIL_REJECTED = 3; // 0x3
+ field @Deprecated public static final int RTT_STATUS_FAIL_SCHEDULE = 11; // 0xb
+ field @Deprecated public static final int RTT_STATUS_FAIL_TM_TIMEOUT = 5; // 0x5
+ field @Deprecated public static final int RTT_STATUS_INVALID_REQ = 13; // 0xd
+ field @Deprecated public static final int RTT_STATUS_NO_WIFI = 14; // 0xe
+ field @Deprecated public static final int RTT_STATUS_SUCCESS = 0; // 0x0
+ field @Deprecated public static final int RTT_TYPE_11_MC = 4; // 0x4
+ field @Deprecated public static final int RTT_TYPE_11_V = 2; // 0x2
+ field @Deprecated public static final int RTT_TYPE_ONE_SIDED = 1; // 0x1
+ field @Deprecated public static final int RTT_TYPE_TWO_SIDED = 2; // 0x2
+ field @Deprecated public static final int RTT_TYPE_UNSPECIFIED = 0; // 0x0
+ }
+
+ @Deprecated public class RttManager.Capabilities {
+ ctor @Deprecated public RttManager.Capabilities();
+ field @Deprecated public int supportedPeerType;
+ field @Deprecated public int supportedType;
+ }
+
+ @Deprecated public static class RttManager.ParcelableRttParams implements android.os.Parcelable {
+ field @Deprecated @NonNull public android.net.wifi.RttManager.RttParams[] mParams;
+ }
+
+ @Deprecated public static class RttManager.ParcelableRttResults implements android.os.Parcelable {
+ ctor @Deprecated public RttManager.ParcelableRttResults(android.net.wifi.RttManager.RttResult[]);
+ field @Deprecated public android.net.wifi.RttManager.RttResult[] mResults;
+ }
+
+ @Deprecated public abstract static class RttManager.ResponderCallback {
+ ctor @Deprecated public RttManager.ResponderCallback();
+ method @Deprecated public abstract void onResponderEnableFailure(int);
+ method @Deprecated public abstract void onResponderEnabled(android.net.wifi.RttManager.ResponderConfig);
+ }
+
+ @Deprecated public static class RttManager.ResponderConfig implements android.os.Parcelable {
+ ctor @Deprecated public RttManager.ResponderConfig();
+ method @Deprecated public int describeContents();
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.RttManager.ResponderConfig> CREATOR;
+ field @Deprecated public int centerFreq0;
+ field @Deprecated public int centerFreq1;
+ field @Deprecated public int channelWidth;
+ field @Deprecated public int frequency;
+ field @Deprecated public String macAddress;
+ field @Deprecated public int preamble;
+ }
+
+ @Deprecated public static class RttManager.RttCapabilities implements android.os.Parcelable {
+ ctor @Deprecated public RttManager.RttCapabilities();
+ field @Deprecated public int bwSupported;
+ field @Deprecated public boolean lciSupported;
+ field @Deprecated public boolean lcrSupported;
+ field @Deprecated public int mcVersion;
+ field @Deprecated public boolean oneSidedRttSupported;
+ field @Deprecated public int preambleSupported;
+ field @Deprecated public boolean responderSupported;
+ field @Deprecated public boolean secureRttSupported;
+ field @Deprecated public boolean supportedPeerType;
+ field @Deprecated public boolean supportedType;
+ field @Deprecated public boolean twoSided11McRttSupported;
+ }
+
+ @Deprecated public static interface RttManager.RttListener {
+ method @Deprecated public void onAborted();
+ method @Deprecated public void onFailure(int, String);
+ method @Deprecated public void onSuccess(android.net.wifi.RttManager.RttResult[]);
+ }
+
+ @Deprecated public static class RttManager.RttParams {
+ ctor @Deprecated public RttManager.RttParams();
+ field @Deprecated public boolean LCIRequest;
+ field @Deprecated public boolean LCRRequest;
+ field @Deprecated public int bandwidth;
+ field @Deprecated public String bssid;
+ field @Deprecated public int burstTimeout;
+ field @Deprecated public int centerFreq0;
+ field @Deprecated public int centerFreq1;
+ field @Deprecated public int channelWidth;
+ field @Deprecated public int deviceType;
+ field @Deprecated public int frequency;
+ field @Deprecated public int interval;
+ field @Deprecated public int numRetriesPerFTMR;
+ field @Deprecated public int numRetriesPerMeasurementFrame;
+ field @Deprecated public int numSamplesPerBurst;
+ field @Deprecated public int num_retries;
+ field @Deprecated public int num_samples;
+ field @Deprecated public int numberBurst;
+ field @Deprecated public int preamble;
+ field @Deprecated public int requestType;
+ field @Deprecated public boolean secure;
+ }
+
+ @Deprecated public static class RttManager.RttResult {
+ ctor @Deprecated public RttManager.RttResult();
+ field @Deprecated public android.net.wifi.RttManager.WifiInformationElement LCI;
+ field @Deprecated public android.net.wifi.RttManager.WifiInformationElement LCR;
+ field @Deprecated public String bssid;
+ field @Deprecated public int burstDuration;
+ field @Deprecated public int burstNumber;
+ field @Deprecated public int distance;
+ field @Deprecated public int distanceSpread;
+ field @Deprecated public int distanceStandardDeviation;
+ field @Deprecated public int distance_cm;
+ field @Deprecated public int distance_sd_cm;
+ field @Deprecated public int distance_spread_cm;
+ field @Deprecated public int frameNumberPerBurstPeer;
+ field @Deprecated public int measurementFrameNumber;
+ field @Deprecated public int measurementType;
+ field @Deprecated public int negotiatedBurstNum;
+ field @Deprecated public int requestType;
+ field @Deprecated public int retryAfterDuration;
+ field @Deprecated public int rssi;
+ field @Deprecated public int rssiSpread;
+ field @Deprecated public int rssi_spread;
+ field @Deprecated public long rtt;
+ field @Deprecated public long rttSpread;
+ field @Deprecated public long rttStandardDeviation;
+ field @Deprecated public long rtt_ns;
+ field @Deprecated public long rtt_sd_ns;
+ field @Deprecated public long rtt_spread_ns;
+ field @Deprecated public int rxRate;
+ field @Deprecated public boolean secure;
+ field @Deprecated public int status;
+ field @Deprecated public int successMeasurementFrameNumber;
+ field @Deprecated public long ts;
+ field @Deprecated public int txRate;
+ field @Deprecated public int tx_rate;
+ }
+
+ @Deprecated public static class RttManager.WifiInformationElement {
+ ctor @Deprecated public RttManager.WifiInformationElement();
+ field @Deprecated public byte[] data;
+ field @Deprecated public byte id;
+ }
+
+ public final class ScanResult implements android.os.Parcelable {
+ field public static final int CIPHER_CCMP = 3; // 0x3
+ field public static final int CIPHER_GCMP_256 = 4; // 0x4
+ field public static final int CIPHER_NONE = 0; // 0x0
+ field public static final int CIPHER_NO_GROUP_ADDRESSED = 1; // 0x1
+ field public static final int CIPHER_SMS4 = 5; // 0x5
+ field public static final int CIPHER_TKIP = 2; // 0x2
+ field public static final int KEY_MGMT_EAP = 2; // 0x2
+ field public static final int KEY_MGMT_EAP_SHA256 = 6; // 0x6
+ field public static final int KEY_MGMT_EAP_SUITE_B_192 = 10; // 0xa
+ field public static final int KEY_MGMT_FT_EAP = 4; // 0x4
+ field public static final int KEY_MGMT_FT_PSK = 3; // 0x3
+ field public static final int KEY_MGMT_FT_SAE = 11; // 0xb
+ field public static final int KEY_MGMT_NONE = 0; // 0x0
+ field public static final int KEY_MGMT_OSEN = 7; // 0x7
+ field public static final int KEY_MGMT_OWE = 9; // 0x9
+ field public static final int KEY_MGMT_OWE_TRANSITION = 12; // 0xc
+ field public static final int KEY_MGMT_PSK = 1; // 0x1
+ field public static final int KEY_MGMT_PSK_SHA256 = 5; // 0x5
+ field public static final int KEY_MGMT_SAE = 8; // 0x8
+ field public static final int KEY_MGMT_WAPI_CERT = 14; // 0xe
+ field public static final int KEY_MGMT_WAPI_PSK = 13; // 0xd
+ field public static final int PROTOCOL_NONE = 0; // 0x0
+ field public static final int PROTOCOL_OSEN = 3; // 0x3
+ field public static final int PROTOCOL_RSN = 2; // 0x2
+ field public static final int PROTOCOL_WAPI = 4; // 0x4
+ field public static final int PROTOCOL_WPA = 1; // 0x1
+ }
+
+ public final class SoftApCapability implements android.os.Parcelable {
+ method public boolean areFeaturesSupported(long);
+ method public int describeContents();
+ method public int getMaxSupportedClients();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApCapability> CREATOR;
+ field public static final long SOFTAP_FEATURE_ACS_OFFLOAD = 1L; // 0x1L
+ field public static final long SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 2L; // 0x2L
+ field public static final long SOFTAP_FEATURE_WPA3_SAE = 4L; // 0x4L
+ }
+
+ public final class SoftApConfiguration implements android.os.Parcelable {
+ method @NonNull public java.util.List<android.net.MacAddress> getAllowedClientList();
+ method public int getBand();
+ method @NonNull public java.util.List<android.net.MacAddress> getBlockedClientList();
+ method public int getChannel();
+ method public int getMaxNumberOfClients();
+ method public long getShutdownTimeoutMillis();
+ method public boolean isAutoShutdownEnabled();
+ method public boolean isClientControlByUserEnabled();
+ method @Nullable public android.net.wifi.WifiConfiguration toWifiConfiguration();
+ field public static final int BAND_2GHZ = 1; // 0x1
+ field public static final int BAND_5GHZ = 2; // 0x2
+ field public static final int BAND_6GHZ = 4; // 0x4
+ field public static final int BAND_ANY = 7; // 0x7
+ }
+
+ public static final class SoftApConfiguration.Builder {
+ ctor public SoftApConfiguration.Builder();
+ ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration);
+ method @NonNull public android.net.wifi.SoftApConfiguration build();
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAllowedClientList(@NonNull java.util.List<android.net.MacAddress>);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAutoShutdownEnabled(boolean);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBlockedClientList(@NonNull java.util.List<android.net.MacAddress>);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientControlByUserEnabled(boolean);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(@IntRange(from=0) long);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
+ }
+
+ public final class SoftApInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getBandwidth();
+ method public int getFrequency();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CHANNEL_WIDTH_160MHZ = 6; // 0x6
+ field public static final int CHANNEL_WIDTH_20MHZ = 2; // 0x2
+ field public static final int CHANNEL_WIDTH_20MHZ_NOHT = 1; // 0x1
+ field public static final int CHANNEL_WIDTH_40MHZ = 3; // 0x3
+ field public static final int CHANNEL_WIDTH_80MHZ = 4; // 0x4
+ field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 5; // 0x5
+ field public static final int CHANNEL_WIDTH_INVALID = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApInfo> CREATOR;
+ }
+
+ public final class WifiClient implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.MacAddress getMacAddress();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiClient> CREATOR;
+ }
+
+ @Deprecated public class WifiConfiguration implements android.os.Parcelable {
+ method @Deprecated public int getAuthType();
+ method @Deprecated @NonNull public android.net.IpConfiguration getIpConfiguration();
+ method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus();
+ method @Deprecated @NonNull public String getPrintableSsid();
+ method @Deprecated public int getRecentFailureReason();
+ method @Deprecated public boolean hasNoInternetAccess();
+ method @Deprecated public boolean isEphemeral();
+ method @Deprecated public static boolean isMetered(@Nullable android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiInfo);
+ method @Deprecated public boolean isNoInternetAccessExpected();
+ method @Deprecated public void setIpConfiguration(@Nullable android.net.IpConfiguration);
+ method @Deprecated public void setNetworkSelectionStatus(@NonNull android.net.wifi.WifiConfiguration.NetworkSelectionStatus);
+ field @Deprecated public static final int INVALID_NETWORK_ID = -1; // 0xffffffff
+ field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1
+ field @Deprecated public static final int METERED_OVERRIDE_NONE = 0; // 0x0
+ field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2
+ field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0
+ field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
+ field @Deprecated public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
+ field @Deprecated public static final int RECENT_FAILURE_NONE = 0; // 0x0
+ field @Deprecated public boolean allowAutojoin;
+ field @Deprecated public int carrierId;
+ field @Deprecated public String creatorName;
+ field @Deprecated public int creatorUid;
+ field @Deprecated public boolean fromWifiNetworkSpecifier;
+ field @Deprecated public boolean fromWifiNetworkSuggestion;
+ field @Deprecated public String lastUpdateName;
+ field @Deprecated public int lastUpdateUid;
+ field @Deprecated public int macRandomizationSetting;
+ field @Deprecated public boolean meteredHint;
+ field @Deprecated public int meteredOverride;
+ field @Deprecated public int numAssociation;
+ field @Deprecated public int numScorerOverride;
+ field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
+ field @Deprecated public boolean requirePmf;
+ field @Deprecated public boolean shared;
+ field @Deprecated public boolean useExternalScores;
+ }
+
+ @Deprecated public static class WifiConfiguration.KeyMgmt {
+ field @Deprecated public static final int WAPI_CERT = 14; // 0xe
+ field @Deprecated public static final int WAPI_PSK = 13; // 0xd
+ field @Deprecated public static final int WPA2_PSK = 4; // 0x4
+ }
+
+ @Deprecated public static class WifiConfiguration.NetworkSelectionStatus {
+ method @Deprecated public int getDisableReasonCounter(int);
+ method @Deprecated public long getDisableTime();
+ method @Deprecated public static int getMaxNetworkSelectionDisableReason();
+ method @Deprecated public int getNetworkSelectionDisableReason();
+ method @Deprecated @Nullable public static String getNetworkSelectionDisableReasonString(int);
+ method @Deprecated public int getNetworkSelectionStatus();
+ method @Deprecated @NonNull public String getNetworkStatusString();
+ method @Deprecated public boolean hasEverConnected();
+ field @Deprecated public static final int DISABLED_ASSOCIATION_REJECTION = 1; // 0x1
+ field @Deprecated public static final int DISABLED_AUTHENTICATION_FAILURE = 2; // 0x2
+ field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5; // 0x5
+ field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9; // 0x9
+ field @Deprecated public static final int DISABLED_BY_WIFI_MANAGER = 7; // 0x7
+ field @Deprecated public static final int DISABLED_BY_WRONG_PASSWORD = 8; // 0x8
+ field @Deprecated public static final int DISABLED_DHCP_FAILURE = 3; // 0x3
+ field @Deprecated public static final int DISABLED_NONE = 0; // 0x0
+ field @Deprecated public static final int DISABLED_NO_INTERNET_PERMANENT = 6; // 0x6
+ field @Deprecated public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; // 0x4
+ field @Deprecated public static final int NETWORK_SELECTION_ENABLED = 0; // 0x0
+ field @Deprecated public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; // 0x2
+ field @Deprecated public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; // 0x1
+ }
+
+ @Deprecated public static final class WifiConfiguration.NetworkSelectionStatus.Builder {
+ ctor @Deprecated public WifiConfiguration.NetworkSelectionStatus.Builder();
+ method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus build();
+ method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionDisableReason(int);
+ method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionStatus(int);
+ }
+
+ public class WifiEnterpriseConfig implements android.os.Parcelable {
+ method @Nullable public String[] getCaCertificateAliases();
+ method @NonNull public String getCaPath();
+ method @NonNull public String getClientCertificateAlias();
+ method public int getOcsp();
+ method @NonNull public String getWapiCertSuite();
+ method public void setCaCertificateAliases(@Nullable String[]);
+ method public void setCaPath(@NonNull String);
+ method public void setClientCertificateAlias(@NonNull String);
+ method public void setOcsp(int);
+ method public void setWapiCertSuite(@NonNull String);
+ field public static final int OCSP_NONE = 0; // 0x0
+ field public static final int OCSP_REQUEST_CERT_STATUS = 1; // 0x1
+ field public static final int OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS = 3; // 0x3
+ field public static final int OCSP_REQUIRE_CERT_STATUS = 2; // 0x2
+ }
+
+ public class WifiFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ }
+
+ public class WifiInfo implements android.os.Parcelable {
+ method public double getLostTxPacketsPerSecond();
+ method @Nullable public String getRequestingPackageName();
+ method public double getRetriedTxPacketsPerSecond();
+ method public int getScore();
+ method public double getSuccessfulRxPacketsPerSecond();
+ method public double getSuccessfulTxPacketsPerSecond();
+ method public boolean isEphemeral();
+ method public boolean isOsuAp();
+ method public boolean isPasspointAp();
+ method @Nullable public static String sanitizeSsid(@Nullable String);
+ field public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
+ field public static final int INVALID_RSSI = -127; // 0xffffff81
+ }
+
+ public class WifiManager {
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoinGlobal(boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoinPasspoint(@NonNull String, boolean);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void clearWifiConnectedNetworkScorer();
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK}) public void disableEphemeralNetwork(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset();
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCountryCode();
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.Network getCurrentNetwork();
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
+ method @NonNull @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.Map<android.net.wifi.WifiNetworkSuggestion,java.util.List<android.net.wifi.ScanResult>> getMatchingScanResults(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, @Nullable java.util.List<android.net.wifi.ScanResult>);
+ method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(@NonNull java.util.List<android.net.wifi.ScanResult>);
+ method public boolean isApMacRandomizationSupported();
+ method public boolean isConnectedMacRandomizationSupported();
+ method @Deprecated public boolean isDeviceToDeviceRttSupported();
+ method public boolean isPortableHotspotSupported();
+ method public boolean isVerboseLoggingEnabled();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
+ method public boolean isWifiScannerSupported();
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration restoreSoftApBackupData(@NonNull byte[]);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData();
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAutoWakeupEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setPasspointMeteredOverride(@NonNull String, int);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanAlwaysAvailable(boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanThrottleEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setVerboseLoggingEnabled(boolean);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public boolean setWifiConnectedNetworkScorer(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiConnectedNetworkScorer);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull android.net.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startTetheredHotspot(@Nullable android.net.wifi.SoftApConfiguration);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateInterfaceIpState(@Nullable String, int);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void updateWifiUsabilityScore(int, int, int);
+ field public static final String ACTION_LINK_CONFIGURATION_CHANGED = "android.net.wifi.LINK_CONFIGURATION_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public static final String ACTION_NETWORK_SETTINGS_RESET = "android.net.wifi.action.NETWORK_SETTINGS_RESET";
+ field public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW = "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
+ field public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
+ field public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
+ field public static final int CHANGE_REASON_ADDED = 0; // 0x0
+ field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
+ field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
+ field public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
+ field public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1; // 0x1
+ field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
+ field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
+ field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
+ field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
+ field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
+ field public static final String EXTRA_CHANGE_REASON = "changeReason";
+ field public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
+ field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
+ field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
+ field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
+ field public static final String EXTRA_URL = "android.net.wifi.extra.URL";
+ field public static final String EXTRA_WIFI_AP_FAILURE_REASON = "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
+ field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
+ field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
+ field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
+ field public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
+ field public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
+ field public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
+ field public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0; // 0x0
+ field public static final int IFACE_IP_MODE_LOCAL_ONLY = 2; // 0x2
+ field public static final int IFACE_IP_MODE_TETHERED = 1; // 0x1
+ field public static final int IFACE_IP_MODE_UNSPECIFIED = -1; // 0xffffffff
+ field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0
+ field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1
+ field public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0; // 0x0
+ field public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1; // 0x1
+ field public static final int SAP_START_FAILURE_GENERAL = 0; // 0x0
+ field public static final int SAP_START_FAILURE_NO_CHANNEL = 1; // 0x1
+ field public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2; // 0x2
+ field public static final String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
+ field public static final int WIFI_AP_STATE_DISABLED = 11; // 0xb
+ field public static final int WIFI_AP_STATE_DISABLING = 10; // 0xa
+ field public static final int WIFI_AP_STATE_ENABLED = 13; // 0xd
+ field public static final int WIFI_AP_STATE_ENABLING = 12; // 0xc
+ field public static final int WIFI_AP_STATE_FAILED = 14; // 0xe
+ field public static final String WIFI_CREDENTIAL_CHANGED_ACTION = "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
+ field public static final int WIFI_CREDENTIAL_FORGOT = 1; // 0x1
+ field public static final int WIFI_CREDENTIAL_SAVED = 0; // 0x0
+ }
+
+ public static interface WifiManager.ActionListener {
+ method public void onFailure(int);
+ method public void onSuccess();
+ }
+
+ public static interface WifiManager.NetworkRequestMatchCallback {
+ method public default void onAbort();
+ method public default void onMatch(@NonNull java.util.List<android.net.wifi.ScanResult>);
+ method public default void onUserSelectionCallbackRegistration(@NonNull android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback);
+ method public default void onUserSelectionConnectFailure(@NonNull android.net.wifi.WifiConfiguration);
+ method public default void onUserSelectionConnectSuccess(@NonNull android.net.wifi.WifiConfiguration);
+ }
+
+ public static interface WifiManager.NetworkRequestUserSelectionCallback {
+ method public default void reject();
+ method public default void select(@NonNull android.net.wifi.WifiConfiguration);
+ }
+
+ public static interface WifiManager.OnWifiActivityEnergyInfoListener {
+ method public void onWifiActivityEnergyInfo(@Nullable android.os.connectivity.WifiActivityEnergyInfo);
+ }
+
+ public static interface WifiManager.OnWifiUsabilityStatsListener {
+ method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry);
+ }
+
+ public static interface WifiManager.ScoreUpdateObserver {
+ method public void notifyScoreUpdate(int, int);
+ method public void triggerUpdateOfWifiUsabilityStats(int);
+ }
+
+ public static interface WifiManager.SoftApCallback {
+ method public default void onBlockedClientConnecting(@NonNull android.net.wifi.WifiClient, int);
+ method public default void onCapabilityChanged(@NonNull android.net.wifi.SoftApCapability);
+ method public default void onConnectedClientsChanged(@NonNull java.util.List<android.net.wifi.WifiClient>);
+ method public default void onInfoChanged(@NonNull android.net.wifi.SoftApInfo);
+ method public default void onStateChanged(int, int);
+ }
+
+ public static interface WifiManager.TrafficStateCallback {
+ method public void onStateChanged(int);
+ field public static final int DATA_ACTIVITY_IN = 1; // 0x1
+ field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3
+ field public static final int DATA_ACTIVITY_NONE = 0; // 0x0
+ field public static final int DATA_ACTIVITY_OUT = 2; // 0x2
+ }
+
+ public static interface WifiManager.WifiConnectedNetworkScorer {
+ method public void onSetScoreUpdateObserver(@NonNull android.net.wifi.WifiManager.ScoreUpdateObserver);
+ method public void onStart(int);
+ method public void onStop(int);
+ }
+
+ public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
+ ctor public WifiNetworkConnectionStatistics(int, int);
+ ctor public WifiNetworkConnectionStatistics();
+ ctor public WifiNetworkConnectionStatistics(android.net.wifi.WifiNetworkConnectionStatistics);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkConnectionStatistics> CREATOR;
+ field public int numConnection;
+ field public int numUsage;
+ }
+
+ public final class WifiNetworkSuggestion implements android.os.Parcelable {
+ method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration();
+ }
+
+ public static final class WifiNetworkSuggestion.Builder {
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
+ }
+
+ public class WifiScanner {
+ method @Deprecated public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
+ method @Deprecated public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<java.lang.Integer> getAvailableChannels(int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults();
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.net.wifi.ScanResult> getSingleScanResults();
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void registerScanListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiScanner.ScanListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setScanningEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
+ method @Deprecated public void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
+ method @Deprecated public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopScan(android.net.wifi.WifiScanner.ScanListener);
+ method @Deprecated public void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
+ method @Deprecated public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+ method public void unregisterScanListener(@NonNull android.net.wifi.WifiScanner.ScanListener);
+ field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
+ field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
+ field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
+ field public static final int REASON_INVALID_LISTENER = -2; // 0xfffffffe
+ field public static final int REASON_INVALID_REQUEST = -3; // 0xfffffffd
+ field public static final int REASON_NOT_AUTHORIZED = -4; // 0xfffffffc
+ field public static final int REASON_SUCCEEDED = 0; // 0x0
+ field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
+ field @Deprecated public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0; // 0x0
+ field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
+ field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
+ field public static final int REPORT_EVENT_NO_BATCH = 4; // 0x4
+ field public static final int SCAN_TYPE_HIGH_ACCURACY = 2; // 0x2
+ field public static final int SCAN_TYPE_LOW_LATENCY = 0; // 0x0
+ field public static final int SCAN_TYPE_LOW_POWER = 1; // 0x1
+ field public static final int WIFI_BAND_24_5_6_GHZ = 11; // 0xb
+ field public static final int WIFI_BAND_24_5_WITH_DFS_6_GHZ = 15; // 0xf
+ field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
+ field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
+ field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
+ field public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; // 0x6
+ field public static final int WIFI_BAND_6_GHZ = 8; // 0x8
+ field public static final int WIFI_BAND_BOTH = 3; // 0x3
+ field public static final int WIFI_BAND_BOTH_WITH_DFS = 7; // 0x7
+ field public static final int WIFI_BAND_UNSPECIFIED = 0; // 0x0
+ }
+
+ public static interface WifiScanner.ActionListener {
+ method public void onFailure(int, String);
+ method public void onSuccess();
+ }
+
+ @Deprecated public static class WifiScanner.BssidInfo {
+ ctor @Deprecated public WifiScanner.BssidInfo();
+ field @Deprecated public String bssid;
+ field @Deprecated public int frequencyHint;
+ field @Deprecated public int high;
+ field @Deprecated public int low;
+ }
+
+ @Deprecated public static interface WifiScanner.BssidListener extends android.net.wifi.WifiScanner.ActionListener {
+ method @Deprecated public void onFound(android.net.wifi.ScanResult[]);
+ method @Deprecated public void onLost(android.net.wifi.ScanResult[]);
+ }
+
+ public static class WifiScanner.ChannelSpec {
+ ctor public WifiScanner.ChannelSpec(int);
+ field public int frequency;
+ }
+
+ @Deprecated public static class WifiScanner.HotlistSettings implements android.os.Parcelable {
+ ctor @Deprecated public WifiScanner.HotlistSettings();
+ field @Deprecated public int apLostThreshold;
+ field @Deprecated public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
+ }
+
+ public static class WifiScanner.ParcelableScanData implements android.os.Parcelable {
+ ctor public WifiScanner.ParcelableScanData(android.net.wifi.WifiScanner.ScanData[]);
+ method public android.net.wifi.WifiScanner.ScanData[] getResults();
+ field public android.net.wifi.WifiScanner.ScanData[] mResults;
+ }
+
+ public static class WifiScanner.ParcelableScanResults implements android.os.Parcelable {
+ ctor public WifiScanner.ParcelableScanResults(android.net.wifi.ScanResult[]);
+ method public android.net.wifi.ScanResult[] getResults();
+ field public android.net.wifi.ScanResult[] mResults;
+ }
+
+ public static class WifiScanner.ScanData implements android.os.Parcelable {
+ ctor public WifiScanner.ScanData(int, int, android.net.wifi.ScanResult[]);
+ ctor public WifiScanner.ScanData(android.net.wifi.WifiScanner.ScanData);
+ method public int getFlags();
+ method public int getId();
+ method public android.net.wifi.ScanResult[] getResults();
+ }
+
+ public static interface WifiScanner.ScanListener extends android.net.wifi.WifiScanner.ActionListener {
+ method public void onFullResult(android.net.wifi.ScanResult);
+ method @Deprecated public void onPeriodChanged(int);
+ method public void onResults(android.net.wifi.WifiScanner.ScanData[]);
+ }
+
+ public static class WifiScanner.ScanSettings implements android.os.Parcelable {
+ ctor public WifiScanner.ScanSettings();
+ field public int band;
+ field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
+ field @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public final java.util.List<android.net.wifi.WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks;
+ field public boolean hideFromAppOps;
+ field public boolean ignoreLocationSettings;
+ field @Deprecated public int maxPeriodInMs;
+ field @Deprecated public int maxScansToCache;
+ field @Deprecated public int numBssidsPerScan;
+ field @Deprecated public int periodInMs;
+ field @Deprecated public int reportEvents;
+ field @Deprecated public int stepCount;
+ field @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public int type;
+ }
+
+ public static class WifiScanner.ScanSettings.HiddenNetwork {
+ ctor public WifiScanner.ScanSettings.HiddenNetwork(@NonNull String);
+ field @NonNull public final String ssid;
+ }
+
+ @Deprecated public static interface WifiScanner.WifiChangeListener extends android.net.wifi.WifiScanner.ActionListener {
+ method @Deprecated public void onChanging(android.net.wifi.ScanResult[]);
+ method @Deprecated public void onQuiescence(android.net.wifi.ScanResult[]);
+ }
+
+ @Deprecated public static class WifiScanner.WifiChangeSettings implements android.os.Parcelable {
+ ctor @Deprecated public WifiScanner.WifiChangeSettings();
+ field @Deprecated public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
+ field @Deprecated public int lostApSampleSize;
+ field @Deprecated public int minApsBreachingThreshold;
+ field @Deprecated public int periodInMs;
+ field @Deprecated public int rssiSampleSize;
+ field @Deprecated public int unchangedSampleSize;
+ }
+
+ public final class WifiUsabilityStatsEntry implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getCellularDataNetworkType();
+ method public int getCellularSignalStrengthDb();
+ method public int getCellularSignalStrengthDbm();
+ method public int getLinkSpeedMbps();
+ method public int getProbeElapsedTimeSinceLastUpdateMillis();
+ method public int getProbeMcsRateSinceLastUpdate();
+ method public int getProbeStatusSinceLastUpdate();
+ method public int getRssi();
+ method public int getRxLinkSpeedMbps();
+ method public long getTimeStampMillis();
+ method public long getTotalBackgroundScanTimeMillis();
+ method public long getTotalBeaconRx();
+ method public long getTotalCcaBusyFreqTimeMillis();
+ method public long getTotalHotspot2ScanTimeMillis();
+ method public long getTotalNanScanTimeMillis();
+ method public long getTotalPnoScanTimeMillis();
+ method public long getTotalRadioOnFreqTimeMillis();
+ method public long getTotalRadioOnTimeMillis();
+ method public long getTotalRadioRxTimeMillis();
+ method public long getTotalRadioTxTimeMillis();
+ method public long getTotalRoamScanTimeMillis();
+ method public long getTotalRxSuccess();
+ method public long getTotalScanTimeMillis();
+ method public long getTotalTxBad();
+ method public long getTotalTxRetries();
+ method public long getTotalTxSuccess();
+ method public boolean isSameRegisteredCell();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiUsabilityStatsEntry> CREATOR;
+ field public static final int PROBE_STATUS_FAILURE = 3; // 0x3
+ field public static final int PROBE_STATUS_NO_PROBE = 1; // 0x1
+ field public static final int PROBE_STATUS_SUCCESS = 2; // 0x2
+ field public static final int PROBE_STATUS_UNKNOWN = 0; // 0x0
+ }
+
+}
+
+package android.net.wifi.aware {
+
+ public class DiscoverySession implements java.lang.AutoCloseable {
+ method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]);
+ }
+
+ public class WifiAwareSession implements java.lang.AutoCloseable {
+ method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, @NonNull byte[], @NonNull byte[]);
+ }
+
+}
+
+package android.net.wifi.hotspot2 {
+
+ public final class OsuProvider implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getFriendlyName();
+ method @Nullable public android.net.Uri getServerUri();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.OsuProvider> CREATOR;
+ }
+
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ method public int getMeteredOverride();
+ method public boolean isAutojoinEnabled();
+ method public boolean isMacRandomizationEnabled();
+ }
+
+ public abstract class ProvisioningCallback {
+ ctor public ProvisioningCallback();
+ method public abstract void onProvisioningComplete();
+ method public abstract void onProvisioningFailure(int);
+ method public abstract void onProvisioningStatus(int);
+ field public static final int OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION = 22; // 0x16
+ field public static final int OSU_FAILURE_AP_CONNECTION = 1; // 0x1
+ field public static final int OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU = 8; // 0x8
+ field public static final int OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE = 17; // 0x11
+ field public static final int OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE = 21; // 0x15
+ field public static final int OSU_FAILURE_NO_OSU_ACTIVITY_FOUND = 14; // 0xe
+ field public static final int OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE = 19; // 0x13
+ field public static final int OSU_FAILURE_NO_PPS_MO = 16; // 0x10
+ field public static final int OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE = 18; // 0x12
+ field public static final int OSU_FAILURE_OSU_PROVIDER_NOT_FOUND = 23; // 0x17
+ field public static final int OSU_FAILURE_PROVISIONING_ABORTED = 6; // 0x6
+ field public static final int OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7; // 0x7
+ field public static final int OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES = 20; // 0x14
+ field public static final int OSU_FAILURE_SERVER_CONNECTION = 3; // 0x3
+ field public static final int OSU_FAILURE_SERVER_URL_INVALID = 2; // 0x2
+ field public static final int OSU_FAILURE_SERVER_VALIDATION = 4; // 0x4
+ field public static final int OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION = 5; // 0x5
+ field public static final int OSU_FAILURE_SOAP_MESSAGE_EXCHANGE = 11; // 0xb
+ field public static final int OSU_FAILURE_START_REDIRECT_LISTENER = 12; // 0xc
+ field public static final int OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER = 13; // 0xd
+ field public static final int OSU_FAILURE_UNEXPECTED_COMMAND_TYPE = 9; // 0x9
+ field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS = 15; // 0xf
+ field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE = 10; // 0xa
+ field public static final int OSU_STATUS_AP_CONNECTED = 2; // 0x2
+ field public static final int OSU_STATUS_AP_CONNECTING = 1; // 0x1
+ field public static final int OSU_STATUS_INIT_SOAP_EXCHANGE = 6; // 0x6
+ field public static final int OSU_STATUS_REDIRECT_RESPONSE_RECEIVED = 8; // 0x8
+ field public static final int OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS = 11; // 0xb
+ field public static final int OSU_STATUS_SECOND_SOAP_EXCHANGE = 9; // 0x9
+ field public static final int OSU_STATUS_SERVER_CONNECTED = 5; // 0x5
+ field public static final int OSU_STATUS_SERVER_CONNECTING = 3; // 0x3
+ field public static final int OSU_STATUS_SERVER_VALIDATED = 4; // 0x4
+ field public static final int OSU_STATUS_THIRD_SOAP_EXCHANGE = 10; // 0xa
+ field public static final int OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE = 7; // 0x7
+ }
+
+}
+
+package android.net.wifi.p2p {
+
+ public final class WifiP2pGroupList implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<android.net.wifi.p2p.WifiP2pGroup> getGroupList();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroupList> CREATOR;
+ }
+
+ public class WifiP2pManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void deletePersistentGroup(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public void requestPersistentGroupInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setDeviceName(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull String, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setMiracastMode(int);
+ method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setWfdInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pWfdInfo, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setWifiP2pChannels(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void startListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void stopListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ field public static final String ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED = "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED";
+ field public static final int MIRACAST_DISABLED = 0; // 0x0
+ field public static final int MIRACAST_SINK = 2; // 0x2
+ field public static final int MIRACAST_SOURCE = 1; // 0x1
+ }
+
+ public static interface WifiP2pManager.PersistentGroupInfoListener {
+ method public void onPersistentGroupInfoAvailable(@NonNull android.net.wifi.p2p.WifiP2pGroupList);
+ }
+
+}
+
+package android.net.wifi.rtt {
+
+ public static final class RangingRequest.Builder {
+ method public android.net.wifi.rtt.RangingRequest.Builder addResponder(@NonNull android.net.wifi.rtt.ResponderConfig);
+ }
+
+ public final class RangingResult implements android.os.Parcelable {
+ method @NonNull public byte[] getLci();
+ method @NonNull public byte[] getLcr();
+ }
+
+ public final class ResponderConfig implements android.os.Parcelable {
+ ctor public ResponderConfig(@NonNull android.net.MacAddress, int, boolean, int, int, int, int, int);
+ ctor public ResponderConfig(@NonNull android.net.wifi.aware.PeerHandle, int, boolean, int, int, int, int, int);
+ method public int describeContents();
+ method public static android.net.wifi.rtt.ResponderConfig fromScanResult(android.net.wifi.ScanResult);
+ method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerHandleWithDefaults(android.net.wifi.aware.PeerHandle);
+ method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(android.net.MacAddress);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
+ field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0
+ field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
+ field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
+ field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.ResponderConfig> CREATOR;
+ field public static final int PREAMBLE_HE = 3; // 0x3
+ field public static final int PREAMBLE_HT = 1; // 0x1
+ field public static final int PREAMBLE_LEGACY = 0; // 0x0
+ field public static final int PREAMBLE_VHT = 2; // 0x2
+ field public static final int RESPONDER_AP = 0; // 0x0
+ field public static final int RESPONDER_AWARE = 4; // 0x4
+ field public static final int RESPONDER_P2P_CLIENT = 3; // 0x3
+ field public static final int RESPONDER_P2P_GO = 2; // 0x2
+ field public static final int RESPONDER_STA = 1; // 0x1
+ field public final int centerFreq0;
+ field public final int centerFreq1;
+ field public final int channelWidth;
+ field public final int frequency;
+ field public final android.net.MacAddress macAddress;
+ field public final android.net.wifi.aware.PeerHandle peerHandle;
+ field public final int preamble;
+ field public final int responderType;
+ field public final boolean supports80211mc;
+ }
+
+ public final class ResponderLocation implements android.os.Parcelable {
+ method public boolean getExtraInfoOnAssociationIndication();
+ }
+
+ public class WifiRttManager {
+ method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE}) public void cancelRanging(@Nullable android.os.WorkSource);
+ method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_WIFI_STATE}) public void startRanging(@Nullable android.os.WorkSource, @NonNull android.net.wifi.rtt.RangingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.rtt.RangingResultCallback);
+ }
+
+}
+
diff --git a/wifi/api/system-lint-baseline.txt b/wifi/api/system-lint-baseline.txt
new file mode 100644
index 000000000000..6547ee8a2188
--- /dev/null
+++ b/wifi/api/system-lint-baseline.txt
@@ -0,0 +1,6 @@
+// Baseline format: 1.0
+MissingGetterMatchingBuilder: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
+ android.net.wifi.rtt.RangingRequest does not declare a `getResponders()` method matching method android.net.wifi.rtt.RangingRequest.Builder.addResponder(android.net.wifi.rtt.ResponderConfig)
+
+MissingNullability: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
+
diff --git a/wifi/api/system-removed.txt b/wifi/api/system-removed.txt
new file mode 100644
index 000000000000..a2d0dff3e712
--- /dev/null
+++ b/wifi/api/system-removed.txt
@@ -0,0 +1,16 @@
+// Signature format: 2.0
+package android.net.wifi {
+
+ @Deprecated public class BatchedScanResult implements android.os.Parcelable {
+ ctor public BatchedScanResult();
+ ctor public BatchedScanResult(android.net.wifi.BatchedScanResult);
+ field public final java.util.List<android.net.wifi.ScanResult> scanResults;
+ field public boolean truncated;
+ }
+
+ public final class ScanResult implements android.os.Parcelable {
+ field public boolean untrusted;
+ }
+
+}
+
diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt
new file mode 100644
index 000000000000..e253ae25659e
--- /dev/null
+++ b/wifi/jarjar-rules.txt
@@ -0,0 +1,126 @@
+## used by service-wifi ##
+
+# Network Stack AIDL interface.
+rule android.net.DataStallReportParcelable* com.android.wifi.x.@0
+rule android.net.DhcpResultsParcelable* com.android.wifi.x.@0
+rule android.net.IIpMemoryStore* com.android.wifi.x.@0
+rule android.net.IIpMemoryStoreCallbacks* com.android.wifi.x.@0
+rule android.net.INetd* com.android.wifi.x.@0
+rule android.net.INetdUnsolicitedEventListener* com.android.wifi.x.@0
+rule android.net.INetworkStackConnector* com.android.wifi.x.@0
+rule android.net.InformationElementParcelable* com.android.wifi.x.@0
+rule android.net.InitialConfigurationParcelable* com.android.wifi.x.@0
+rule android.net.InterfaceConfigurationParcel* com.android.wifi.x.@0
+rule android.net.Layer2InformationParcelable* com.android.wifi.x.@0
+rule android.net.Layer2PacketParcelable* com.android.wifi.x.@0
+rule android.net.MarkMaskParcel* com.android.wifi.x.@0
+rule android.net.NattKeepalivePacketDataParcelable* com.android.wifi.x.@0
+rule android.net.NetworkTestResultParcelable* com.android.wifi.x.@0
+rule android.net.PrivateDnsConfigParcel* com.android.wifi.x.@0
+rule android.net.ProvisioningConfigurationParcelable* com.android.wifi.x.@0
+rule android.net.ResolverParamsParcel* com.android.wifi.x.@0
+rule android.net.RouteInfoParcel* com.android.wifi.x.@0
+rule android.net.ScanResultInfoParcelable* com.android.wifi.x.@0
+rule android.net.TetherConfigParcel* com.android.wifi.x.@0
+rule android.net.TetherOffloadRuleParcel* com.android.wifi.x.@0
+rule android.net.TetherStatsParcel* com.android.wifi.x.@0
+rule android.net.UidRangeParcel* com.android.wifi.x.@0
+rule android.net.dhcp.DhcpLeaseParcelable* com.android.wifi.x.@0
+rule android.net.dhcp.DhcpServingParamsParcel* com.android.wifi.x.@0
+rule android.net.ip.IIpClient* com.android.wifi.x.@0
+rule android.net.ip.IIpClientCallbacks* com.android.wifi.x.@0
+rule android.net.ipmemorystore.Blob* com.android.wifi.x.@0
+rule android.net.ipmemorystore.IOnBlobRetrievedListener* com.android.wifi.x.@0
+rule android.net.ipmemorystore.IOnStatusAndCountListener* com.android.wifi.x.@0
+rule android.net.ipmemorystore.IOnStatusListener* com.android.wifi.x.@0
+rule android.net.ipmemorystore.NetworkAttributesParcelable* com.android.wifi.x.@0
+rule android.net.ipmemorystore.SameL3NetworkResponseParcelable* com.android.wifi.x.@0
+rule android.net.ipmemorystore.StatusParcelable* com.android.wifi.x.@0
+
+# Net utils (includes Network Stack helper classes).
+rule android.net.DhcpResults* com.android.wifi.x.@0
+rule android.net.InterfaceConfiguration* com.android.wifi.x.@0
+rule android.net.IpMemoryStore* com.android.wifi.x.@0
+rule android.net.NetworkMonitorManager* com.android.wifi.x.@0
+rule android.net.TcpKeepalivePacketData* com.android.wifi.x.@0
+rule android.net.NetworkFactory* com.android.wifi.x.@0
+rule android.net.ip.IpClientCallbacks* com.android.wifi.x.@0
+rule android.net.ip.IpClientManager* com.android.wifi.x.@0
+rule android.net.ip.IpClientUtil* com.android.wifi.x.@0
+rule android.net.ipmemorystore.NetworkAttributes* com.android.wifi.x.@0
+rule android.net.ipmemorystore.OnBlobRetrievedListener* com.android.wifi.x.@0
+rule android.net.ipmemorystore.OnDeleteStatusListener* com.android.wifi.x.@0
+rule android.net.ipmemorystore.OnStatusListener* com.android.wifi.x.@0
+rule android.net.ipmemorystore.Status* com.android.wifi.x.@0
+rule android.net.networkstack.ModuleNetworkStackClient* com.android.wifi.x.@0
+rule android.net.networkstack.NetworkStackClientBase* com.android.wifi.x.@0
+rule android.net.shared.InetAddressUtils* com.android.wifi.x.@0
+rule android.net.shared.InitialConfiguration* com.android.wifi.x.@0
+rule android.net.shared.IpConfigurationParcelableUtil* com.android.wifi.x.@0
+rule android.net.shared.Layer2Information* com.android.wifi.x.@0
+rule android.net.shared.LinkPropertiesParcelableUtil* com.android.wifi.x.@0
+rule android.net.shared.NetdUtils* com.android.wifi.x.@0
+rule android.net.shared.NetworkMonitorUtils* com.android.wifi.x.@0
+rule android.net.shared.ParcelableUtil* com.android.wifi.x.@0
+rule android.net.shared.PrivateDnsConfig* com.android.wifi.x.@0
+rule android.net.shared.ProvisioningConfiguration* com.android.wifi.x.@0
+rule android.net.shared.RouteUtils* com.android.wifi.x.@0
+rule android.net.util.KeepalivePacketDataUtil* com.android.wifi.x.@0
+rule android.net.util.NetworkConstants* com.android.wifi.x.@0
+rule android.net.util.InterfaceParams* com.android.wifi.x.@0
+rule android.net.util.SharedLog* com.android.wifi.x.@0
+rule android.net.util.NetUtils* com.android.wifi.x.@0
+rule android.net.util.IpUtils* com.android.wifi.x.@0
+
+rule androidx.annotation.** com.android.wifi.x.@0
+
+# We don't jar-jar the entire package because, we still use some classes (like
+# AsyncChannel in com.android.internal.util) from these packages which are not
+# inside our jar (currently in framework.jar, but will be in wifisdk.jar in the future).
+rule com.android.internal.util.FastXmlSerializer* com.android.wifi.x.@0
+rule com.android.internal.util.HexDump* com.android.wifi.x.@0
+rule com.android.internal.util.IState* com.android.wifi.x.@0
+rule com.android.internal.util.MessageUtils* com.android.wifi.x.@0
+rule com.android.internal.util.State* com.android.wifi.x.@0
+rule com.android.internal.util.StateMachine* com.android.wifi.x.@0
+rule com.android.internal.util.WakeupMessage* com.android.wifi.x.@0
+
+rule android.util.BackupUtils* com.android.wifi.x.@0
+rule android.util.LocalLog* com.android.wifi.x.@0
+rule android.util.Rational* com.android.wifi.x.@0
+
+rule android.os.BasicShellCommandHandler* com.android.wifi.x.@0
+
+# Use our statically linked bouncy castle library
+rule org.bouncycastle.** com.android.wifi.x.@0
+# Use our statically linked protobuf library
+rule com.google.protobuf.** com.android.wifi.x.@0
+# use statically linked SystemMessageProto
+rule com.android.internal.messages.SystemMessageProto* com.android.wifi.x.@0
+# Use our statically linked PlatformProperties library
+rule android.sysprop.** com.android.wifi.x.@0
+# Use our statically linked HIDL stubs
+# Note: android.hardware.wifi.** is used by various wifi feature flags. This unfortunately is also the namespace
+# used by vendor HAL stubs. So, this rule is intentionally weird to try and filter the vendor HAL stubs only.
+rule android.hardware.wifi.V** com.android.wifi.x.@0
+rule android.hardware.wifi.supplicant.** com.android.wifi.x.@0
+rule android.hardware.wifi.hostapd.** com.android.wifi.x.@0
+rule android.hidl.** com.android.wifi.x.@0
+# Use our statically linked ksoap2
+rule org.ksoap2.** com.android.wifi.x.@0
+# Use our statically linked nanohttpd
+rule fi.iki.elonen.** com.android.wifi.x.@0
+
+## used by both framework-wifi and service-wifi ##
+rule android.content.pm.BaseParceledListSlice* com.android.wifi.x.@0
+rule android.content.pm.ParceledListSlice* com.android.wifi.x.@0
+rule android.net.util.MacAddressUtils* com.android.wifi.x.@0
+rule android.net.util.nsd.DnsSdTxtRecord* com.android.wifi.x.@0
+rule android.os.HandlerExecutor* com.android.wifi.x.@0
+rule android.telephony.Annotation* com.android.wifi.x.@0
+rule com.android.internal.util.AsyncChannel* com.android.wifi.x.@0
+rule com.android.internal.util.AsyncService* com.android.wifi.x.@0
+rule com.android.internal.util.Preconditions* com.android.wifi.x.@0
+rule com.android.internal.util.Protocol* com.android.wifi.x.@0
+
+rule com.android.net.module.util.** com.android.wifi.x.@0
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
index b8c82fd9e0ae..6c2e6ddf5dd2 100644
--- a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -17,32 +17,44 @@
package android.net.wifi;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.os.Handler;
+import android.util.SparseArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
/**
* Easy Connect (DPP) Status Callback. Use this callback to get status updates (success, failure,
- * progress) from the Easy Connect operation started with
- * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String,
- * int, int, Handler, EasyConnectStatusCallback)} or
- * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
- * Handler, EasyConnectStatusCallback)}
- *
- * @hide
+ * progress) from the Easy Connect operations.
*/
-@SystemApi
public abstract class EasyConnectStatusCallback {
/**
- * Easy Connect Success event: Configuration sent (Configurator mode).
+ * Easy Connect R1 Success event: Configuration sent (Configurator mode). This is the last
+ * and final Easy Connect event when either the local device or remote device implement R1.
+ * If both devices implement R2, this event will never be received, and the
+ * {@link #EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED} will be received.
+ * @hide
*/
+ @SystemApi
public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
+ /**
+ * Easy Connect R2 Success event: Configuration applied by Enrollee (Configurator mode).
+ * This is the last and final Easy Connect event when both the local device and remote device
+ * implement R2. If either the local device or remote device implement R1, this event will never
+ * be received, and the {@link #EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT} will be received.
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED = 1;
+
/** @hide */
@IntDef(prefix = {"EASY_CONNECT_EVENT_SUCCESS_"}, value = {
EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT,
+ EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EasyConnectSuccessStatusCode {
@@ -50,18 +62,38 @@ public abstract class EasyConnectStatusCallback {
/**
* Easy Connect Progress event: Initial authentication with peer succeeded.
+ * @hide
*/
+ @SystemApi
public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
/**
* Easy Connect Progress event: Peer requires more time to process bootstrapping.
+ * @hide
*/
+ @SystemApi
public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1;
+ /**
+ * Easy Connect R2 Progress event: Configuration sent to Enrollee, waiting for response
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE = 2;
+
+ /**
+ * Easy Connect R2 Progress event: Configuration accepted by Enrollee, waiting for response
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED = 3;
+
/** @hide */
@IntDef(prefix = {"EASY_CONNECT_EVENT_PROGRESS_"}, value = {
EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING,
+ EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE,
+ EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EasyConnectProgressStatusCode {
@@ -114,6 +146,20 @@ public abstract class EasyConnectStatusCallback {
*/
public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9;
+ /**
+ * Easy Connect R2 Failure event: Enrollee cannot find the network.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK = -10;
+
+ /**
+ * Easy Connect R2 Failure event: Enrollee failed to authenticate with the network.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION = -11;
+
+ /**
+ * Easy Connect R2 Failure event: Enrollee rejected the configuration.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION = -12;
/** @hide */
@IntDef(prefix = {"EASY_CONNECT_EVENT_FAILURE_"}, value = {
@@ -126,11 +172,20 @@ public abstract class EasyConnectStatusCallback {
EASY_CONNECT_EVENT_FAILURE_GENERIC,
EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED,
EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK,
+ EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
+ EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION,
+ EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EasyConnectFailureStatusCode {
}
+ /** @hide */
+ @SystemApi
+ public EasyConnectStatusCallback() {
+ // Fully-static utility classes must not have constructor
+ }
+
/**
* Called when local Easy Connect Enrollee successfully receives a new Wi-Fi configuration from
* the
@@ -138,42 +193,75 @@ public abstract class EasyConnectStatusCallback {
* current Easy Connect
* session, and no further callbacks will be called. This callback is the successful outcome
* of a Easy Connect flow starting with
- * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
- * Handler,
- * EasyConnectStatusCallback)}.
+ * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String, Executor,
+ * EasyConnectStatusCallback)} .
*
* @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
+ * @hide
*/
+ @SystemApi
public abstract void onEnrolleeSuccess(int newNetworkId);
/**
* Called when a Easy Connect success event takes place, except for when configuration is
- * received from
- * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
- * This callback marks the successful end of the current Easy Connect session, and no further
- * callbacks will be called. This callback is the successful outcome of a Easy Connect flow
- * starting with
- * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int, int, Handler,
- * EasyConnectStatusCallback)}.
+ * received from an external Configurator. The callback onSuccessConfigReceived will be used in
+ * this case. This callback marks the successful end of the current Easy Connect session, and no
+ * further callbacks will be called. This callback is the successful outcome of a Easy Connect
+ * flow starting with {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int,
+ * int, Executor,EasyConnectStatusCallback)}.
*
* @param code Easy Connect success status code.
+ * @hide
*/
+ @SystemApi
public abstract void onConfiguratorSuccess(@EasyConnectSuccessStatusCode int code);
/**
* Called when a Easy Connect Failure event takes place. This callback marks the unsuccessful
- * end of the
- * current Easy Connect session, and no further callbacks will be called.
+ * end of the current Easy Connect session, and no further callbacks will be called.
+ *
+ * @param code Easy Connect failure status code.
+ * @hide
+ */
+ @SystemApi
+ public void onFailure(@EasyConnectFailureStatusCode int code) {}
+
+ /**
+ * Called when a Easy Connect Failure event takes place. This callback marks the unsuccessful
+ * end of the current Easy Connect session, and no further callbacks will be called.
+ *
+ * Note: Easy Connect (DPP) R2, provides additional details for the Configurator when the
+ * remote Enrollee is unable to connect to a network. The ssid, channelList and bandList
+ * inputs are initialized only for the EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK failure
+ * code, and the ssid and bandList are initialized for the
+ * EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION failure code.
*
* @param code Easy Connect failure status code.
+ * @param ssid SSID of the network the Enrollee tried to connect to.
+ * @param channelListArray List of Global Operating classes and channel sets the Enrollee used
+ * to scan to find the network, see the "DPP Connection Status Object"
+ * section in the specification for the format, and Table E-4 in
+ * IEEE Std 802.11-2016 - Global operating classes for more details.
+ * The sparse array key is the Global Operating class, and the value
+ * is an integer array of Wi-Fi channels.
+ * @param operatingClassArray Array of bands the Enrollee supports as expressed as the Global
+ * Operating Class, see Table E-4 in IEEE Std 802.11-2016 - Global
+ * operating classes.
+ * @hide
*/
- public abstract void onFailure(@EasyConnectFailureStatusCode int code);
+ @SystemApi
+ public void onFailure(@EasyConnectFailureStatusCode int code, @Nullable String ssid,
+ @NonNull SparseArray<int[]> channelListArray, @NonNull int[] operatingClassArray) {
+ onFailure(code);
+ }
/**
* Called when Easy Connect events that indicate progress take place. Can be used by UI elements
* to show progress.
*
* @param code Easy Connect progress status code.
+ * @hide
*/
+ @SystemApi
public abstract void onProgress(@EasyConnectProgressStatusCode int code);
}
diff --git a/wifi/java/android/net/wifi/IActionListener.aidl b/wifi/java/android/net/wifi/IActionListener.aidl
new file mode 100644
index 000000000000..faa0901cb087
--- /dev/null
+++ b/wifi/java/android/net/wifi/IActionListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+/**
+ * Interface for generic wifi callbacks.
+ * @hide
+ */
+oneway interface IActionListener
+{
+ void onSuccess();
+ void onFailure(int reason);
+}
diff --git a/wifi/java/android/net/wifi/IDppCallback.aidl b/wifi/java/android/net/wifi/IDppCallback.aidl
index c452c7664c12..d7a958a5b4b1 100644
--- a/wifi/java/android/net/wifi/IDppCallback.aidl
+++ b/wifi/java/android/net/wifi/IDppCallback.aidl
@@ -38,7 +38,7 @@ oneway interface IDppCallback
/**
* Called when DPP Failure events take place.
*/
- void onFailure(int status);
+ void onFailure(int status, String ssid, String channelList, in int[] bandArray);
/**
* Called when DPP events that indicate progress take place. Can be used by UI elements
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl b/wifi/java/android/net/wifi/ILocalOnlyHotspotCallback.aidl
index e923f1f0fee8..b567f29660a7 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl
+++ b/wifi/java/android/net/wifi/ILocalOnlyHotspotCallback.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017, The Android Open Source Project
+ * Copyright (c) 2019, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,17 @@
* limitations under the License.
*/
-package android.net.wifi.hotspot2.pps;
+package android.net.wifi;
-parcelable Policy;
+import android.net.wifi.SoftApConfiguration;
+
+/**
+ * Communicates LOHS status back to the application process.
+ *
+ * @hide
+ */
+oneway interface ILocalOnlyHotspotCallback {
+ void onHotspotStarted(in SoftApConfiguration config);
+ void onHotspotStopped();
+ void onHotspotFailed(int reason);
+}
diff --git a/wifi/java/android/net/wifi/IOnWifiActivityEnergyInfoListener.aidl b/wifi/java/android/net/wifi/IOnWifiActivityEnergyInfoListener.aidl
new file mode 100644
index 000000000000..7e25fd8a3be2
--- /dev/null
+++ b/wifi/java/android/net/wifi/IOnWifiActivityEnergyInfoListener.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.os.connectivity.WifiActivityEnergyInfo;
+
+/**
+ * Interface for Wi-Fi activity energy info listener.
+ *
+ * @hide
+ */
+oneway interface IOnWifiActivityEnergyInfoListener
+{
+ /**
+ * Service to manager callback providing current Wi-Fi activity energy info.
+ * @param info the Wi-Fi activity energy info
+ */
+ void onWifiActivityEnergyInfo(in WifiActivityEnergyInfo info);
+}
diff --git a/wifi/java/android/net/wifi/IScanResultsCallback.aidl b/wifi/java/android/net/wifi/IScanResultsCallback.aidl
new file mode 100644
index 000000000000..56f602510fd9
--- /dev/null
+++ b/wifi/java/android/net/wifi/IScanResultsCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+/**
+ * Interface for Wi-Fi scan result available callback.
+ *
+ * @hide
+ */
+oneway interface IScanResultsCallback
+{
+ void onScanResultsAvailable();
+}
diff --git a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl b/wifi/java/android/net/wifi/IScanResultsListener.aidl
index eb7cc39d5e33..e7eaddd712c9 100644
--- a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl
+++ b/wifi/java/android/net/wifi/IScanResultsListener.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2008, The Android Open Source Project
+/*
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,4 +16,9 @@
package android.net.wifi;
-parcelable PasspointManagementObjectDefinition;
+/** @hide */
+
+oneway interface IScanResultsListener
+{
+ void onScanResultsAvailable();
+}
diff --git a/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
new file mode 100644
index 000000000000..775fed7d47ef
--- /dev/null
+++ b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+/**
+ * Interface for Wi-Fi score callback.
+ *
+ * @hide
+ */
+oneway interface IScoreUpdateObserver
+{
+ void notifyScoreUpdate(int sessionId, int score);
+
+ void triggerUpdateOfWifiUsabilityStats(int sessionId);
+}
diff --git a/wifi/java/android/net/wifi/ISoftApCallback.aidl b/wifi/java/android/net/wifi/ISoftApCallback.aidl
index 8a252dd1e447..f81bcb9e06d7 100644
--- a/wifi/java/android/net/wifi/ISoftApCallback.aidl
+++ b/wifi/java/android/net/wifi/ISoftApCallback.aidl
@@ -15,6 +15,8 @@
*/
package android.net.wifi;
+import android.net.wifi.SoftApCapability;
+import android.net.wifi.SoftApInfo;
import android.net.wifi.WifiClient;
@@ -43,4 +45,27 @@ oneway interface ISoftApCallback
* @param clients the currently connected clients
*/
void onConnectedClientsChanged(in List<WifiClient> clients);
+
+ /**
+ * Service to manager callback providing information of softap.
+ *
+ * @param softApInfo is the softap information. {@link SoftApInfo}
+ */
+ void onInfoChanged(in SoftApInfo softApInfo);
+
+
+ /**
+ * Service to manager callback providing capability of softap.
+ *
+ * @param capability is the softap capability. {@link SoftApCapability}
+ */
+ void onCapabilityChanged(in SoftApCapability capability);
+
+ /**
+ * Service to manager callback providing blocked client of softap with specific reason code.
+ *
+ * @param client the currently blocked client.
+ * @param blockedReason one of blocked reason from {@link WifiManager.SapClientBlockedReason}
+ */
+ void onBlockedClientConnecting(in WifiClient client, int blockedReason);
}
diff --git a/wifi/java/android/net/wifi/ISuggestionConnectionStatusListener.aidl b/wifi/java/android/net/wifi/ISuggestionConnectionStatusListener.aidl
new file mode 100644
index 000000000000..b49e49ba0cd5
--- /dev/null
+++ b/wifi/java/android/net/wifi/ISuggestionConnectionStatusListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.net.wifi.WifiNetworkSuggestion;
+
+/**
+ * Interface for suggestion network connection listener.
+ *
+ * @hide
+ */
+oneway interface ISuggestionConnectionStatusListener
+{
+ void onConnectionStatus(in WifiNetworkSuggestion wifiNetworkSuggestion, int failureReason);
+}
diff --git a/wifi/java/android/net/wifi/ITxPacketCountListener.aidl b/wifi/java/android/net/wifi/ITxPacketCountListener.aidl
new file mode 100644
index 000000000000..9105bd0265cb
--- /dev/null
+++ b/wifi/java/android/net/wifi/ITxPacketCountListener.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+/**
+ * Interface for tx packet counter callback.
+ * @deprecated no longer used, remove once removed from BaseWifiService
+ * @hide
+ */
+oneway interface ITxPacketCountListener
+{
+ void onSuccess(int count);
+ void onFailure(int reason);
+}
diff --git a/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
new file mode 100644
index 000000000000..f96d037cbfea
--- /dev/null
+++ b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.net.wifi.IScoreUpdateObserver;
+
+/**
+ * Interface for Wi-Fi connected network scorer.
+ *
+ * @hide
+ */
+oneway interface IWifiConnectedNetworkScorer
+{
+ void onStart(int sessionId);
+
+ void onStop(int sessionId);
+
+ void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl);
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 9010f3c9943e..5063ad66e446 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -24,14 +24,19 @@ import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.DhcpInfo;
import android.net.Network;
+import android.net.wifi.IActionListener;
import android.net.wifi.IDppCallback;
+import android.net.wifi.ILocalOnlyHotspotCallback;
import android.net.wifi.INetworkRequestMatchCallback;
+import android.net.wifi.IOnWifiActivityEnergyInfoListener;
+import android.net.wifi.IOnWifiUsabilityStatsListener;
+import android.net.wifi.IScanResultsCallback;
import android.net.wifi.ISoftApCallback;
+import android.net.wifi.ISuggestionConnectionStatusListener;
import android.net.wifi.ITrafficStateCallback;
-import android.net.wifi.IOnWifiUsabilityStatsListener;
-import android.net.wifi.PasspointManagementObjectDefinition;
+import android.net.wifi.IWifiConnectedNetworkScorer;
import android.net.wifi.ScanResult;
-import android.net.wifi.WifiActivityEnergyInfo;
+import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiNetworkSuggestion;
@@ -49,19 +54,11 @@ interface IWifiManager
{
long getSupportedFeatures();
- WifiActivityEnergyInfo reportActivityInfo();
-
- /**
- * Requests the controller activity info asynchronously.
- * The implementor is expected to reply with the
- * {@link android.net.wifi.WifiActivityEnergyInfo} object placed into the Bundle with the key
- * {@link android.os.BatteryStats#RESULT_RECEIVER_CONTROLLER_KEY}. The result code is ignored.
- */
- oneway void requestActivityInfo(in ResultReceiver result);
+ oneway void getWifiActivityEnergyInfoAsync(in IOnWifiActivityEnergyInfoListener listener);
- ParceledListSlice getConfiguredNetworks(String packageName);
+ ParceledListSlice getConfiguredNetworks(String packageName, String featureId);
- ParceledListSlice getPrivilegedConfiguredNetworks(String packageName);
+ ParceledListSlice getPrivilegedConfiguredNetworks(String packageName, String featureId);
Map getAllMatchingFqdnsForScanResults(in List<ScanResult> scanResult);
@@ -91,9 +88,19 @@ interface IWifiManager
boolean disableNetwork(int netId, String packageName);
- boolean startScan(String packageName);
+ void allowAutojoinGlobal(boolean choice);
+
+ void allowAutojoin(int netId, boolean choice);
+
+ void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin);
+
+ void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable);
+
+ void setPasspointMeteredOverride(String fqdn, int meteredOverride);
+
+ boolean startScan(String packageName, String featureId);
- List<ScanResult> getScanResults(String callingPackage);
+ List<ScanResult> getScanResults(String callingPackage, String callingFeatureId);
boolean disconnect(String packageName);
@@ -101,22 +108,24 @@ interface IWifiManager
boolean reassociate(String packageName);
- WifiInfo getConnectionInfo(String callingPackage);
+ WifiInfo getConnectionInfo(String callingPackage, String callingFeatureId);
boolean setWifiEnabled(String packageName, boolean enable);
int getWifiEnabledState();
- void setCountryCode(String country);
-
String getCountryCode();
- boolean isDualBandSupported();
+ boolean is5GHzBandSupported();
+
+ boolean is6GHzBandSupported();
- boolean needs5GHzToAnyApBandConversion();
+ boolean isWifiStandardSupported(int standard);
DhcpInfo getDhcpInfo();
+ void setScanAlwaysAvailable(boolean isAvailable);
+
boolean isScanAlwaysAvailable();
boolean acquireWifiLock(IBinder lock, int lockType, String tag, in WorkSource ws);
@@ -137,13 +146,16 @@ interface IWifiManager
boolean startSoftAp(in WifiConfiguration wifiConfig);
+ boolean startTetheredHotspot(in SoftApConfiguration softApConfig);
+
boolean stopSoftAp();
- int startLocalOnlyHotspot(in Messenger messenger, in IBinder binder, String packageName);
+ int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName,
+ String featureId, in SoftApConfiguration customConfig);
void stopLocalOnlyHotspot();
- void startWatchLocalOnlyHotspot(in Messenger messenger, in IBinder binder);
+ void startWatchLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback);
void stopWatchLocalOnlyHotspot();
@@ -153,11 +165,13 @@ interface IWifiManager
@UnsupportedAppUsage
WifiConfiguration getWifiApConfiguration();
+ SoftApConfiguration getSoftApConfiguration();
+
boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
- void notifyUserOfApBandConversion(String packageName);
+ boolean setSoftApConfiguration(in SoftApConfiguration softApConfig, String packageName);
- Messenger getWifiServiceMessenger(String packageName);
+ void notifyUserOfApBandConversion(String packageName);
void enableTdls(String remoteIPAddress, boolean enable);
@@ -169,8 +183,6 @@ interface IWifiManager
int getVerboseLoggingLevel();
- void enableWifiConnectivityManager(boolean enabled);
-
void disableEphemeralNetwork(String SSID, String packageName);
void factoryReset(String packageName);
@@ -182,6 +194,10 @@ interface IWifiManager
void restoreBackupData(in byte[] data);
+ byte[] retrieveSoftApBackupData();
+
+ SoftApConfiguration restoreSoftApBackupData(in byte[] data);
+
void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData);
void startSubscriptionProvisioning(in OsuProvider provider, in IProvisioningCallback callback);
@@ -202,10 +218,13 @@ interface IWifiManager
void unregisterNetworkRequestMatchCallback(int callbackIdentifier);
- int addNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName);
+ int addNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName,
+ in String featureId);
int removeNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName);
+ List<WifiNetworkSuggestion> getNetworkSuggestions(in String packageName);
+
String[] getFactoryMacAddresses();
void setDeviceMobilityState(int state);
@@ -219,4 +238,41 @@ interface IWifiManager
void stopDppSession();
void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec);
+
+ oneway void connect(in WifiConfiguration config, int netId, in IBinder binder, in IActionListener listener, int callbackIdentifier);
+
+ oneway void save(in WifiConfiguration config, in IBinder binder, in IActionListener listener, int callbackIdentifier);
+
+ oneway void forget(int netId, in IBinder binder, in IActionListener listener, int callbackIdentifier);
+
+ void registerScanResultsCallback(in IScanResultsCallback callback);
+
+ void unregisterScanResultsCallback(in IScanResultsCallback callback);
+
+ void registerSuggestionConnectionStatusListener(in IBinder binder, in ISuggestionConnectionStatusListener listener, int listenerIdentifier, String packageName, String featureId);
+
+ void unregisterSuggestionConnectionStatusListener(int listenerIdentifier, String packageName);
+
+ int calculateSignalLevel(int rssi);
+
+ List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(in List<ScanResult> scanResults);
+
+ boolean setWifiConnectedNetworkScorer(in IBinder binder, in IWifiConnectedNetworkScorer scorer);
+
+ void clearWifiConnectedNetworkScorer();
+
+ /**
+ * Return the Map of {@link WifiNetworkSuggestion} and the list of <ScanResult>
+ */
+ Map getMatchingScanResults(in List<WifiNetworkSuggestion> networkSuggestions, in List<ScanResult> scanResults, String callingPackage, String callingFeatureId);
+
+ void setScanThrottleEnabled(boolean enable);
+
+ boolean isScanThrottleEnabled();
+
+ Map getAllMatchingPasspointProfilesForScanResults(in List<ScanResult> scanResult);
+
+ void setAutoWakeupEnabled(boolean enable);
+
+ boolean isAutoWakeupEnabled();
}
diff --git a/wifi/java/android/net/wifi/IWifiScanner.aidl b/wifi/java/android/net/wifi/IWifiScanner.aidl
index 398493439bbe..485f5ce5415e 100644
--- a/wifi/java/android/net/wifi/IWifiScanner.aidl
+++ b/wifi/java/android/net/wifi/IWifiScanner.aidl
@@ -26,5 +26,5 @@ interface IWifiScanner
{
Messenger getMessenger();
- Bundle getAvailableChannels(int band);
+ Bundle getAvailableChannels(int band, String packageName, String featureId);
}
diff --git a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java
deleted file mode 100644
index 70577b9695e5..000000000000
--- a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * This object describes a partial tree structure in the Hotspot 2.0 release 2 management object.
- * The object is used during subscription remediation to modify parts of an existing PPS MO
- * tree (Hotspot 2.0 specification section 9.1).
- * @hide
- */
-public class PasspointManagementObjectDefinition implements Parcelable {
- private final String mBaseUri;
- private final String mUrn;
- private final String mMoTree;
-
- public PasspointManagementObjectDefinition(String baseUri, String urn, String moTree) {
- mBaseUri = baseUri;
- mUrn = urn;
- mMoTree = moTree;
- }
-
- public String getBaseUri() {
- return mBaseUri;
- }
-
- public String getUrn() {
- return mUrn;
- }
-
- public String getMoTree() {
- return mMoTree;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mBaseUri);
- dest.writeString(mUrn);
- dest.writeString(mMoTree);
- }
-
- /**
- * Implement the Parcelable interface {@hide}
- */
- public static final @android.annotation.NonNull Creator<PasspointManagementObjectDefinition> CREATOR =
- new Creator<PasspointManagementObjectDefinition>() {
- public PasspointManagementObjectDefinition createFromParcel(Parcel in) {
- return new PasspointManagementObjectDefinition(
- in.readString(), /* base URI */
- in.readString(), /* URN */
- in.readString() /* Tree XML */
- );
- }
-
- public PasspointManagementObjectDefinition[] newArray(int size) {
- return new PasspointManagementObjectDefinition[size];
- }
- };
-}
-
diff --git a/wifi/java/android/net/wifi/RssiPacketCountInfo.java b/wifi/java/android/net/wifi/RssiPacketCountInfo.java
deleted file mode 100644
index 4301165308d1..000000000000
--- a/wifi/java/android/net/wifi/RssiPacketCountInfo.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Bundle of RSSI and packet count information, for WiFi watchdog
- *
- * @see WifiWatchdogStateMachine
- *
- * @hide
- */
-public class RssiPacketCountInfo implements Parcelable {
-
- public int rssi;
-
- public int txgood;
-
- public int txbad;
-
- public int rxgood;
-
- public RssiPacketCountInfo() {
- rssi = txgood = txbad = rxgood = 0;
- }
-
- private RssiPacketCountInfo(Parcel in) {
- rssi = in.readInt();
- txgood = in.readInt();
- txbad = in.readInt();
- rxgood = in.readInt();
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(rssi);
- out.writeInt(txgood);
- out.writeInt(txbad);
- out.writeInt(rxgood);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<RssiPacketCountInfo> CREATOR =
- new Parcelable.Creator<RssiPacketCountInfo>() {
- @Override
- public RssiPacketCountInfo createFromParcel(Parcel in) {
- return new RssiPacketCountInfo(in);
- }
-
- @Override
- public RssiPacketCountInfo[] newArray(int size) {
- return new RssiPacketCountInfo[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 6a03c73bc3f9..73c52ab0ab1b 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -1212,7 +1212,7 @@ public class RttManager {
*
* @hide
*/
- public RttManager(Context context, WifiRttManager service) {
+ public RttManager(@NonNull Context context, @NonNull WifiRttManager service) {
mNewService = service;
mContext = context;
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 2d0942d3ffa7..aa3a13925894 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -17,8 +17,11 @@
package android.net.wifi;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.wifi.WifiAnnotations.ChannelWidth;
+import android.net.wifi.WifiAnnotations.WifiStandard;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,7 +38,7 @@ import java.util.Objects;
* {@code quality}, {@code noise}, and {@code maxbitrate} attributes,
* but does not currently report them to external clients.
*/
-public class ScanResult implements Parcelable {
+public final class ScanResult implements Parcelable {
/**
* The network name.
*/
@@ -81,16 +84,19 @@ public class ScanResult implements Parcelable {
* @hide
* No security protocol.
*/
+ @SystemApi
public static final int PROTOCOL_NONE = 0;
/**
* @hide
* Security protocol type: WPA version 1.
*/
+ @SystemApi
public static final int PROTOCOL_WPA = 1;
/**
* @hide
* Security protocol type: RSN, for WPA version 2, and version 3.
*/
+ @SystemApi
public static final int PROTOCOL_RSN = 2;
/**
* @hide
@@ -98,99 +104,154 @@ public class ScanResult implements Parcelable {
* OSU Server-only authenticated layer 2 Encryption Network.
* Used for Hotspot 2.0.
*/
+ @SystemApi
public static final int PROTOCOL_OSEN = 3;
/**
* @hide
+ * Security protocol type: WAPI.
+ */
+ @SystemApi
+ public static final int PROTOCOL_WAPI = 4;
+
+ /**
+ * @hide
* No security key management scheme.
*/
+ @SystemApi
public static final int KEY_MGMT_NONE = 0;
/**
* @hide
* Security key management scheme: PSK.
*/
+ @SystemApi
public static final int KEY_MGMT_PSK = 1;
/**
* @hide
* Security key management scheme: EAP.
*/
+ @SystemApi
public static final int KEY_MGMT_EAP = 2;
/**
* @hide
* Security key management scheme: FT_PSK.
*/
+ @SystemApi
public static final int KEY_MGMT_FT_PSK = 3;
/**
* @hide
* Security key management scheme: FT_EAP.
*/
+ @SystemApi
public static final int KEY_MGMT_FT_EAP = 4;
/**
* @hide
* Security key management scheme: PSK_SHA256
*/
+ @SystemApi
public static final int KEY_MGMT_PSK_SHA256 = 5;
/**
* @hide
* Security key management scheme: EAP_SHA256.
*/
+ @SystemApi
public static final int KEY_MGMT_EAP_SHA256 = 6;
/**
* @hide
* Security key management scheme: OSEN.
* Used for Hotspot 2.0.
*/
+ @SystemApi
public static final int KEY_MGMT_OSEN = 7;
/**
* @hide
* Security key management scheme: SAE.
*/
+ @SystemApi
public static final int KEY_MGMT_SAE = 8;
/**
* @hide
* Security key management scheme: OWE.
*/
+ @SystemApi
public static final int KEY_MGMT_OWE = 9;
/**
* @hide
* Security key management scheme: SUITE_B_192.
*/
+ @SystemApi
public static final int KEY_MGMT_EAP_SUITE_B_192 = 10;
/**
* @hide
* Security key management scheme: FT_SAE.
*/
+ @SystemApi
public static final int KEY_MGMT_FT_SAE = 11;
/**
* @hide
* Security key management scheme: OWE in transition mode.
*/
+ @SystemApi
public static final int KEY_MGMT_OWE_TRANSITION = 12;
/**
* @hide
+ * Security key management scheme: WAPI_PSK.
+ */
+ @SystemApi
+ public static final int KEY_MGMT_WAPI_PSK = 13;
+ /**
+ * @hide
+ * Security key management scheme: WAPI_CERT.
+ */
+ @SystemApi
+ public static final int KEY_MGMT_WAPI_CERT = 14;
+
+ /**
+ * @hide
+ * Security key management scheme: FILS_SHA256.
+ */
+ public static final int KEY_MGMT_FILS_SHA256 = 15;
+ /**
+ * @hide
+ * Security key management scheme: FILS_SHA384.
+ */
+ public static final int KEY_MGMT_FILS_SHA384 = 16;
+ /**
+ * @hide
* No cipher suite.
*/
+ @SystemApi
public static final int CIPHER_NONE = 0;
/**
* @hide
* No group addressed, only used for group data cipher.
*/
+ @SystemApi
public static final int CIPHER_NO_GROUP_ADDRESSED = 1;
/**
* @hide
* Cipher suite: TKIP
*/
+ @SystemApi
public static final int CIPHER_TKIP = 2;
/**
* @hide
* Cipher suite: CCMP
*/
+ @SystemApi
public static final int CIPHER_CCMP = 3;
/**
* @hide
* Cipher suite: GCMP
*/
+ @SystemApi
public static final int CIPHER_GCMP_256 = 4;
+ /**
+ * @hide
+ * Cipher suite: SMS4
+ */
+ @SystemApi
+ public static final int CIPHER_SMS4 = 5;
/**
* The detected signal level in dBm, also known as the RSSI.
@@ -226,12 +287,76 @@ public class ScanResult implements Parcelable {
*/
public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
- /**
- * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
- * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
- * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
- */
- public int channelWidth;
+ /**
+ * Wi-Fi unknown standard
+ */
+ public static final int WIFI_STANDARD_UNKNOWN = 0;
+
+ /**
+ * Wi-Fi 802.11a/b/g
+ */
+ public static final int WIFI_STANDARD_LEGACY = 1;
+
+ /**
+ * Wi-Fi 802.11n
+ */
+ public static final int WIFI_STANDARD_11N = 4;
+
+ /**
+ * Wi-Fi 802.11ac
+ */
+ public static final int WIFI_STANDARD_11AC = 5;
+
+ /**
+ * Wi-Fi 802.11ax
+ */
+ public static final int WIFI_STANDARD_11AX = 6;
+
+ /**
+ * AP wifi standard.
+ */
+ private @WifiStandard int mWifiStandard;
+
+ /**
+ * return the AP wifi standard.
+ */
+ public @WifiStandard int getWifiStandard() {
+ return mWifiStandard;
+ }
+
+ /**
+ * sets the AP wifi standard.
+ * @hide
+ */
+ public void setWifiStandard(@WifiStandard int standard) {
+ mWifiStandard = standard;
+ }
+
+ /**
+ * Convert Wi-Fi standard to string
+ */
+ private static @Nullable String wifiStandardToString(@WifiStandard int standard) {
+ switch(standard) {
+ case WIFI_STANDARD_LEGACY:
+ return "legacy";
+ case WIFI_STANDARD_11N:
+ return "11n";
+ case WIFI_STANDARD_11AC:
+ return "11ac";
+ case WIFI_STANDARD_11AX:
+ return "11ax";
+ case WIFI_STANDARD_UNKNOWN:
+ return "unknown";
+ }
+ return null;
+ }
+
+ /**
+ * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
+ * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
+ * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
+ */
+ public @ChannelWidth int channelWidth;
/**
* Not used if the AP bandwidth is 20 MHz
@@ -399,19 +524,166 @@ public class ScanResult implements Parcelable {
* {@hide}
*/
public final static int UNSPECIFIED = -1;
+
/**
+ * 2.4 GHz band first channel number
* @hide
*/
- public boolean is24GHz() {
- return ScanResult.is24GHz(frequency);
+ public static final int BAND_24_GHZ_FIRST_CH_NUM = 1;
+ /**
+ * 2.4 GHz band last channel number
+ * @hide
+ */
+ public static final int BAND_24_GHZ_LAST_CH_NUM = 14;
+ /**
+ * 2.4 GHz band frequency of first channel in MHz
+ * @hide
+ */
+ public static final int BAND_24_GHZ_START_FREQ_MHZ = 2412;
+ /**
+ * 2.4 GHz band frequency of last channel in MHz
+ * @hide
+ */
+ public static final int BAND_24_GHZ_END_FREQ_MHZ = 2484;
+
+ /**
+ * 5 GHz band first channel number
+ * @hide
+ */
+ public static final int BAND_5_GHZ_FIRST_CH_NUM = 32;
+ /**
+ * 5 GHz band last channel number
+ * @hide
+ */
+ public static final int BAND_5_GHZ_LAST_CH_NUM = 173;
+ /**
+ * 5 GHz band frequency of first channel in MHz
+ * @hide
+ */
+ public static final int BAND_5_GHZ_START_FREQ_MHZ = 5160;
+ /**
+ * 5 GHz band frequency of last channel in MHz
+ * @hide
+ */
+ public static final int BAND_5_GHZ_END_FREQ_MHZ = 5865;
+
+ /**
+ * 6 GHz band first channel number
+ * @hide
+ */
+ public static final int BAND_6_GHZ_FIRST_CH_NUM = 1;
+ /**
+ * 6 GHz band last channel number
+ * @hide
+ */
+ public static final int BAND_6_GHZ_LAST_CH_NUM = 233;
+ /**
+ * 6 GHz band frequency of first channel in MHz
+ * @hide
+ */
+ public static final int BAND_6_GHZ_START_FREQ_MHZ = 5945;
+ /**
+ * 6 GHz band frequency of last channel in MHz
+ * @hide
+ */
+ public static final int BAND_6_GHZ_END_FREQ_MHZ = 7105;
+
+ /**
+ * Utility function to check if a frequency within 2.4 GHz band
+ * @param freqMhz frequency in MHz
+ * @return true if within 2.4GHz, false otherwise
+ *
+ * @hide
+ */
+ public static boolean is24GHz(int freqMhz) {
+ return freqMhz >= BAND_24_GHZ_START_FREQ_MHZ && freqMhz <= BAND_24_GHZ_END_FREQ_MHZ;
+ }
+
+ /**
+ * Utility function to check if a frequency within 5 GHz band
+ * @param freqMhz frequency in MHz
+ * @return true if within 5GHz, false otherwise
+ *
+ * @hide
+ */
+ public static boolean is5GHz(int freqMhz) {
+ return freqMhz >= BAND_5_GHZ_START_FREQ_MHZ && freqMhz <= BAND_5_GHZ_END_FREQ_MHZ;
+ }
+
+ /**
+ * Utility function to check if a frequency within 6 GHz band
+ * @param freqMhz
+ * @return true if within 6GHz, false otherwise
+ *
+ * @hide
+ */
+ public static boolean is6GHz(int freqMhz) {
+ return freqMhz >= BAND_6_GHZ_START_FREQ_MHZ && freqMhz <= BAND_6_GHZ_END_FREQ_MHZ;
+ }
+
+ /**
+ * Utility function to convert channel number/band to frequency in MHz
+ * @param channel number to convert
+ * @param band of channel to convert
+ * @return center frequency in Mhz of the channel, {@link UNSPECIFIED} if no match
+ *
+ * @hide
+ */
+ public static int convertChannelToFrequencyMhz(int channel, @WifiScanner.WifiBand int band) {
+ if (band == WifiScanner.WIFI_BAND_24_GHZ) {
+ // Special case
+ if (channel == 14) {
+ return 2484;
+ } else if (channel >= BAND_24_GHZ_FIRST_CH_NUM && channel <= BAND_24_GHZ_LAST_CH_NUM) {
+ return ((channel - BAND_24_GHZ_FIRST_CH_NUM) * 5) + BAND_24_GHZ_START_FREQ_MHZ;
+ } else {
+ return UNSPECIFIED;
+ }
+ }
+ if (band == WifiScanner.WIFI_BAND_5_GHZ) {
+ if (channel >= BAND_5_GHZ_FIRST_CH_NUM && channel <= BAND_5_GHZ_LAST_CH_NUM) {
+ return ((channel - BAND_5_GHZ_FIRST_CH_NUM) * 5) + BAND_5_GHZ_START_FREQ_MHZ;
+ } else {
+ return UNSPECIFIED;
+ }
+ }
+ if (band == WifiScanner.WIFI_BAND_6_GHZ) {
+ if (channel >= BAND_6_GHZ_FIRST_CH_NUM && channel <= BAND_6_GHZ_LAST_CH_NUM) {
+ return ((channel - BAND_6_GHZ_FIRST_CH_NUM) * 5) + BAND_6_GHZ_START_FREQ_MHZ;
+ } else {
+ return UNSPECIFIED;
+ }
+ }
+ return UNSPECIFIED;
+ }
+
+ /**
+ * Utility function to convert frequency in MHz to channel number
+ * @param freqMhz frequency in MHz
+ * @return channel number associated with given frequency, {@link UNSPECIFIED} if no match
+ *
+ * @hide
+ */
+ public static int convertFrequencyMhzToChannel(int freqMhz) {
+ // Special case
+ if (freqMhz == 2484) {
+ return 14;
+ } else if (is24GHz(freqMhz)) {
+ return (freqMhz - BAND_24_GHZ_START_FREQ_MHZ) / 5 + BAND_24_GHZ_FIRST_CH_NUM;
+ } else if (is5GHz(freqMhz)) {
+ return ((freqMhz - BAND_5_GHZ_START_FREQ_MHZ) / 5) + BAND_5_GHZ_FIRST_CH_NUM;
+ } else if (is6GHz(freqMhz)) {
+ return ((freqMhz - BAND_6_GHZ_START_FREQ_MHZ) / 5) + BAND_6_GHZ_FIRST_CH_NUM;
+ }
+
+ return UNSPECIFIED;
}
/**
* @hide
- * TODO: makes real freq boundaries
*/
- public static boolean is24GHz(int freq) {
- return freq > 2400 && freq < 2500;
+ public boolean is24GHz() {
+ return ScanResult.is24GHz(frequency);
}
/**
@@ -423,10 +695,9 @@ public class ScanResult implements Parcelable {
/**
* @hide
- * TODO: makes real freq boundaries
*/
- public static boolean is5GHz(int freq) {
- return freq > 4900 && freq < 5900;
+ public boolean is6GHz() {
+ return ScanResult.is6GHz(frequency);
}
/**
@@ -483,11 +754,22 @@ public class ScanResult implements Parcelable {
/** @hide */
@UnsupportedAppUsage
public static final int EID_VSA = 221;
+ /** @hide */
+ public static final int EID_EXTENSION_PRESENT = 255;
+
+ // Extension IDs
+ /** @hide */
+ public static final int EID_EXT_HE_CAPABILITIES = 35;
+ /** @hide */
+ public static final int EID_EXT_HE_OPERATION = 36;
/** @hide */
@UnsupportedAppUsage
public int id;
/** @hide */
+ public int idExt;
+
+ /** @hide */
@UnsupportedAppUsage
public byte[] bytes;
@@ -497,6 +779,7 @@ public class ScanResult implements Parcelable {
public InformationElement(@NonNull InformationElement rhs) {
this.id = rhs.id;
+ this.idExt = rhs.idExt;
this.bytes = rhs.bytes.clone();
}
@@ -509,6 +792,14 @@ public class ScanResult implements Parcelable {
}
/**
+ * The element ID Extension of the information element. Defined in the IEEE 802.11-2016 spec
+ * Table 9-77.
+ */
+ public int getIdExt() {
+ return idExt;
+ }
+
+ /**
* Get the specific content of the information element.
*/
@NonNull
@@ -536,33 +827,11 @@ public class ScanResult implements Parcelable {
*/
public AnqpInformationElement[] anqpElements;
- /**
- * Flag indicating if this AP is a carrier AP. The determination is based
- * on the AP's SSID and if AP is using EAP security.
- *
- * @hide
- */
- public boolean isCarrierAp;
-
- /**
- * The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP.
- *
- * @hide
- */
- public int carrierApEapType;
-
- /**
- * The name of the carrier that's associated with this AP if it is a carrier AP.
- *
- * @hide
- */
- public String carrierName;
-
/** {@hide} */
public ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId,
byte[] osuProviders, String caps, int level, int frequency, long tsf) {
this.wifiSsid = wifiSsid;
- this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
+ this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiManager.UNKNOWN_SSID;
this.BSSID = BSSID;
this.hessid = hessid;
this.anqpDomainId = anqpDomainId;
@@ -582,17 +851,15 @@ public class ScanResult implements Parcelable {
this.centerFreq0 = UNSPECIFIED;
this.centerFreq1 = UNSPECIFIED;
this.flags = 0;
- this.isCarrierAp = false;
- this.carrierApEapType = UNSPECIFIED;
- this.carrierName = null;
this.radioChainInfos = null;
+ this.mWifiStandard = WIFI_STANDARD_UNKNOWN;
}
/** {@hide} */
public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
long tsf, int distCm, int distSdCm) {
this.wifiSsid = wifiSsid;
- this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
+ this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiManager.UNKNOWN_SSID;
this.BSSID = BSSID;
this.capabilities = caps;
this.level = level;
@@ -604,10 +871,8 @@ public class ScanResult implements Parcelable {
this.centerFreq0 = UNSPECIFIED;
this.centerFreq1 = UNSPECIFIED;
this.flags = 0;
- this.isCarrierAp = false;
- this.carrierApEapType = UNSPECIFIED;
- this.carrierName = null;
this.radioChainInfos = null;
+ this.mWifiStandard = WIFI_STANDARD_UNKNOWN;
}
/** {@hide} */
@@ -633,10 +898,8 @@ public class ScanResult implements Parcelable {
} else {
this.flags = 0;
}
- this.isCarrierAp = false;
- this.carrierApEapType = UNSPECIFIED;
- this.carrierName = null;
this.radioChainInfos = null;
+ this.mWifiStandard = WIFI_STANDARD_UNKNOWN;
}
/** {@hide} */
@@ -674,17 +937,12 @@ public class ScanResult implements Parcelable {
venueName = source.venueName;
operatorFriendlyName = source.operatorFriendlyName;
flags = source.flags;
- isCarrierAp = source.isCarrierAp;
- carrierApEapType = source.carrierApEapType;
- carrierName = source.carrierName;
radioChainInfos = source.radioChainInfos;
+ this.mWifiStandard = source.mWifiStandard;
}
}
- /** empty scan result
- *
- * {@hide}
- * */
+ /** Construct an empty scan result. */
public ScanResult() {
}
@@ -693,19 +951,18 @@ public class ScanResult implements Parcelable {
StringBuffer sb = new StringBuffer();
String none = "<none>";
- sb.append("SSID: ").
- append(wifiSsid == null ? WifiSsid.NONE : wifiSsid).
- append(", BSSID: ").
- append(BSSID == null ? none : BSSID).
- append(", capabilities: ").
- append(capabilities == null ? none : capabilities).
- append(", level: ").
- append(level).
- append(", frequency: ").
- append(frequency).
- append(", timestamp: ").
- append(timestamp);
-
+ sb.append("SSID: ")
+ .append(wifiSsid == null ? WifiManager.UNKNOWN_SSID : wifiSsid)
+ .append(", BSSID: ")
+ .append(BSSID == null ? none : BSSID)
+ .append(", capabilities: ")
+ .append(capabilities == null ? none : capabilities)
+ .append(", level: ")
+ .append(level)
+ .append(", frequency: ")
+ .append(frequency)
+ .append(", timestamp: ")
+ .append(timestamp);
sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")).
append("(cm)");
sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
@@ -716,11 +973,9 @@ public class ScanResult implements Parcelable {
sb.append(", ChannelBandwidth: ").append(channelWidth);
sb.append(", centerFreq0: ").append(centerFreq0);
sb.append(", centerFreq1: ").append(centerFreq1);
+ sb.append(", standard: ").append(wifiStandardToString(mWifiStandard));
sb.append(", 80211mcResponder: ");
sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported");
- sb.append(", Carrier AP: ").append(isCarrierAp ? "yes" : "no");
- sb.append(", Carrier AP EAP Type: ").append(carrierApEapType);
- sb.append(", Carrier name: ").append(carrierName);
sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos));
return sb.toString();
}
@@ -751,6 +1006,7 @@ public class ScanResult implements Parcelable {
dest.writeInt(channelWidth);
dest.writeInt(centerFreq0);
dest.writeInt(centerFreq1);
+ dest.writeInt(mWifiStandard);
dest.writeLong(seen);
dest.writeInt(untrusted ? 1 : 0);
dest.writeInt(numUsage);
@@ -762,6 +1018,7 @@ public class ScanResult implements Parcelable {
dest.writeInt(informationElements.length);
for (int i = 0; i < informationElements.length; i++) {
dest.writeInt(informationElements[i].id);
+ dest.writeInt(informationElements[i].idExt);
dest.writeInt(informationElements[i].bytes.length);
dest.writeByteArray(informationElements[i].bytes);
}
@@ -789,9 +1046,6 @@ public class ScanResult implements Parcelable {
} else {
dest.writeInt(0);
}
- dest.writeInt(isCarrierAp ? 1 : 0);
- dest.writeInt(carrierApEapType);
- dest.writeString(carrierName);
if (radioChainInfos != null) {
dest.writeInt(radioChainInfos.length);
@@ -831,6 +1085,7 @@ public class ScanResult implements Parcelable {
fixed with flags below */
);
+ sr.mWifiStandard = in.readInt();
sr.seen = in.readLong();
sr.untrusted = in.readInt() != 0;
sr.numUsage = in.readInt();
@@ -843,6 +1098,7 @@ public class ScanResult implements Parcelable {
for (int i = 0; i < n; i++) {
sr.informationElements[i] = new InformationElement();
sr.informationElements[i].id = in.readInt();
+ sr.informationElements[i].idExt = in.readInt();
int len = in.readInt();
sr.informationElements[i].bytes = new byte[len];
in.readByteArray(sr.informationElements[i].bytes);
@@ -869,9 +1125,6 @@ public class ScanResult implements Parcelable {
new AnqpInformationElement(vendorId, elementId, payload);
}
}
- sr.isCarrierAp = in.readInt() != 0;
- sr.carrierApEapType = in.readInt();
- sr.carrierName = in.readString();
n = in.readInt();
if (n != 0) {
sr.radioChainInfos = new RadioChainInfo[n];
diff --git a/wifi/java/android/net/wifi/SoftApCapability.java b/wifi/java/android/net/wifi/SoftApCapability.java
new file mode 100644
index 000000000000..dcb57ecc933f
--- /dev/null
+++ b/wifi/java/android/net/wifi/SoftApCapability.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.annotation.LongDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * A class representing capability of the SoftAp.
+ * {@see WifiManager}
+ *
+ * @hide
+ */
+@SystemApi
+public final class SoftApCapability implements Parcelable {
+
+ /**
+ * Support for automatic channel selection in driver (ACS).
+ * Driver will auto select best channel based on interference to optimize performance.
+ *
+ * flag when {@link R.bool.config_wifi_softap_acs_supported)} is true.
+ *
+ * <p>
+ * Use {@link WifiManager.SoftApCallback#onInfoChanged(SoftApInfo)} and
+ * {@link SoftApInfo#getFrequency} and {@link SoftApInfo#getBandwidth} to get
+ * driver channel selection result.
+ */
+ public static final long SOFTAP_FEATURE_ACS_OFFLOAD = 1 << 0;
+
+ /**
+ * Support for client force disconnect.
+ * flag when {@link R.bool.config_wifi_sofap_client_force_disconnect_supported)} is true
+ *
+ * <p>
+ * Several Soft AP client control features, e.g. specifying the maximum number of
+ * Soft AP clients, only work when this feature support is present.
+ * Check feature support before invoking
+ * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
+ */
+ public static final long SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 1 << 1;
+
+
+ /**
+ * Support for WPA3 Simultaneous Authentication of Equals (WPA3-SAE).
+ *
+ * flag when {@link config_wifi_softap_sae_supported)} is true.
+ */
+ public static final long SOFTAP_FEATURE_WPA3_SAE = 1 << 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @LongDef(flag = true, prefix = { "SOFTAP_FEATURE_" }, value = {
+ SOFTAP_FEATURE_ACS_OFFLOAD,
+ SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT,
+ SOFTAP_FEATURE_WPA3_SAE,
+ })
+ public @interface HotspotFeatures {}
+
+ private @HotspotFeatures long mSupportedFeatures = 0;
+
+ private int mMaximumSupportedClientNumber;
+
+ /**
+ * Get the maximum supported client numbers which AP resides on.
+ */
+ public int getMaxSupportedClients() {
+ return mMaximumSupportedClientNumber;
+ }
+
+ /**
+ * Set the maximum supported client numbers which AP resides on.
+ *
+ * @param maxClient maximum supported client numbers for the softap.
+ * @hide
+ */
+ public void setMaxSupportedClients(int maxClient) {
+ mMaximumSupportedClientNumber = maxClient;
+ }
+
+ /**
+ * Returns true when all of the queried features are supported, otherwise false.
+ *
+ * @param features One or combination of the following features:
+ * {@link #SOFTAP_FEATURE_ACS_OFFLOAD}, {@link #SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} or
+ * {@link #SOFTAP_FEATURE_WPA3_SAE}.
+ */
+ public boolean areFeaturesSupported(@HotspotFeatures long features) {
+ return (mSupportedFeatures & features) == features;
+ }
+
+ /**
+ * @hide
+ */
+ public SoftApCapability(@Nullable SoftApCapability source) {
+ if (source != null) {
+ mSupportedFeatures = source.mSupportedFeatures;
+ mMaximumSupportedClientNumber = source.mMaximumSupportedClientNumber;
+ }
+ }
+
+ /**
+ * Constructor with combination of the feature.
+ * Zero to no supported feature.
+ *
+ * @param features One or combination of the following features:
+ * {@link #SOFTAP_FEATURE_ACS_OFFLOAD}, {@link #SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} or
+ * {@link #SOFTAP_FEATURE_WPA3_SAE}.
+ * @hide
+ */
+ public SoftApCapability(@HotspotFeatures long features) {
+ mSupportedFeatures = features;
+ }
+
+ @Override
+ /** Implement the Parcelable interface. */
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ /** Implement the Parcelable interface */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeLong(mSupportedFeatures);
+ dest.writeInt(mMaximumSupportedClientNumber);
+ }
+
+ @NonNull
+ /** Implement the Parcelable interface */
+ public static final Creator<SoftApCapability> CREATOR = new Creator<SoftApCapability>() {
+ public SoftApCapability createFromParcel(Parcel in) {
+ long supportedFeatures = in.readLong();
+ SoftApCapability capability = new SoftApCapability(supportedFeatures);
+ capability.mMaximumSupportedClientNumber = in.readInt();
+ return capability;
+ }
+
+ public SoftApCapability[] newArray(int size) {
+ return new SoftApCapability[size];
+ }
+ };
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append("SupportedFeatures=").append(mSupportedFeatures);
+ sbuf.append("MaximumSupportedClientNumber=").append(mMaximumSupportedClientNumber);
+ return sbuf.toString();
+ }
+
+ @Override
+ public boolean equals(@NonNull Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SoftApCapability)) return false;
+ SoftApCapability capability = (SoftApCapability) o;
+ return mSupportedFeatures == capability.mSupportedFeatures
+ && mMaximumSupportedClientNumber == capability.mMaximumSupportedClientNumber;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSupportedFeatures, mMaximumSupportedClientNumber);
+ }
+}
diff --git a/wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java b/wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java
new file mode 100755
index 000000000000..c5472ce34478
--- /dev/null
+++ b/wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static android.os.Environment.getDataMiscDirectory;
+
+import android.annotation.Nullable;
+import android.net.MacAddress;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Utility class to convert the legacy softap.conf file format to the new XML format.
+ * Note:
+ * <li>This should be modified by the OEM if they want to migrate configuration for existing
+ * devices for new softap features supported by AOSP in Android 11.
+ * For ex: client allowlist/blocklist feature was already supported by some OEM's before Android 10
+ * while AOSP only supported it in Android 11. </li>
+ * <li>Most of this class was copied over from WifiApConfigStore class in Android 10 and
+ * SoftApStoreData class in Android 11</li>
+ * @hide
+ */
+public final class SoftApConfToXmlMigrationUtil {
+ private static final String TAG = "SoftApConfToXmlMigrationUtil";
+
+ /**
+ * Directory to read the wifi config store files from under.
+ */
+ private static final String LEGACY_WIFI_STORE_DIRECTORY_NAME = "wifi";
+ /**
+ * The legacy Softap config file which contained key/value pairs.
+ */
+ private static final String LEGACY_AP_CONFIG_FILE = "softap.conf";
+
+ /**
+ * Pre-apex wifi shared folder.
+ */
+ private static File getLegacyWifiSharedDirectory() {
+ return new File(getDataMiscDirectory(), LEGACY_WIFI_STORE_DIRECTORY_NAME);
+ }
+
+ /* @hide constants copied from WifiConfiguration */
+ /**
+ * 2GHz band.
+ */
+ private static final int WIFICONFIG_AP_BAND_2GHZ = 0;
+ /**
+ * 5GHz band.
+ */
+ private static final int WIFICONFIG_AP_BAND_5GHZ = 1;
+ /**
+ * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
+ * operating country code and current radio conditions.
+ */
+ private static final int WIFICONFIG_AP_BAND_ANY = -1;
+ /**
+ * Convert band from WifiConfiguration into SoftApConfiguration
+ *
+ * @param wifiConfigBand band encoded as WIFICONFIG_AP_BAND_xxxx
+ * @return band as encoded as SoftApConfiguration.BAND_xxx
+ */
+ @VisibleForTesting
+ public static int convertWifiConfigBandToSoftApConfigBand(int wifiConfigBand) {
+ switch (wifiConfigBand) {
+ case WIFICONFIG_AP_BAND_2GHZ:
+ return SoftApConfiguration.BAND_2GHZ;
+ case WIFICONFIG_AP_BAND_5GHZ:
+ return SoftApConfiguration.BAND_5GHZ;
+ case WIFICONFIG_AP_BAND_ANY:
+ return SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ;
+ default:
+ return SoftApConfiguration.BAND_2GHZ;
+ }
+ }
+
+ /**
+ * Load AP configuration from legacy persistent storage.
+ * Note: This is deprecated and only used for migrating data once on reboot.
+ */
+ private static SoftApConfiguration loadFromLegacyFile(InputStream fis) {
+ SoftApConfiguration config = null;
+ DataInputStream in = null;
+ try {
+ SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
+ in = new DataInputStream(new BufferedInputStream(fis));
+
+ int version = in.readInt();
+ if (version < 1 || version > 3) {
+ Log.e(TAG, "Bad version on hotspot configuration file");
+ return null;
+ }
+ configBuilder.setSsid(in.readUTF());
+
+ if (version >= 2) {
+ int band = in.readInt();
+ int channel = in.readInt();
+ if (channel == 0) {
+ configBuilder.setBand(
+ convertWifiConfigBandToSoftApConfigBand(band));
+ } else {
+ configBuilder.setChannel(channel,
+ convertWifiConfigBandToSoftApConfigBand(band));
+ }
+ }
+ if (version >= 3) {
+ configBuilder.setHiddenSsid(in.readBoolean());
+ }
+ int authType = in.readInt();
+ if (authType == WifiConfiguration.KeyMgmt.WPA2_PSK) {
+ configBuilder.setPassphrase(in.readUTF(),
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ }
+ config = configBuilder.build();
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading hotspot configuration ", e);
+ config = null;
+ } catch (IllegalArgumentException ie) {
+ Log.e(TAG, "Invalid hotspot configuration ", ie);
+ config = null;
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Error closing hotspot configuration during read", e);
+ }
+ }
+ }
+ // NOTE: OEM's should add their customized parsing code here.
+ return config;
+ }
+
+ // This is the version that Android 11 released with.
+ private static final int CONFIG_STORE_DATA_VERSION = 3;
+
+ private static final String XML_TAG_DOCUMENT_HEADER = "WifiConfigStoreData";
+ private static final String XML_TAG_VERSION = "Version";
+ private static final String XML_TAG_SECTION_HEADER_SOFTAP = "SoftAp";
+ private static final String XML_TAG_SSID = "SSID";
+ private static final String XML_TAG_BSSID = "Bssid";
+ private static final String XML_TAG_CHANNEL = "Channel";
+ private static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
+ private static final String XML_TAG_SECURITY_TYPE = "SecurityType";
+ private static final String XML_TAG_AP_BAND = "ApBand";
+ private static final String XML_TAG_PASSPHRASE = "Passphrase";
+ private static final String XML_TAG_MAX_NUMBER_OF_CLIENTS = "MaxNumberOfClients";
+ private static final String XML_TAG_AUTO_SHUTDOWN_ENABLED = "AutoShutdownEnabled";
+ private static final String XML_TAG_SHUTDOWN_TIMEOUT_MILLIS = "ShutdownTimeoutMillis";
+ private static final String XML_TAG_CLIENT_CONTROL_BY_USER = "ClientControlByUser";
+ private static final String XML_TAG_BLOCKED_CLIENT_LIST = "BlockedClientList";
+ private static final String XML_TAG_ALLOWED_CLIENT_LIST = "AllowedClientList";
+ public static final String XML_TAG_CLIENT_MACADDRESS = "ClientMacAddress";
+
+ private static byte[] convertConfToXml(SoftApConfiguration softApConf) {
+ try {
+ final XmlSerializer out = new FastXmlSerializer();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+
+ // Header for the XML file.
+ out.startDocument(null, true);
+ out.startTag(null, XML_TAG_DOCUMENT_HEADER);
+ XmlUtils.writeValueXml(CONFIG_STORE_DATA_VERSION, XML_TAG_VERSION, out);
+ out.startTag(null, XML_TAG_SECTION_HEADER_SOFTAP);
+
+ // SoftAp conf
+ XmlUtils.writeValueXml(softApConf.getSsid(), XML_TAG_SSID, out);
+ if (softApConf.getBssid() != null) {
+ XmlUtils.writeValueXml(softApConf.getBssid().toString(), XML_TAG_BSSID, out);
+ }
+ XmlUtils.writeValueXml(softApConf.getBand(), XML_TAG_AP_BAND, out);
+ XmlUtils.writeValueXml(softApConf.getChannel(), XML_TAG_CHANNEL, out);
+ XmlUtils.writeValueXml(softApConf.isHiddenSsid(), XML_TAG_HIDDEN_SSID, out);
+ XmlUtils.writeValueXml(softApConf.getSecurityType(), XML_TAG_SECURITY_TYPE, out);
+ if (softApConf.getSecurityType() != SoftApConfiguration.SECURITY_TYPE_OPEN) {
+ XmlUtils.writeValueXml(softApConf.getPassphrase(), XML_TAG_PASSPHRASE, out);
+ }
+ XmlUtils.writeValueXml(softApConf.getMaxNumberOfClients(),
+ XML_TAG_MAX_NUMBER_OF_CLIENTS, out);
+ XmlUtils.writeValueXml(softApConf.isClientControlByUserEnabled(),
+ XML_TAG_CLIENT_CONTROL_BY_USER, out);
+ XmlUtils.writeValueXml(softApConf.isAutoShutdownEnabled(),
+ XML_TAG_AUTO_SHUTDOWN_ENABLED, out);
+ XmlUtils.writeValueXml(softApConf.getShutdownTimeoutMillis(),
+ XML_TAG_SHUTDOWN_TIMEOUT_MILLIS, out);
+ out.startTag(null, XML_TAG_BLOCKED_CLIENT_LIST);
+ for (MacAddress mac: softApConf.getBlockedClientList()) {
+ XmlUtils.writeValueXml(mac.toString(), XML_TAG_CLIENT_MACADDRESS, out);
+ }
+ out.endTag(null, XML_TAG_BLOCKED_CLIENT_LIST);
+ out.startTag(null, XML_TAG_ALLOWED_CLIENT_LIST);
+ for (MacAddress mac: softApConf.getAllowedClientList()) {
+ XmlUtils.writeValueXml(mac.toString(), XML_TAG_CLIENT_MACADDRESS, out);
+ }
+ out.endTag(null, XML_TAG_ALLOWED_CLIENT_LIST);
+
+ // Footer for the XML file.
+ out.endTag(null, XML_TAG_SECTION_HEADER_SOFTAP);
+ out.endTag(null, XML_TAG_DOCUMENT_HEADER);
+ out.endDocument();
+
+ return outputStream.toByteArray();
+ } catch (IOException | XmlPullParserException e) {
+ Log.e(TAG, "Failed to convert softap conf to XML", e);
+ return null;
+ }
+ }
+
+ private SoftApConfToXmlMigrationUtil() { }
+
+ /**
+ * Read the legacy /data/misc/wifi/softap.conf file format and convert to the new XML
+ * format understood by WifiConfigStore.
+ * Note: Used for unit testing.
+ */
+ @VisibleForTesting
+ @Nullable
+ public static InputStream convert(InputStream fis) {
+ SoftApConfiguration softApConf = loadFromLegacyFile(fis);
+ if (softApConf == null) return null;
+
+ byte[] xmlBytes = convertConfToXml(softApConf);
+ if (xmlBytes == null) return null;
+
+ return new ByteArrayInputStream(xmlBytes);
+ }
+
+ /**
+ * Read the legacy /data/misc/wifi/softap.conf file format and convert to the new XML
+ * format understood by WifiConfigStore.
+ */
+ @Nullable
+ public static InputStream convert() {
+ File file = new File(getLegacyWifiSharedDirectory(), LEGACY_AP_CONFIG_FILE);
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(file);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ if (fis == null) return null;
+ return convert(fis);
+ }
+
+ /**
+ * Remove the legacy /data/misc/wifi/softap.conf file.
+ */
+ @Nullable
+ public static void remove() {
+ File file = new File(getLegacyWifiSharedDirectory(), LEGACY_AP_CONFIG_FILE);
+ file.delete();
+ }
+}
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
new file mode 100644
index 000000000000..a5e76e6c92ee
--- /dev/null
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -0,0 +1,972 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.net.MacAddress;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
+ *
+ * This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the
+ * framework how it should configure a hotspot.
+ *
+ * System apps can use this to configure a tethered hotspot using
+ * {@code WifiManager#startTetheredHotspot(SoftApConfiguration)} and
+ * {@code WifiManager#setSoftApConfiguration(SoftApConfiguration)}
+ * or local-only hotspot using
+ * {@code WifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor,
+ * WifiManager.LocalOnlyHotspotCallback)}.
+ *
+ * Instances of this class are immutable; use {@link SoftApConfiguration.Builder} and its methods to
+ * create a new instance.
+ *
+ */
+public final class SoftApConfiguration implements Parcelable {
+
+ private static final String TAG = "SoftApConfiguration";
+
+ @VisibleForTesting
+ static final int PSK_MIN_LEN = 8;
+
+ @VisibleForTesting
+ static final int PSK_MAX_LEN = 63;
+
+ /**
+ * 2GHz band.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_2GHZ = 1 << 0;
+
+ /**
+ * 5GHz band.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_5GHZ = 1 << 1;
+
+ /**
+ * 6GHz band.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_6GHZ = 1 << 2;
+
+ /**
+ * Device is allowed to choose the optimal band (2Ghz, 5Ghz, 6Ghz) based on device capability,
+ * operating country code and current radio conditions.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_ANY = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "BAND_TYPE_" }, value = {
+ BAND_2GHZ,
+ BAND_5GHZ,
+ BAND_6GHZ,
+ })
+ public @interface BandType {}
+
+ private static boolean isBandValid(@BandType int band) {
+ return ((band != 0) && ((band & ~BAND_ANY) == 0));
+ }
+
+ private static final int MIN_CH_2G_BAND = 1;
+ private static final int MAX_CH_2G_BAND = 14;
+ private static final int MIN_CH_5G_BAND = 34;
+ private static final int MAX_CH_5G_BAND = 196;
+ private static final int MIN_CH_6G_BAND = 1;
+ private static final int MAX_CH_6G_BAND = 253;
+
+
+
+ private static boolean isChannelBandPairValid(int channel, @BandType int band) {
+ switch (band) {
+ case BAND_2GHZ:
+ if (channel < MIN_CH_2G_BAND || channel > MAX_CH_2G_BAND) {
+ return false;
+ }
+ break;
+
+ case BAND_5GHZ:
+ if (channel < MIN_CH_5G_BAND || channel > MAX_CH_5G_BAND) {
+ return false;
+ }
+ break;
+
+ case BAND_6GHZ:
+ if (channel < MIN_CH_6G_BAND || channel > MAX_CH_6G_BAND) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * SSID for the AP, or null for a framework-determined SSID.
+ */
+ private final @Nullable String mSsid;
+
+ /**
+ * BSSID for the AP, or null to use a framework-determined BSSID.
+ */
+ private final @Nullable MacAddress mBssid;
+
+ /**
+ * Pre-shared key for WPA2-PSK or WPA3-SAE-Transition or WPA3-SAE encryption which depends on
+ * the security type.
+ */
+ private final @Nullable String mPassphrase;
+
+ /**
+ * This is a network that does not broadcast its SSID, so an
+ * SSID-specific probe request must be used for scans.
+ */
+ private final boolean mHiddenSsid;
+
+ /**
+ * The operating band of the AP.
+ * One or combination of the following band type:
+ * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
+ */
+ private final @BandType int mBand;
+
+ /**
+ * The operating channel of the AP.
+ */
+ private final int mChannel;
+
+ /**
+ * The maximim allowed number of clients that can associate to the AP.
+ */
+ private final int mMaxNumberOfClients;
+
+ /**
+ * The operating security type of the AP.
+ * One of the following security types:
+ * {@link #SECURITY_TYPE_OPEN},
+ * {@link #SECURITY_TYPE_WPA2_PSK},
+ * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
+ * {@link #SECURITY_TYPE_WPA3_SAE}
+ */
+ private final @SecurityType int mSecurityType;
+
+ /**
+ * The flag to indicate client need to authorize by user
+ * when client is connecting to AP.
+ */
+ private final boolean mClientControlByUser;
+
+ /**
+ * The list of blocked client that can't associate to the AP.
+ */
+ private final List<MacAddress> mBlockedClientList;
+
+ /**
+ * The list of allowed client that can associate to the AP.
+ */
+ private final List<MacAddress> mAllowedClientList;
+
+ /**
+ * Whether auto shutdown of soft AP is enabled or not.
+ */
+ private final boolean mAutoShutdownEnabled;
+
+ /**
+ * Delay in milliseconds before shutting down soft AP when
+ * there are no connected devices.
+ */
+ private final long mShutdownTimeoutMillis;
+
+ /**
+ * THe definition of security type OPEN.
+ */
+ public static final int SECURITY_TYPE_OPEN = 0;
+
+ /**
+ * The definition of security type WPA2-PSK.
+ */
+ public static final int SECURITY_TYPE_WPA2_PSK = 1;
+
+ /**
+ * The definition of security type WPA3-SAE Transition mode.
+ */
+ public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2;
+
+ /**
+ * The definition of security type WPA3-SAE.
+ */
+ public static final int SECURITY_TYPE_WPA3_SAE = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "SECURITY_TYPE_" }, value = {
+ SECURITY_TYPE_OPEN,
+ SECURITY_TYPE_WPA2_PSK,
+ SECURITY_TYPE_WPA3_SAE_TRANSITION,
+ SECURITY_TYPE_WPA3_SAE,
+ })
+ public @interface SecurityType {}
+
+ /** Private constructor for Builder and Parcelable implementation. */
+ private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
+ @Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel,
+ @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled,
+ long shutdownTimeoutMillis, boolean clientControlByUser,
+ @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList) {
+ mSsid = ssid;
+ mBssid = bssid;
+ mPassphrase = passphrase;
+ mHiddenSsid = hiddenSsid;
+ mBand = band;
+ mChannel = channel;
+ mSecurityType = securityType;
+ mMaxNumberOfClients = maxNumberOfClients;
+ mAutoShutdownEnabled = shutdownTimeoutEnabled;
+ mShutdownTimeoutMillis = shutdownTimeoutMillis;
+ mClientControlByUser = clientControlByUser;
+ mBlockedClientList = new ArrayList<>(blockedList);
+ mAllowedClientList = new ArrayList<>(allowedList);
+ }
+
+ @Override
+ public boolean equals(Object otherObj) {
+ if (this == otherObj) {
+ return true;
+ }
+ if (!(otherObj instanceof SoftApConfiguration)) {
+ return false;
+ }
+ SoftApConfiguration other = (SoftApConfiguration) otherObj;
+ return Objects.equals(mSsid, other.mSsid)
+ && Objects.equals(mBssid, other.mBssid)
+ && Objects.equals(mPassphrase, other.mPassphrase)
+ && mHiddenSsid == other.mHiddenSsid
+ && mBand == other.mBand
+ && mChannel == other.mChannel
+ && mSecurityType == other.mSecurityType
+ && mMaxNumberOfClients == other.mMaxNumberOfClients
+ && mAutoShutdownEnabled == other.mAutoShutdownEnabled
+ && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis
+ && mClientControlByUser == other.mClientControlByUser
+ && Objects.equals(mBlockedClientList, other.mBlockedClientList)
+ && Objects.equals(mAllowedClientList, other.mAllowedClientList);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid,
+ mBand, mChannel, mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled,
+ mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList,
+ mAllowedClientList);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append("ssid=").append(mSsid);
+ if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString());
+ sbuf.append(" \n Passphrase =").append(
+ TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>");
+ sbuf.append(" \n HiddenSsid =").append(mHiddenSsid);
+ sbuf.append(" \n Band =").append(mBand);
+ sbuf.append(" \n Channel =").append(mChannel);
+ sbuf.append(" \n SecurityType=").append(getSecurityType());
+ sbuf.append(" \n MaxClient=").append(mMaxNumberOfClients);
+ sbuf.append(" \n AutoShutdownEnabled=").append(mAutoShutdownEnabled);
+ sbuf.append(" \n ShutdownTimeoutMillis=").append(mShutdownTimeoutMillis);
+ sbuf.append(" \n ClientControlByUser=").append(mClientControlByUser);
+ sbuf.append(" \n BlockedClientList=").append(mBlockedClientList);
+ sbuf.append(" \n AllowedClientList=").append(mAllowedClientList);
+ return sbuf.toString();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mSsid);
+ dest.writeParcelable(mBssid, flags);
+ dest.writeString(mPassphrase);
+ dest.writeBoolean(mHiddenSsid);
+ dest.writeInt(mBand);
+ dest.writeInt(mChannel);
+ dest.writeInt(mSecurityType);
+ dest.writeInt(mMaxNumberOfClients);
+ dest.writeBoolean(mAutoShutdownEnabled);
+ dest.writeLong(mShutdownTimeoutMillis);
+ dest.writeBoolean(mClientControlByUser);
+ dest.writeTypedList(mBlockedClientList);
+ dest.writeTypedList(mAllowedClientList);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<SoftApConfiguration> CREATOR = new Creator<SoftApConfiguration>() {
+ @Override
+ public SoftApConfiguration createFromParcel(Parcel in) {
+ return new SoftApConfiguration(
+ in.readString(),
+ in.readParcelable(MacAddress.class.getClassLoader()),
+ in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(),
+ in.readInt(), in.readBoolean(), in.readLong(), in.readBoolean(),
+ in.createTypedArrayList(MacAddress.CREATOR),
+ in.createTypedArrayList(MacAddress.CREATOR));
+ }
+
+ @Override
+ public SoftApConfiguration[] newArray(int size) {
+ return new SoftApConfiguration[size];
+ }
+ };
+
+ /**
+ * Return String set to be the SSID for the AP.
+ * {@link Builder#setSsid(String)}.
+ */
+ @Nullable
+ public String getSsid() {
+ return mSsid;
+ }
+
+ /**
+ * Returns MAC address set to be BSSID for the AP.
+ * {@link Builder#setBssid(MacAddress)}.
+ */
+ @Nullable
+ public MacAddress getBssid() {
+ return mBssid;
+ }
+
+ /**
+ * Returns String set to be passphrase for current AP.
+ * {@link Builder#setPassphrase(String, int)}.
+ */
+ @Nullable
+ public String getPassphrase() {
+ return mPassphrase;
+ }
+
+ /**
+ * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or
+ * not (false: broadcasts its SSID) for the AP.
+ * {@link Builder#setHiddenSsid(boolean)}.
+ */
+ public boolean isHiddenSsid() {
+ return mHiddenSsid;
+ }
+
+ /**
+ * Returns band type set to be the band for the AP.
+ *
+ * One or combination of the following band type:
+ * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
+ *
+ * {@link Builder#setBand(int)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @BandType int getBand() {
+ return mBand;
+ }
+
+ /**
+ * Returns Integer set to be the channel for the AP.
+ * {@link Builder#setChannel(int)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public int getChannel() {
+ return mChannel;
+ }
+
+ /**
+ * Get security type params which depends on which security passphrase to set.
+ *
+ * @return One of:
+ * {@link #SECURITY_TYPE_OPEN},
+ * {@link #SECURITY_TYPE_WPA2_PSK},
+ * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
+ * {@link #SECURITY_TYPE_WPA3_SAE}
+ */
+ public @SecurityType int getSecurityType() {
+ return mSecurityType;
+ }
+
+ /**
+ * Returns the maximum number of clients that can associate to the AP.
+ * {@link Builder#setMaxNumberOfClients(int)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public int getMaxNumberOfClients() {
+ return mMaxNumberOfClients;
+ }
+
+ /**
+ * Returns whether auto shutdown is enabled or not.
+ * The Soft AP will shutdown when there are no devices associated to it for
+ * the timeout duration. See {@link Builder#setAutoShutdownEnabled(boolean)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isAutoShutdownEnabled() {
+ return mAutoShutdownEnabled;
+ }
+
+ /**
+ * Returns the shutdown timeout in milliseconds.
+ * The Soft AP will shutdown when there are no devices associated to it for
+ * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(long)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public long getShutdownTimeoutMillis() {
+ return mShutdownTimeoutMillis;
+ }
+
+ /**
+ * Returns a flag indicating whether clients need to be pre-approved by the user.
+ * (true: authorization required) or not (false: not required).
+ * {@link Builder#setClientControlByUserEnabled(Boolean)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isClientControlByUserEnabled() {
+ return mClientControlByUser;
+ }
+
+ /**
+ * Returns List of clients which aren't allowed to associate to the AP.
+ *
+ * Clients are configured using {@link Builder#setBlockedClientList(List)}
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public List<MacAddress> getBlockedClientList() {
+ return mBlockedClientList;
+ }
+
+ /**
+ * List of clients which are allowed to associate to the AP.
+ * Clients are configured using {@link Builder#setAllowedClientList(List)}
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public List<MacAddress> getAllowedClientList() {
+ return mAllowedClientList;
+ }
+
+ /**
+ * Returns a {@link WifiConfiguration} representation of this {@link SoftApConfiguration}.
+ * Note that SoftApConfiguration may contain configuration which is cannot be represented
+ * by the legacy WifiConfiguration, in such cases a null will be returned.
+ *
+ * <li> SoftAp band in {@link WifiConfiguration.apBand} only supports
+ * 2GHz, 5GHz, 2GHz+5GHz bands, so conversion is limited to these bands. </li>
+ *
+ * <li> SoftAp security type in {@link WifiConfiguration.KeyMgmt} only supports
+ * NONE, WPA2_PSK, so conversion is limited to these security type.</li>
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ public WifiConfiguration toWifiConfiguration() {
+ WifiConfiguration wifiConfig = new WifiConfiguration();
+ wifiConfig.SSID = mSsid;
+ wifiConfig.preSharedKey = mPassphrase;
+ wifiConfig.hiddenSSID = mHiddenSsid;
+ wifiConfig.apChannel = mChannel;
+ switch (mSecurityType) {
+ case SECURITY_TYPE_OPEN:
+ wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ break;
+ case SECURITY_TYPE_WPA2_PSK:
+ wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
+ break;
+ default:
+ Log.e(TAG, "Convert fail, unsupported security type :" + mSecurityType);
+ return null;
+ }
+
+ switch (mBand) {
+ case BAND_2GHZ:
+ wifiConfig.apBand = WifiConfiguration.AP_BAND_2GHZ;
+ break;
+ case BAND_5GHZ:
+ wifiConfig.apBand = WifiConfiguration.AP_BAND_5GHZ;
+ break;
+ case BAND_2GHZ | BAND_5GHZ:
+ wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY;
+ break;
+ case BAND_ANY:
+ wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY;
+ break;
+ default:
+ Log.e(TAG, "Convert fail, unsupported band setting :" + mBand);
+ return null;
+ }
+ return wifiConfig;
+ }
+
+ /**
+ * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
+ * Soft AP.
+ *
+ * All fields are optional. By default, SSID and BSSID are automatically chosen by the
+ * framework, and an open network is created.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+ private String mSsid;
+ private MacAddress mBssid;
+ private String mPassphrase;
+ private boolean mHiddenSsid;
+ private int mBand;
+ private int mChannel;
+ private int mMaxNumberOfClients;
+ private int mSecurityType;
+ private boolean mAutoShutdownEnabled;
+ private long mShutdownTimeoutMillis;
+ private boolean mClientControlByUser;
+ private List<MacAddress> mBlockedClientList;
+ private List<MacAddress> mAllowedClientList;
+
+ /**
+ * Constructs a Builder with default values (see {@link Builder}).
+ */
+ public Builder() {
+ mSsid = null;
+ mBssid = null;
+ mPassphrase = null;
+ mHiddenSsid = false;
+ mBand = BAND_2GHZ;
+ mChannel = 0;
+ mMaxNumberOfClients = 0;
+ mSecurityType = SECURITY_TYPE_OPEN;
+ mAutoShutdownEnabled = true; // enabled by default.
+ mShutdownTimeoutMillis = 0;
+ mClientControlByUser = false;
+ mBlockedClientList = new ArrayList<>();
+ mAllowedClientList = new ArrayList<>();
+ }
+
+ /**
+ * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance.
+ */
+ public Builder(@NonNull SoftApConfiguration other) {
+ Objects.requireNonNull(other);
+
+ mSsid = other.mSsid;
+ mBssid = other.mBssid;
+ mPassphrase = other.mPassphrase;
+ mHiddenSsid = other.mHiddenSsid;
+ mBand = other.mBand;
+ mChannel = other.mChannel;
+ mMaxNumberOfClients = other.mMaxNumberOfClients;
+ mSecurityType = other.mSecurityType;
+ mAutoShutdownEnabled = other.mAutoShutdownEnabled;
+ mShutdownTimeoutMillis = other.mShutdownTimeoutMillis;
+ mClientControlByUser = other.mClientControlByUser;
+ mBlockedClientList = new ArrayList<>(other.mBlockedClientList);
+ mAllowedClientList = new ArrayList<>(other.mAllowedClientList);
+ }
+
+ /**
+ * Builds the {@link SoftApConfiguration}.
+ *
+ * @return A new {@link SoftApConfiguration}, as configured by previous method calls.
+ */
+ @NonNull
+ public SoftApConfiguration build() {
+ for (MacAddress client : mAllowedClientList) {
+ if (mBlockedClientList.contains(client)) {
+ throw new IllegalArgumentException("A MacAddress exist in both client list");
+ }
+ }
+ return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
+ mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients,
+ mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser,
+ mBlockedClientList, mAllowedClientList);
+ }
+
+ /**
+ * Specifies an SSID for the AP.
+ * <p>
+ * Null SSID only support when configure a local-only hotspot.
+ * <p>
+ * <li>If not set, defaults to null.</li>
+ *
+ * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically
+ * chosen by the framework.
+ * @return Builder for chaining.
+ * @throws IllegalArgumentException when the SSID is empty or not valid Unicode.
+ */
+ @NonNull
+ public Builder setSsid(@Nullable String ssid) {
+ if (ssid != null) {
+ Preconditions.checkStringNotEmpty(ssid);
+ Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid));
+ }
+ mSsid = ssid;
+ return this;
+ }
+
+ /**
+ * Specifies a BSSID for the AP.
+ * <p>
+ * <li>If not set, defaults to null.</li>
+ * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
+ * responsible for avoiding collisions.
+ * @return Builder for chaining.
+ * @throws IllegalArgumentException when the given BSSID is the all-zero or broadcast MAC
+ * address.
+ */
+ @NonNull
+ public Builder setBssid(@Nullable MacAddress bssid) {
+ if (bssid != null) {
+ Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS));
+ Preconditions.checkArgument(!bssid.equals(MacAddress.BROADCAST_ADDRESS));
+ }
+ mBssid = bssid;
+ return this;
+ }
+
+ /**
+ * Specifies that this AP should use specific security type with the given ASCII passphrase.
+ *
+ * @param securityType One of the following security types:
+ * {@link #SECURITY_TYPE_OPEN},
+ * {@link #SECURITY_TYPE_WPA2_PSK},
+ * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
+ * {@link #SECURITY_TYPE_WPA3_SAE}.
+ * @param passphrase The passphrase to use for sepcific {@code securityType} configuration
+ * or null with {@link #SECURITY_TYPE_OPEN}.
+ *
+ * @return Builder for chaining.
+ * @throws IllegalArgumentException when the passphrase length is invalid and
+ * {@code securityType} is not {@link #SECURITY_TYPE_OPEN}
+ * or non-null passphrase and {@code securityType} is
+ * {@link #SECURITY_TYPE_OPEN}.
+ */
+ @NonNull
+ public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) {
+ if (securityType == SECURITY_TYPE_OPEN) {
+ if (passphrase != null) {
+ throw new IllegalArgumentException(
+ "passphrase should be null when security type is open");
+ }
+ } else {
+ Preconditions.checkStringNotEmpty(passphrase);
+ final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+ if (!asciiEncoder.canEncode(passphrase)) {
+ throw new IllegalArgumentException("passphrase not ASCII encodable");
+ }
+ if (securityType == SECURITY_TYPE_WPA2_PSK
+ || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION) {
+ if (passphrase.length() < PSK_MIN_LEN || passphrase.length() > PSK_MAX_LEN) {
+ throw new IllegalArgumentException(
+ "Password size must be at least " + PSK_MIN_LEN
+ + " and no more than " + PSK_MAX_LEN
+ + " for WPA2_PSK and WPA3_SAE_TRANSITION Mode");
+ }
+ }
+ }
+ mSecurityType = securityType;
+ mPassphrase = passphrase;
+ return this;
+ }
+
+ /**
+ * Specifies whether the AP is hidden (doesn't broadcast its SSID) or
+ * not (broadcasts its SSID).
+ * <p>
+ * <li>If not set, defaults to false (i.e not a hidden network).</li>
+ *
+ * @param hiddenSsid true for a hidden SSID, false otherwise.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setHiddenSsid(boolean hiddenSsid) {
+ mHiddenSsid = hiddenSsid;
+ return this;
+ }
+
+ /**
+ * Specifies the band for the AP.
+ * <p>
+ * <li>If not set, defaults to {@link #BAND_2GHZ}.</li>
+ *
+ * @param band One or combination of the following band type:
+ * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setBand(@BandType int band) {
+ if (!isBandValid(band)) {
+ throw new IllegalArgumentException("Invalid band type");
+ }
+ mBand = band;
+ // Since band preference is specified, no specific channel is selected.
+ mChannel = 0;
+ return this;
+ }
+
+ /**
+ * Specifies the channel and associated band for the AP.
+ *
+ * The channel which AP resides on. Valid channels are country dependent.
+ * <p>
+ * The default for the channel is a the special value 0 to have the framework
+ * auto-select a valid channel from the band configured with
+ * {@link #setBand(int)}.
+ *
+ * The channel auto selection will offload to driver when
+ * {@link SoftApCapability#areFeaturesSupported(
+ * SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD)}
+ * return true. Driver will auto select best channel which based on environment
+ * interference to get best performance. Check {@link SoftApCapability} to get more detail.
+ *
+ * Note, since 6GHz band use the same channel numbering of 2.4GHz and 5GHZ bands,
+ * the caller needs to pass the band containing the selected channel.
+ *
+ * <p>
+ * <li>If not set, defaults to 0.</li>
+ * @param channel operating channel of the AP.
+ * @param band containing this channel.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setChannel(int channel, @BandType int band) {
+ if (!isChannelBandPairValid(channel, band)) {
+ throw new IllegalArgumentException("Invalid band type");
+ }
+ mBand = band;
+ mChannel = channel;
+ return this;
+ }
+
+ /**
+ * Specifies the maximum number of clients that can associate to the AP.
+ *
+ * The maximum number of clients (STAs) which can associate to the AP.
+ * The AP will reject association from any clients above this number.
+ * Specify a value of 0 to have the framework automatically use the maximum number
+ * which the device can support (based on hardware and carrier constraints).
+ * <p>
+ * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
+ * {@link SoftApCapability#getMaxSupportedClients} to get the maximum number of clients
+ * which the device supports (based on hardware and carrier constraints).
+ *
+ * <p>
+ * <li>If not set, defaults to 0.</li>
+ *
+ * This method requires hardware support. If the method is used to set a
+ * non-zero {@code maxNumberOfClients} value then
+ * {@link WifiManager#startTetheredHotspot} will report error code
+ * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
+ *
+ * <p>
+ * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
+ * {@link SoftApCapability#areFeaturesSupported(int)}
+ * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether
+ * or not this feature is supported.
+ *
+ * @param maxNumberOfClients maximum client number of the AP.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setMaxNumberOfClients(@IntRange(from = 0) int maxNumberOfClients) {
+ if (maxNumberOfClients < 0) {
+ throw new IllegalArgumentException("maxNumberOfClients should be not negative");
+ }
+ mMaxNumberOfClients = maxNumberOfClients;
+ return this;
+ }
+
+ /**
+ * Specifies whether auto shutdown is enabled or not.
+ * The Soft AP will shut down when there are no devices connected to it for
+ * the timeout duration.
+ *
+ * <p>
+ * <li>If not set, defaults to true</li>
+ *
+ * @param enable true to enable, false to disable.
+ * @return Builder for chaining.
+ *
+ * @see #setShutdownTimeoutMillis(long)
+ */
+ @NonNull
+ public Builder setAutoShutdownEnabled(boolean enable) {
+ mAutoShutdownEnabled = enable;
+ return this;
+ }
+
+ /**
+ * Specifies the shutdown timeout in milliseconds.
+ * The Soft AP will shut down when there are no devices connected to it for
+ * the timeout duration.
+ *
+ * Specify a value of 0 to have the framework automatically use default timeout
+ * setting which defined in {@link R.integer.config_wifi_framework_soft_ap_timeout_delay}
+ *
+ * <p>
+ * <li>If not set, defaults to 0</li>
+ * <li>The shut down timeout will apply when {@link #setAutoShutdownEnabled(boolean)} is
+ * set to true</li>
+ *
+ * @param timeoutMillis milliseconds of the timeout delay.
+ * @return Builder for chaining.
+ *
+ * @see #setAutoShutdownEnabled(boolean)
+ */
+ @NonNull
+ public Builder setShutdownTimeoutMillis(@IntRange(from = 0) long timeoutMillis) {
+ if (timeoutMillis < 0) {
+ throw new IllegalArgumentException("Invalid timeout value");
+ }
+ mShutdownTimeoutMillis = timeoutMillis;
+ return this;
+ }
+
+ /**
+ * Configure the Soft AP to require manual user control of client association.
+ * If disabled (the default) then any client which isn't in the blocked list
+ * {@link #getBlockedClientList()} can associate to this Soft AP using the
+ * correct credentials until the Soft AP capacity is reached (capacity is hardware, carrier,
+ * or user limited - using {@link #setMaxNumberOfClients(int)}).
+ *
+ * If manual user control is enabled then clients will be accepted, rejected, or require
+ * a user approval based on the configuration provided by
+ * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}.
+ *
+ * <p>
+ * This method requires hardware support. Hardware support can be determined using
+ * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
+ * {@link SoftApCapability#areFeaturesSupported(int)}
+ * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
+ *
+ * <p>
+ * If the method is called on a device without hardware support then starting the soft AP
+ * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
+ * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
+ *
+ * <p>
+ * <li>If not set, defaults to false (i.e The authoriztion is not required).</li>
+ *
+ * @param enabled true for enabling the control by user, false otherwise.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setClientControlByUserEnabled(boolean enabled) {
+ mClientControlByUser = enabled;
+ return this;
+ }
+
+
+ /**
+ * This method together with {@link setClientControlByUserEnabled(boolean)} control client
+ * connections to the AP. If client control by user is disabled using the above method then
+ * this API has no effect and clients are allowed to associate to the AP (within limit of
+ * max number of clients).
+ *
+ * If client control by user is enabled then this API configures the list of clients
+ * which are explicitly allowed. These are auto-accepted.
+ *
+ * All other clients which attempt to associate, whose MAC addresses are on neither list,
+ * are:
+ * <ul>
+ * <li>Rejected</li>
+ * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)}
+ * is issued (which allows the user to add them to the allowed client list if desired).<li>
+ * </ul>
+ *
+ * @param allowedClientList list of clients which are allowed to associate to the AP
+ * without user pre-approval.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) {
+ mAllowedClientList = new ArrayList<>(allowedClientList);
+ return this;
+ }
+
+ /**
+ * This API configures the list of clients which are blocked and cannot associate
+ * to the Soft AP.
+ *
+ * <p>
+ * This method requires hardware support. Hardware support can be determined using
+ * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
+ * {@link SoftApCapability#areFeaturesSupported(int)}
+ * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
+ *
+ * <p>
+ * If the method is called on a device without hardware support then starting the soft AP
+ * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
+ * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
+ *
+ * @param blockedClientList list of clients which are not allowed to associate to the AP.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) {
+ mBlockedClientList = new ArrayList<>(blockedClientList);
+ return this;
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java
new file mode 100644
index 000000000000..24ed8effe471
--- /dev/null
+++ b/wifi/java/android/net/wifi/SoftApInfo.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A class representing information about SoftAp.
+ * {@see WifiManager}
+ *
+ * @hide
+ */
+@SystemApi
+public final class SoftApInfo implements Parcelable {
+
+ /**
+ * AP Channel bandwidth is invalid.
+ *
+ * @see #getBandwidth()
+ */
+ public static final int CHANNEL_WIDTH_INVALID = 0;
+
+ /**
+ * AP Channel bandwidth is 20 MHZ but no HT.
+ *
+ * @see #getBandwidth()
+ */
+ public static final int CHANNEL_WIDTH_20MHZ_NOHT = 1;
+
+ /**
+ * AP Channel bandwidth is 20 MHZ.
+ *
+ * @see #getBandwidth()
+ */
+ public static final int CHANNEL_WIDTH_20MHZ = 2;
+
+ /**
+ * AP Channel bandwidth is 40 MHZ.
+ *
+ * @see #getBandwidth()
+ */
+ public static final int CHANNEL_WIDTH_40MHZ = 3;
+
+ /**
+ * AP Channel bandwidth is 80 MHZ.
+ *
+ * @see #getBandwidth()
+ */
+ public static final int CHANNEL_WIDTH_80MHZ = 4;
+
+ /**
+ * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ.
+ *
+ * @see #getBandwidth()
+ */
+ public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 5;
+
+ /**
+ * AP Channel bandwidth is 160 MHZ.
+ *
+ * @see #getBandwidth()
+ */
+ public static final int CHANNEL_WIDTH_160MHZ = 6;
+
+
+
+ /** The frequency which AP resides on. */
+ private int mFrequency = 0;
+
+ @WifiAnnotations.Bandwidth
+ private int mBandwidth = CHANNEL_WIDTH_INVALID;
+
+ /**
+ * Get the frequency which AP resides on.
+ */
+ public int getFrequency() {
+ return mFrequency;
+ }
+
+ /**
+ * Set the frequency which AP resides on.
+ * @hide
+ */
+ public void setFrequency(int freq) {
+ mFrequency = freq;
+ }
+
+ /**
+ * Get AP Channel bandwidth.
+ *
+ * @return One of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
+ * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ},
+ * {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ} or {@link #CHANNEL_WIDTH_INVALID}.
+ */
+ @WifiAnnotations.Bandwidth
+ public int getBandwidth() {
+ return mBandwidth;
+ }
+
+ /**
+ * Set AP Channel bandwidth.
+ * @hide
+ */
+ public void setBandwidth(@WifiAnnotations.Bandwidth int bandwidth) {
+ mBandwidth = bandwidth;
+ }
+
+ /**
+ * @hide
+ */
+ public SoftApInfo(@Nullable SoftApInfo source) {
+ if (source != null) {
+ mFrequency = source.mFrequency;
+ mBandwidth = source.mBandwidth;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public SoftApInfo() {
+ }
+
+ @Override
+ /** Implement the Parcelable interface. */
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ /** Implement the Parcelable interface */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mFrequency);
+ dest.writeInt(mBandwidth);
+ }
+
+ @NonNull
+ /** Implement the Parcelable interface */
+ public static final Creator<SoftApInfo> CREATOR = new Creator<SoftApInfo>() {
+ public SoftApInfo createFromParcel(Parcel in) {
+ SoftApInfo info = new SoftApInfo();
+ info.mFrequency = in.readInt();
+ info.mBandwidth = in.readInt();
+ return info;
+ }
+
+ public SoftApInfo[] newArray(int size) {
+ return new SoftApInfo[size];
+ }
+ };
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "SoftApInfo{"
+ + "bandwidth= " + mBandwidth
+ + ",frequency= " + mFrequency
+ + '}';
+ }
+
+ @Override
+ public boolean equals(@NonNull Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SoftApInfo)) return false;
+ SoftApInfo softApInfo = (SoftApInfo) o;
+ return mFrequency == softApInfo.mFrequency
+ && mBandwidth == softApInfo.mBandwidth;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFrequency, mBandwidth);
+ }
+}
diff --git a/wifi/java/android/net/wifi/SynchronousExecutor.java b/wifi/java/android/net/wifi/SynchronousExecutor.java
new file mode 100644
index 000000000000..9926b1b5f7dc
--- /dev/null
+++ b/wifi/java/android/net/wifi/SynchronousExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.wifi;
+
+import java.util.concurrent.Executor;
+
+/**
+ * An executor implementation that runs synchronously on the current thread.
+ * @hide
+ */
+public class SynchronousExecutor implements Executor {
+ @Override
+ public void execute(Runnable r) {
+ r.run();
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
deleted file mode 100644
index 0f7fc2d48b7d..000000000000
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-
-/**
- * Record of energy and activity information from controller and
- * underlying wifi stack state. Timestamp the record with elapsed
- * real-time.
- * @hide
- */
-public final class WifiActivityEnergyInfo implements Parcelable {
- /**
- * @hide
- */
- public long mTimestamp;
-
- /**
- * @hide
- */
- public int mStackState;
-
- /**
- * @hide
- */
- public long mControllerTxTimeMs;
-
- /**
- * @hide
- */
- public long[] mControllerTxTimePerLevelMs;
-
- /**
- * @hide
- */
- public long mControllerRxTimeMs;
-
- /**
- * @hide
- */
- public long mControllerScanTimeMs;
-
- /**
- * @hide
- */
- public long mControllerIdleTimeMs;
-
- /**
- * @hide
- */
- public long mControllerEnergyUsed;
-
- public static final int STACK_STATE_INVALID = 0;
- public static final int STACK_STATE_STATE_ACTIVE = 1;
- public static final int STACK_STATE_STATE_SCANNING = 2;
- public static final int STACK_STATE_STATE_IDLE = 3;
-
- public WifiActivityEnergyInfo(long timestamp, int stackState,
- long txTime, long[] txTimePerLevel, long rxTime, long scanTime,
- long idleTime, long energyUsed) {
- mTimestamp = timestamp;
- mStackState = stackState;
- mControllerTxTimeMs = txTime;
- mControllerTxTimePerLevelMs = txTimePerLevel;
- mControllerRxTimeMs = rxTime;
- mControllerScanTimeMs = scanTime;
- mControllerIdleTimeMs = idleTime;
- mControllerEnergyUsed = energyUsed;
- }
-
- @Override
- public String toString() {
- return "WifiActivityEnergyInfo{"
- + " timestamp=" + mTimestamp
- + " mStackState=" + mStackState
- + " mControllerTxTimeMs=" + mControllerTxTimeMs
- + " mControllerTxTimePerLevelMs=" + Arrays.toString(mControllerTxTimePerLevelMs)
- + " mControllerRxTimeMs=" + mControllerRxTimeMs
- + " mControllerScanTimeMs=" + mControllerScanTimeMs
- + " mControllerIdleTimeMs=" + mControllerIdleTimeMs
- + " mControllerEnergyUsed=" + mControllerEnergyUsed
- + " }";
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<WifiActivityEnergyInfo> CREATOR =
- new Parcelable.Creator<WifiActivityEnergyInfo>() {
- public WifiActivityEnergyInfo createFromParcel(Parcel in) {
- long timestamp = in.readLong();
- int stackState = in.readInt();
- long txTime = in.readLong();
- long[] txTimePerLevel = in.createLongArray();
- long rxTime = in.readLong();
- long scanTime = in.readLong();
- long idleTime = in.readLong();
- long energyUsed = in.readLong();
- return new WifiActivityEnergyInfo(timestamp, stackState,
- txTime, txTimePerLevel, rxTime, scanTime, idleTime, energyUsed);
- }
- public WifiActivityEnergyInfo[] newArray(int size) {
- return new WifiActivityEnergyInfo[size];
- }
- };
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(mTimestamp);
- out.writeInt(mStackState);
- out.writeLong(mControllerTxTimeMs);
- out.writeLongArray(mControllerTxTimePerLevelMs);
- out.writeLong(mControllerRxTimeMs);
- out.writeLong(mControllerScanTimeMs);
- out.writeLong(mControllerIdleTimeMs);
- out.writeLong(mControllerEnergyUsed);
- }
-
- public int describeContents() {
- return 0;
- }
-
- /**
- * @return bt stack reported state
- */
- public int getStackState() {
- return mStackState;
- }
-
- /**
- * @return tx time in ms
- */
- public long getControllerTxTimeMillis() {
- return mControllerTxTimeMs;
- }
-
- /**
- * @return tx time at power level provided in ms
- */
- public long getControllerTxTimeMillisAtLevel(int level) {
- if (level < mControllerTxTimePerLevelMs.length) {
- return mControllerTxTimePerLevelMs[level];
- }
- return 0;
- }
-
- /**
- * @return rx time in ms
- */
- public long getControllerRxTimeMillis() {
- return mControllerRxTimeMs;
- }
-
- /**
- * @return scan time in ms
- */
- public long getControllerScanTimeMillis() {
- return mControllerScanTimeMs;
- }
-
- /**
- * @return idle time in ms
- */
- public long getControllerIdleTimeMillis() {
- return mControllerIdleTimeMs;
- }
-
- /**
- * product of current(mA), voltage(V) and time(ms)
- * @return energy used
- */
- public long getControllerEnergyUsed() {
- return mControllerEnergyUsed;
- }
- /**
- * @return timestamp(wall clock) of record creation
- */
- public long getTimeStamp() {
- return mTimestamp;
- }
-
- /**
- * @return if the record is valid
- */
- public boolean isValid() {
- return ((mControllerTxTimeMs >=0) &&
- (mControllerRxTimeMs >=0) &&
- (mControllerScanTimeMs >=0) &&
- (mControllerIdleTimeMs >=0));
- }
-} \ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiAnnotations.java b/wifi/java/android/net/wifi/WifiAnnotations.java
new file mode 100644
index 000000000000..acda7e06c95d
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiAnnotations.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.annotation.IntDef;
+import android.annotation.StringDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Wifi annotations meant to be statically linked into client modules, since they cannot be
+ * exposed as @SystemApi.
+ *
+ * e.g. {@link IntDef}, {@link StringDef}
+ *
+ * @hide
+ */
+public final class WifiAnnotations {
+ private WifiAnnotations() {}
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SCAN_TYPE_"}, value = {
+ WifiScanner.SCAN_TYPE_LOW_LATENCY,
+ WifiScanner.SCAN_TYPE_LOW_POWER,
+ WifiScanner.SCAN_TYPE_HIGH_ACCURACY})
+ public @interface ScanType {}
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"WIFI_BAND_"}, value = {
+ WifiScanner.WIFI_BAND_UNSPECIFIED,
+ WifiScanner.WIFI_BAND_24_GHZ,
+ WifiScanner.WIFI_BAND_5_GHZ,
+ WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY,
+ WifiScanner.WIFI_BAND_6_GHZ})
+ public @interface WifiBandBasic {}
+
+ @IntDef(prefix = { "CHANNEL_WIDTH_" }, value = {
+ SoftApInfo.CHANNEL_WIDTH_INVALID,
+ SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT,
+ SoftApInfo.CHANNEL_WIDTH_20MHZ,
+ SoftApInfo.CHANNEL_WIDTH_40MHZ,
+ SoftApInfo.CHANNEL_WIDTH_80MHZ,
+ SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ,
+ SoftApInfo.CHANNEL_WIDTH_160MHZ,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Bandwidth {}
+
+ @IntDef(prefix = { "CHANNEL_WIDTH_" }, value = {
+ ScanResult.CHANNEL_WIDTH_20MHZ,
+ ScanResult.CHANNEL_WIDTH_40MHZ,
+ ScanResult.CHANNEL_WIDTH_80MHZ,
+ ScanResult.CHANNEL_WIDTH_160MHZ,
+ ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ChannelWidth{}
+
+ @IntDef(prefix = { "WIFI_STANDARD_" }, value = {
+ ScanResult.WIFI_STANDARD_UNKNOWN,
+ ScanResult.WIFI_STANDARD_LEGACY,
+ ScanResult.WIFI_STANDARD_11N,
+ ScanResult.WIFI_STANDARD_11AC,
+ ScanResult.WIFI_STANDARD_11AX,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WifiStandard{}
+
+ @IntDef(prefix = { "PROTOCOL_" }, value = {
+ ScanResult.PROTOCOL_NONE,
+ ScanResult.PROTOCOL_WPA,
+ ScanResult.PROTOCOL_RSN,
+ ScanResult.PROTOCOL_OSEN,
+ ScanResult.PROTOCOL_WAPI
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Protocol {}
+
+ @IntDef(prefix = { "KEY_MGMT_" }, value = {
+ ScanResult.KEY_MGMT_NONE,
+ ScanResult.KEY_MGMT_PSK,
+ ScanResult.KEY_MGMT_EAP,
+ ScanResult.KEY_MGMT_FT_PSK,
+ ScanResult.KEY_MGMT_FT_EAP,
+ ScanResult.KEY_MGMT_PSK_SHA256,
+ ScanResult.KEY_MGMT_EAP_SHA256,
+ ScanResult.KEY_MGMT_OSEN,
+ ScanResult.KEY_MGMT_SAE,
+ ScanResult.KEY_MGMT_OWE,
+ ScanResult.KEY_MGMT_EAP_SUITE_B_192,
+ ScanResult.KEY_MGMT_FT_SAE,
+ ScanResult.KEY_MGMT_OWE_TRANSITION,
+ ScanResult.KEY_MGMT_WAPI_PSK,
+ ScanResult.KEY_MGMT_WAPI_CERT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface KeyMgmt {}
+
+ @IntDef(prefix = { "CIPHER_" }, value = {
+ ScanResult.CIPHER_NONE,
+ ScanResult.CIPHER_NO_GROUP_ADDRESSED,
+ ScanResult.CIPHER_TKIP,
+ ScanResult.CIPHER_CCMP,
+ ScanResult.CIPHER_GCMP_256,
+ ScanResult.CIPHER_SMS4
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Cipher {}
+}
diff --git a/wifi/java/android/net/wifi/WifiClient.java b/wifi/java/android/net/wifi/WifiClient.java
index 3e09580802ce..3794566f3d8f 100644
--- a/wifi/java/android/net/wifi/WifiClient.java
+++ b/wifi/java/android/net/wifi/WifiClient.java
@@ -22,8 +22,6 @@ import android.net.MacAddress;
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.util.Preconditions;
-
import java.util.Objects;
/** @hide */
@@ -46,7 +44,7 @@ public final class WifiClient implements Parcelable {
/** @hide */
public WifiClient(@NonNull MacAddress macAddress) {
- Preconditions.checkNotNull(macAddress, "mMacAddress must not be null.");
+ Objects.requireNonNull(macAddress, "mMacAddress must not be null.");
this.mMacAddress = macAddress;
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e0a4200b7d9e..71f0ab8087ab 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -18,6 +18,7 @@ package android.net.wifi;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.PackageManager;
@@ -34,19 +35,18 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.util.BackupUtils;
import android.util.Log;
-import android.util.TimeUtils;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.Calendar;
import java.util.HashMap;
/**
@@ -85,7 +85,12 @@ public class WifiConfiguration implements Parcelable {
public static final String pmfVarName = "ieee80211w";
/** {@hide} */
public static final String updateIdentiferVarName = "update_identifier";
- /** {@hide} */
+ /**
+ * The network ID for an invalid network.
+ *
+ * @hide
+ */
+ @SystemApi
public static final int INVALID_NETWORK_ID = -1;
/** {@hide} */
public static final int LOCAL_ONLY_NETWORK_ID = -2;
@@ -101,20 +106,45 @@ public class WifiConfiguration implements Parcelable {
public static class KeyMgmt {
private KeyMgmt() { }
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ NONE,
+ WPA_PSK,
+ WPA_EAP,
+ IEEE8021X,
+ WPA2_PSK,
+ OSEN,
+ FT_PSK,
+ FT_EAP,
+ SAE,
+ OWE,
+ SUITE_B_192,
+ WPA_PSK_SHA256,
+ WPA_EAP_SHA256,
+ WAPI_PSK,
+ WAPI_CERT,
+ FILS_SHA256,
+ FILS_SHA384})
+ public @interface KeyMgmtScheme {}
+
/** WPA is not used; plaintext or static WEP could be used. */
public static final int NONE = 0;
/** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
public static final int WPA_PSK = 1;
/** WPA using EAP authentication. Generally used with an external authentication server. */
public static final int WPA_EAP = 2;
- /** IEEE 802.1X using EAP authentication and (optionally) dynamically
- * generated WEP keys. */
+ /**
+ * IEEE 802.1X using EAP authentication and (optionally) dynamically
+ * generated WEP keys.
+ */
public static final int IEEE8021X = 3;
- /** WPA2 pre-shared key for use with soft access point
- * (requires {@code preSharedKey} to be specified).
- * @hide
- */
+ /**
+ * WPA2 pre-shared key for use with soft access point
+ * (requires {@code preSharedKey} to be specified).
+ * @hide
+ */
@SystemApi
public static final int WPA2_PSK = 4;
/**
@@ -162,11 +192,37 @@ public class WifiConfiguration implements Parcelable {
*/
public static final int WPA_EAP_SHA256 = 12;
+ /**
+ * WAPI pre-shared key (requires {@code preSharedKey} to be specified).
+ * @hide
+ */
+ @SystemApi
+ public static final int WAPI_PSK = 13;
+
+ /**
+ * WAPI certificate to be specified.
+ * @hide
+ */
+ @SystemApi
+ public static final int WAPI_CERT = 14;
+
+ /**
+ * IEEE 802.11ai FILS SK with SHA256
+ * @hide
+ */
+ public static final int FILS_SHA256 = 15;
+ /**
+ * IEEE 802.11ai FILS SK with SHA384:
+ * @hide
+ */
+ public static final int FILS_SHA384 = 16;
+
public static final String varName = "key_mgmt";
public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
"IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP",
- "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256" };
+ "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256",
+ "WAPI_PSK", "WAPI_CERT", "FILS_SHA256", "FILS_SHA384" };
}
/**
@@ -187,9 +243,14 @@ public class WifiConfiguration implements Parcelable {
*/
public static final int OSEN = 2;
+ /**
+ * WAPI Protocol
+ */
+ public static final int WAPI = 3;
+
public static final String varName = "proto";
- public static final String[] strings = { "WPA", "RSN", "OSEN" };
+ public static final String[] strings = { "WPA", "RSN", "OSEN", "WAPI" };
}
/**
@@ -208,9 +269,12 @@ public class WifiConfiguration implements Parcelable {
/** LEAP/Network EAP (only used with LEAP) */
public static final int LEAP = 2;
+ /** SAE (Used only for WPA3-Personal) */
+ public static final int SAE = 3;
+
public static final String varName = "auth_alg";
- public static final String[] strings = { "OPEN", "SHARED", "LEAP" };
+ public static final String[] strings = { "OPEN", "SHARED", "LEAP", "SAE" };
}
/**
@@ -232,10 +296,14 @@ public class WifiConfiguration implements Parcelable {
* AES in Galois/Counter Mode
*/
public static final int GCMP_256 = 3;
+ /**
+ * SMS4 cipher for WAPI
+ */
+ public static final int SMS4 = 4;
public static final String varName = "pairwise";
- public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256" };
+ public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256", "SMS4" };
}
/**
@@ -273,12 +341,17 @@ public class WifiConfiguration implements Parcelable {
* AES in Galois/Counter Mode
*/
public static final int GCMP_256 = 5;
+ /**
+ * SMS4 cipher for WAPI
+ */
+ public static final int SMS4 = 6;
public static final String varName = "group";
public static final String[] strings =
{ /* deprecated */ "WEP40", /* deprecated */ "WEP104",
- "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256" };
+ "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256",
+ "SMS4" };
}
/**
@@ -343,25 +416,29 @@ public class WifiConfiguration implements Parcelable {
public static final String[] strings = { "current", "disabled", "enabled" };
}
- /**
- * Security types we support.
- */
- /** @hide */
+ /** Security type for an open network. */
public static final int SECURITY_TYPE_OPEN = 0;
- /** @hide */
+ /** Security type for a WEP network. */
public static final int SECURITY_TYPE_WEP = 1;
- /** @hide */
+ /** Security type for a PSK network. */
public static final int SECURITY_TYPE_PSK = 2;
- /** @hide */
+ /** Security type for an EAP network. */
public static final int SECURITY_TYPE_EAP = 3;
- /** @hide */
+ /** Security type for an SAE network. */
public static final int SECURITY_TYPE_SAE = 4;
- /** @hide */
+ /** Security type for an EAP Suite B network. */
public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
- /** @hide */
+ /** Security type for an OWE network. */
public static final int SECURITY_TYPE_OWE = 6;
+ /** Security type for a WAPI PSK network. */
+ public static final int SECURITY_TYPE_WAPI_PSK = 7;
+ /** Security type for a WAPI Certificate network. */
+ public static final int SECURITY_TYPE_WAPI_CERT = 8;
- /** @hide */
+ /**
+ * Security types we support.
+ * @hide
+ */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "SECURITY_TYPE_" }, value = {
SECURITY_TYPE_OPEN,
@@ -370,15 +447,26 @@ public class WifiConfiguration implements Parcelable {
SECURITY_TYPE_EAP,
SECURITY_TYPE_SAE,
SECURITY_TYPE_EAP_SUITE_B,
- SECURITY_TYPE_OWE
+ SECURITY_TYPE_OWE,
+ SECURITY_TYPE_WAPI_PSK,
+ SECURITY_TYPE_WAPI_CERT
})
public @interface SecurityType {}
/**
- * @hide
- * Set security params (sets the various bitsets exposed in WifiConfiguration).
+ * Set the various security params to correspond to the provided security type.
+ * This is accomplished by setting the various BitSets exposed in WifiConfiguration.
*
- * @param securityType One of the security types from {@link SecurityType}.
+ * @param securityType One of the following security types:
+ * {@link #SECURITY_TYPE_OPEN},
+ * {@link #SECURITY_TYPE_WEP},
+ * {@link #SECURITY_TYPE_PSK},
+ * {@link #SECURITY_TYPE_EAP},
+ * {@link #SECURITY_TYPE_SAE},
+ * {@link #SECURITY_TYPE_EAP_SUITE_B},
+ * {@link #SECURITY_TYPE_OWE},
+ * {@link #SECURITY_TYPE_WAPI_PSK}, or
+ * {@link #SECURITY_TYPE_WAPI_CERT}
*/
public void setSecurityParams(@SecurityType int securityType) {
// Clear all the bitsets.
@@ -407,20 +495,46 @@ public class WifiConfiguration implements Parcelable {
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
break;
case SECURITY_TYPE_SAE:
+ allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
- requirePMF = true;
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
+ requirePmf = true;
break;
case SECURITY_TYPE_EAP_SUITE_B:
+ allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
// Note: allowedSuiteBCiphers bitset will be set by the service once the
// certificates are attached to this profile
- requirePMF = true;
+ requirePmf = true;
break;
case SECURITY_TYPE_OWE:
+ allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
- requirePMF = true;
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
+ requirePmf = true;
+ break;
+ case SECURITY_TYPE_WAPI_PSK:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_PSK);
+ allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
+ break;
+ case SECURITY_TYPE_WAPI_CERT:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_CERT);
+ allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
break;
default:
throw new IllegalArgumentException("unknown security type " + securityType);
@@ -461,6 +575,14 @@ public class WifiConfiguration implements Parcelable {
*/
public String BSSID;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"AP_BAND_"}, value = {
+ AP_BAND_2GHZ,
+ AP_BAND_5GHZ,
+ AP_BAND_ANY})
+ public @interface ApBand {}
+
/**
* 2GHz band.
* @hide
@@ -481,12 +603,14 @@ public class WifiConfiguration implements Parcelable {
public static final int AP_BAND_ANY = -1;
/**
- * The band which AP resides on
- * -1:Any 0:2G 1:5G
- * By default, 2G is chosen
+ * The band which the AP resides on.
+ * One of {@link #AP_BAND_2GHZ}, {@link #AP_BAND_5GHZ}, or {@link #AP_BAND_ANY}.
+ * By default, {@link #AP_BAND_2GHZ} is chosen.
+ *
* @hide
*/
@UnsupportedAppUsage
+ @ApBand
public int apBand = AP_BAND_2GHZ;
/**
@@ -546,10 +670,11 @@ public class WifiConfiguration implements Parcelable {
public boolean hiddenSSID;
/**
- * This is a network that requries Protected Management Frames (PMF).
+ * True if the network requires Protected Management Frames (PMF), false otherwise.
* @hide
*/
- public boolean requirePMF;
+ @SystemApi
+ public boolean requirePmf;
/**
* Update identifier, for Passpoint network.
@@ -600,8 +725,8 @@ public class WifiConfiguration implements Parcelable {
public BitSet allowedGroupManagementCiphers;
/**
* The set of SuiteB ciphers supported by this configuration.
- * To be used for WPA3-Enterprise mode.
- * See {@link SuiteBCipher} for descriptions of the values.
+ * To be used for WPA3-Enterprise mode. Set automatically by the framework based on the
+ * certificate type that is used in this configuration.
*/
@NonNull
public BitSet allowedSuiteBCiphers;
@@ -636,11 +761,12 @@ public class WifiConfiguration implements Parcelable {
public long[] roamingConsortiumIds;
/**
+ * True if this network configuration is visible to and usable by other users on the
+ * same device, false otherwise.
+ *
* @hide
- * This network configuration is visible to and usable by other users on the
- * same device.
*/
- @UnsupportedAppUsage
+ @SystemApi
public boolean shared;
/**
@@ -724,47 +850,25 @@ public class WifiConfiguration implements Parcelable {
public String lastUpdateName;
/**
+ * The carrier ID identifies the operator who provides this network configuration.
+ * see {@link TelephonyManager#getSimCarrierId()}
* @hide
- * Status of user approval for connection
*/
- public int userApproved = USER_UNSPECIFIED;
+ @SystemApi
+ public int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
- /** The Below RSSI thresholds are used to configure AutoJoin
- * - GOOD/LOW/BAD thresholds are used so as to calculate link score
- * - UNWANTED_SOFT are used by the blacklisting logic so as to handle
- * the unwanted network message coming from CS
- * - UNBLACKLIST thresholds are used so as to tweak the speed at which
- * the network is unblacklisted (i.e. if
- * it is seen with good RSSI, it is blacklisted faster)
- * - INITIAL_AUTOJOIN_ATTEMPT, used to determine how close from
- * the network we need to be before autojoin kicks in
+ /**
+ * @hide
+ * Auto-join is allowed by user for this network.
+ * Default true.
*/
+ @SystemApi
+ public boolean allowAutojoin = true;
+
/** @hide **/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static int INVALID_RSSI = -127;
- // States for the userApproved field
- /**
- * @hide
- * User hasn't specified if connection is okay
- */
- public static final int USER_UNSPECIFIED = 0;
- /**
- * @hide
- * User has approved this for connection
- */
- public static final int USER_APPROVED = 1;
- /**
- * @hide
- * User has banned this from connection
- */
- public static final int USER_BANNED = 2;
- /**
- * @hide
- * Waiting for user input
- */
- public static final int USER_PENDING = 3;
-
/**
* @hide
* Number of reports indicating no Internet Access
@@ -774,18 +878,6 @@ public class WifiConfiguration implements Parcelable {
/**
* @hide
- * For debug: date at which the config was last updated
- */
- public String updateTime;
-
- /**
- * @hide
- * For debug: date at which the config was last updated
- */
- public String creationTime;
-
- /**
- * @hide
* The WiFi configuration is considered to have no internet access for purpose of autojoining
* if there has been a report of it having no internet access, and, it never have had
* internet access in the past.
@@ -838,21 +930,13 @@ public class WifiConfiguration implements Parcelable {
* This boolean is cleared if we get a connect/save/ update or
* any wifiManager command that indicate the user interacted with the configuration
* since we will now consider that the configuration belong to him.
+ * @deprecated only kept for @UnsupportedAppUsage
* @hide
*/
@UnsupportedAppUsage
public boolean selfAdded;
/**
- * Set if the configuration was self added by the framework
- * This boolean is set once and never cleared. It is used
- * so as we never loose track of who created the
- * configuration in the first place.
- * @hide
- */
- public boolean didSelfAdd;
-
- /**
* Peer WifiConfiguration this WifiConfiguration was added for
* @hide
*/
@@ -876,51 +960,86 @@ public class WifiConfiguration implements Parcelable {
}
/**
- * Indicate whther the network is trusted or not. Networks are considered trusted
+ * Indicate whether the network is trusted or not. Networks are considered trusted
* if the user explicitly allowed this network connection.
+ * This bit can be used by suggestion network, see
+ * {@link WifiNetworkSuggestion.Builder#setUntrusted(boolean)}
* @hide
*/
public boolean trusted;
/**
- * This Wifi configuration is created from a {@link WifiNetworkSuggestion}
+ * True if this Wifi configuration is created from a {@link WifiNetworkSuggestion},
+ * false otherwise.
+ *
* @hide
*/
+ @SystemApi
public boolean fromWifiNetworkSuggestion;
/**
- * This Wifi configuration is created from a {@link WifiNetworkSpecifier}
+ * True if this Wifi configuration is created from a {@link WifiNetworkSpecifier},
+ * false otherwise.
+ *
* @hide
*/
+ @SystemApi
public boolean fromWifiNetworkSpecifier;
/**
- * Indicates if the creator of this configuration has expressed that it
- * should be considered metered.
+ * True if the creator of this configuration has expressed that it
+ * should be considered metered, false otherwise.
*
* @see #isMetered(WifiConfiguration, WifiInfo)
+ *
* @hide
*/
@SystemApi
public boolean meteredHint;
- /** {@hide} */
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"METERED_OVERRIDE_"}, value = {
+ METERED_OVERRIDE_NONE,
+ METERED_OVERRIDE_METERED,
+ METERED_OVERRIDE_NOT_METERED})
+ public @interface MeteredOverride {}
+
+ /**
+ * No metered override.
+ * @hide
+ */
+ @SystemApi
public static final int METERED_OVERRIDE_NONE = 0;
- /** {@hide} */
+ /**
+ * Override network to be metered.
+ * @hide
+ */
+ @SystemApi
public static final int METERED_OVERRIDE_METERED = 1;
- /** {@hide} */
+ /**
+ * Override network to be unmetered.
+ * @hide
+ */
+ @SystemApi
public static final int METERED_OVERRIDE_NOT_METERED = 2;
/**
* Indicates if the end user has expressed an explicit opinion about the
* meteredness of this network, such as through the Settings app.
+ * This value is one of {@link #METERED_OVERRIDE_NONE}, {@link #METERED_OVERRIDE_METERED},
+ * or {@link #METERED_OVERRIDE_NOT_METERED}.
* <p>
* This should always override any values from {@link #meteredHint} or
* {@link WifiInfo#getMeteredHint()}.
*
+ * By default this field is set to {@link #METERED_OVERRIDE_NONE}.
+ *
* @see #isMetered(WifiConfiguration, WifiInfo)
* @hide
*/
+ @SystemApi
+ @MeteredOverride
public int meteredOverride = METERED_OVERRIDE_NONE;
/**
@@ -929,7 +1048,8 @@ public class WifiConfiguration implements Parcelable {
*
* @hide
*/
- public static boolean isMetered(WifiConfiguration config, WifiInfo info) {
+ @SystemApi
+ public static boolean isMetered(@Nullable WifiConfiguration config, @Nullable WifiInfo info) {
boolean metered = false;
if (info != null && info.getMeteredHint()) {
metered = true;
@@ -1006,21 +1126,34 @@ public class WifiConfiguration implements Parcelable {
@SystemApi
public int numAssociation;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"RANDOMIZATION_"}, value = {
+ RANDOMIZATION_NONE,
+ RANDOMIZATION_PERSISTENT})
+ public @interface MacRandomizationSetting {}
+
/**
- * @hide
* Use factory MAC when connecting to this network
+ * @hide
*/
+ @SystemApi
public static final int RANDOMIZATION_NONE = 0;
/**
- * @hide
* Generate a randomized MAC once and reuse it for all connections to this network
+ * @hide
*/
+ @SystemApi
public static final int RANDOMIZATION_PERSISTENT = 1;
/**
+ * Level of MAC randomization for this network.
+ * One of {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}.
+ * By default this field is set to {@link #RANDOMIZATION_PERSISTENT}.
* @hide
- * Level of MAC randomization for this network
*/
+ @SystemApi
+ @MacRandomizationSetting
public int macRandomizationSetting = RANDOMIZATION_PERSISTENT;
/**
@@ -1032,6 +1165,13 @@ public class WifiConfiguration implements Parcelable {
/**
* @hide
+ * The wall clock time of when |mRandomizedMacAddress| should be re-randomized in aggressive
+ * randomization mode.
+ */
+ public long randomizedMacExpirationTimeMs = 0;
+
+ /**
+ * @hide
* Checks if the given MAC address can be used for Connected Mac Randomization
* by verifying that it is non-null, unicast, locally assigned, and not default mac.
* @param mac MacAddress to check
@@ -1043,26 +1183,6 @@ public class WifiConfiguration implements Parcelable {
}
/**
- * @hide
- * Returns Randomized MAC address to use with the network.
- * If it is not set/valid, creates a new randomized address.
- * If it can't generate a valid mac, returns the default MAC.
- */
- public @NonNull MacAddress getOrCreateRandomizedMacAddress() {
- int randomMacGenerationCount = 0;
- while (!isValidMacAddressForRandomization(mRandomizedMacAddress)
- && randomMacGenerationCount < MAXIMUM_RANDOM_MAC_GENERATION_RETRY) {
- mRandomizedMacAddress = MacAddressUtils.createRandomUnicastAddress();
- randomMacGenerationCount++;
- }
-
- if (!isValidMacAddressForRandomization(mRandomizedMacAddress)) {
- mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
- }
- return mRandomizedMacAddress;
- }
-
- /**
* Returns MAC address set to be the local randomized MAC address.
* Depending on user preference, the device may or may not use the returned MAC address for
* connections to this network.
@@ -1097,145 +1217,279 @@ public class WifiConfiguration implements Parcelable {
public static final int HOME_NETWORK_RSSI_BOOST = 5;
/**
+ * This class is used to contain all the information and API used for quality network selection.
* @hide
- * This class is used to contain all the information and API used for quality network selection
*/
+ @SystemApi
public static class NetworkSelectionStatus {
- /**
- * Quality Network Selection Status enable, temporary disabled, permanently disabled
- */
- /**
- * This network is allowed to join Quality Network Selection
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "NETWORK_SELECTION_",
+ value = {
+ NETWORK_SELECTION_ENABLED,
+ NETWORK_SELECTION_TEMPORARY_DISABLED,
+ NETWORK_SELECTION_PERMANENTLY_DISABLED})
+ public @interface NetworkEnabledStatus {}
+ /**
+ * This network will be considered as a potential candidate to connect to during network
+ * selection.
*/
public static final int NETWORK_SELECTION_ENABLED = 0;
/**
- * network was temporary disabled. Can be re-enabled after a time period expire
+ * This network was temporary disabled. May be re-enabled after a time out.
*/
- public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1;
+ public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1;
/**
- * network was permanently disabled.
+ * This network was permanently disabled.
*/
- public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2;
+ public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2;
/**
* Maximum Network selection status
+ * @hide
*/
public static final int NETWORK_SELECTION_STATUS_MAX = 3;
/**
* Quality network selection status String (for debug purpose). Use Quality network
* selection status value as index to extec the corresponding debug string
+ * @hide
*/
public static final String[] QUALITY_NETWORK_SELECTION_STATUS = {
"NETWORK_SELECTION_ENABLED",
"NETWORK_SELECTION_TEMPORARY_DISABLED",
"NETWORK_SELECTION_PERMANENTLY_DISABLED"};
- //Quality Network disabled reasons
- /**
- * Default value. Means not disabled
- */
- public static final int NETWORK_SELECTION_ENABLE = 0;
- /**
- * The starting index for network selection disabled reasons
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "DISABLED_", value = {
+ DISABLED_NONE,
+ DISABLED_ASSOCIATION_REJECTION,
+ DISABLED_AUTHENTICATION_FAILURE,
+ DISABLED_DHCP_FAILURE,
+ DISABLED_NO_INTERNET_TEMPORARY,
+ DISABLED_AUTHENTICATION_NO_CREDENTIALS,
+ DISABLED_NO_INTERNET_PERMANENT,
+ DISABLED_BY_WIFI_MANAGER,
+ DISABLED_BY_WRONG_PASSWORD,
+ DISABLED_AUTHENTICATION_NO_SUBSCRIPTION})
+ public @interface NetworkSelectionDisableReason {}
+
+ // Quality Network disabled reasons
+ /** Default value. Means not disabled. */
+ public static final int DISABLED_NONE = 0;
+ /**
+ * The starting index for network selection disabled reasons.
+ * @hide
*/
public static final int NETWORK_SELECTION_DISABLED_STARTING_INDEX = 1;
/**
- * @deprecated it is not used any more.
- * This network is disabled because higher layer (>2) network is bad
- */
- public static final int DISABLED_BAD_LINK = 1;
- /**
- * This network is disabled because multiple association rejects
- */
- public static final int DISABLED_ASSOCIATION_REJECTION = 2;
- /**
- * This network is disabled because multiple authentication failure
- */
- public static final int DISABLED_AUTHENTICATION_FAILURE = 3;
- /**
- * This network is disabled because multiple DHCP failure
- */
- public static final int DISABLED_DHCP_FAILURE = 4;
- /**
- * This network is disabled because of security network but no credentials
- */
- public static final int DISABLED_DNS_FAILURE = 5;
- /**
- * This network is temporarily disabled because it has no Internet access.
- */
- public static final int DISABLED_NO_INTERNET_TEMPORARY = 6;
- /**
- * This network is disabled because we started WPS
- */
- public static final int DISABLED_WPS_START = 7;
- /**
- * This network is disabled because EAP-TLS failure
- */
- public static final int DISABLED_TLS_VERSION_MISMATCH = 8;
- // Values above are for temporary disablement; values below are for permanent disablement.
- /**
- * This network is disabled due to absence of user credentials
- */
- public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 9;
- /**
- * This network is permanently disabled because it has no Internet access and user does not
- * want to stay connected.
+ * The starting index for network selection temporarily disabled reasons.
+ * @hide
*/
- public static final int DISABLED_NO_INTERNET_PERMANENT = 10;
- /**
- * This network is disabled due to WifiManager disable it explicitly
+ public static final int TEMPORARILY_DISABLED_STARTING_INDEX = 1;
+ /** This network is disabled because of multiple association rejections. */
+ public static final int DISABLED_ASSOCIATION_REJECTION = 1;
+ /** This network is disabled because of multiple authentication failure. */
+ public static final int DISABLED_AUTHENTICATION_FAILURE = 2;
+ /** This network is disabled because of multiple DHCP failure. */
+ public static final int DISABLED_DHCP_FAILURE = 3;
+ /** This network is temporarily disabled because it has no Internet access. */
+ public static final int DISABLED_NO_INTERNET_TEMPORARY = 4;
+ /**
+ * The starting index for network selection permanently disabled reasons.
+ * @hide
*/
- public static final int DISABLED_BY_WIFI_MANAGER = 11;
+ public static final int PERMANENTLY_DISABLED_STARTING_INDEX = 5;
+ /** This network is disabled due to absence of user credentials */
+ public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5;
/**
- * This network is disabled due to user switching
+ * This network is permanently disabled because it has no Internet access and the user does
+ * not want to stay connected.
*/
- public static final int DISABLED_DUE_TO_USER_SWITCH = 12;
+ public static final int DISABLED_NO_INTERNET_PERMANENT = 6;
+ /** This network is disabled due to WifiManager disabling it explicitly. */
+ public static final int DISABLED_BY_WIFI_MANAGER = 7;
+ /** This network is disabled due to wrong password. */
+ public static final int DISABLED_BY_WRONG_PASSWORD = 8;
+ /** This network is disabled because service is not subscribed. */
+ public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9;
/**
- * This network is disabled due to wrong password
+ * All other disable reasons should be strictly less than this value.
+ * @hide
*/
- public static final int DISABLED_BY_WRONG_PASSWORD = 13;
+ public static final int NETWORK_SELECTION_DISABLED_MAX = 10;
+
/**
- * This network is disabled because service is not subscribed
+ * Get an integer that is equal to the maximum integer value of all the
+ * DISABLED_* reasons
+ * e.g. {@link #DISABLED_NONE}, {@link #DISABLED_ASSOCIATION_REJECTION}, etc.
+ *
+ * All DISABLED_* constants will be contiguous in the range
+ * 0, 1, 2, 3, ..., getMaxNetworkSelectionDisableReasons()
+ *
+ * <br />
+ * For example, this can be used to iterate through all the network selection
+ * disable reasons like so:
+ * <pre>{@code
+ * for (int reason = 0; reason <= getMaxNetworkSelectionDisableReasons(); reason++) {
+ * ...
+ * }
+ * }</pre>
*/
- public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 14;
+ public static int getMaxNetworkSelectionDisableReason() {
+ return NETWORK_SELECTION_DISABLED_MAX - 1;
+ }
+
/**
- * This Maximum disable reason value
+ * Contains info about disable reasons.
+ * @hide
*/
- public static final int NETWORK_SELECTION_DISABLED_MAX = 15;
+ public static final class DisableReasonInfo {
+ /**
+ * String representation for the disable reason.
+ * Note that these strings are persisted in
+ * {@link
+ * com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil#writeToXml},
+ * so do not change the string values to maintain backwards compatibility.
+ */
+ public final String mReasonStr;
+ /**
+ * Network Selection disable reason threshold, used to debounce network failures before
+ * we disable them.
+ */
+ public final int mDisableThreshold;
+ /**
+ * Network Selection disable timeout for the error. After the timeout milliseconds,
+ * enable the network again.
+ */
+ public final int mDisableTimeoutMillis;
+
+ /**
+ * Constructor
+ * @param reasonStr string representation of the error
+ * @param disableThreshold number of failures before we disable the network
+ * @param disableTimeoutMillis the timeout, in milliseconds, before we re-enable the
+ * network after disabling it
+ */
+ public DisableReasonInfo(String reasonStr, int disableThreshold,
+ int disableTimeoutMillis) {
+ mReasonStr = reasonStr;
+ mDisableThreshold = disableThreshold;
+ mDisableTimeoutMillis = disableTimeoutMillis;
+ }
+ }
/**
- * Quality network selection disable reason String (for debug purpose)
+ * Quality network selection disable reason infos.
+ * @hide
*/
- public static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
- "NETWORK_SELECTION_ENABLE",
- "NETWORK_SELECTION_DISABLED_BAD_LINK", // deprecated
- "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
- "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
- "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
- "NETWORK_SELECTION_DISABLED_DNS_FAILURE",
- "NETWORK_SELECTION_DISABLED_NO_INTERNET_TEMPORARY",
- "NETWORK_SELECTION_DISABLED_WPS_START",
- "NETWORK_SELECTION_DISABLED_TLS_VERSION",
- "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
- "NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT",
- "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
- "NETWORK_SELECTION_DISABLED_BY_USER_SWITCH",
- "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD",
- "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_SUBSCRIPTION"
- };
+ public static final SparseArray<DisableReasonInfo> DISABLE_REASON_INFOS =
+ buildDisableReasonInfos();
+
+ private static SparseArray<DisableReasonInfo> buildDisableReasonInfos() {
+ SparseArray<DisableReasonInfo> reasons = new SparseArray<>();
+
+ reasons.append(DISABLED_NONE,
+ new DisableReasonInfo(
+ // Note that these strings are persisted in
+ // XmlUtil.NetworkSelectionStatusXmlUtil#writeToXml,
+ // so do not change the string values to maintain backwards
+ // compatibility.
+ "NETWORK_SELECTION_ENABLE",
+ -1,
+ Integer.MAX_VALUE));
+
+ reasons.append(DISABLED_ASSOCIATION_REJECTION,
+ new DisableReasonInfo(
+ // Note that there is a space at the end of this string. Cannot fix
+ // since this string is persisted.
+ "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
+ 5,
+ 5 * 60 * 1000));
+
+ reasons.append(DISABLED_AUTHENTICATION_FAILURE,
+ new DisableReasonInfo(
+ "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
+ 5,
+ 5 * 60 * 1000));
+
+ reasons.append(DISABLED_DHCP_FAILURE,
+ new DisableReasonInfo(
+ "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
+ 5,
+ 5 * 60 * 1000));
+
+ reasons.append(DISABLED_NO_INTERNET_TEMPORARY,
+ new DisableReasonInfo(
+ "NETWORK_SELECTION_DISABLED_NO_INTERNET_TEMPORARY",
+ 1,
+ 10 * 60 * 1000));
+
+ reasons.append(DISABLED_AUTHENTICATION_NO_CREDENTIALS,
+ new DisableReasonInfo(
+ "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
+ 1,
+ Integer.MAX_VALUE));
+
+ reasons.append(DISABLED_NO_INTERNET_PERMANENT,
+ new DisableReasonInfo(
+ "NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT",
+ 1,
+ Integer.MAX_VALUE));
+
+ reasons.append(DISABLED_BY_WIFI_MANAGER,
+ new DisableReasonInfo(
+ "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
+ 1,
+ Integer.MAX_VALUE));
+
+ reasons.append(DISABLED_BY_WRONG_PASSWORD,
+ new DisableReasonInfo(
+ "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD",
+ 1,
+ Integer.MAX_VALUE));
+
+ reasons.append(DISABLED_AUTHENTICATION_NO_SUBSCRIPTION,
+ new DisableReasonInfo(
+ "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_SUBSCRIPTION",
+ 1,
+ Integer.MAX_VALUE));
+
+ return reasons;
+ }
+
+ /**
+ * Get the {@link NetworkSelectionDisableReason} int code by its string value.
+ * @return the NetworkSelectionDisableReason int code corresponding to the reason string,
+ * or -1 if the reason string is unrecognized.
+ * @hide
+ */
+ @NetworkSelectionDisableReason
+ public static int getDisableReasonByString(@NonNull String reasonString) {
+ for (int i = 0; i < DISABLE_REASON_INFOS.size(); i++) {
+ int key = DISABLE_REASON_INFOS.keyAt(i);
+ DisableReasonInfo value = DISABLE_REASON_INFOS.valueAt(i);
+ if (value != null && TextUtils.equals(reasonString, value.mReasonStr)) {
+ return key;
+ }
+ }
+ Log.e(TAG, "Unrecognized network disable reason: " + reasonString);
+ return -1;
+ }
/**
* Invalid time stamp for network selection disable
+ * @hide
*/
public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
/**
- * This constant indicates the current configuration has connect choice set
+ * This constant indicates the current configuration has connect choice set
*/
private static final int CONNECT_CHOICE_EXISTS = 1;
/**
- * This constant indicates the current configuration does not have connect choice set
+ * This constant indicates the current configuration does not have connect choice set
*/
private static final int CONNECT_CHOICE_NOT_EXISTS = -1;
@@ -1244,11 +1498,13 @@ public class WifiConfiguration implements Parcelable {
* Network selection status, should be in one of three status: enable, temporaily disabled
* or permanently disabled
*/
+ @NetworkEnabledStatus
private int mStatus;
/**
* Reason for disable this network
*/
+ @NetworkSelectionDisableReason
private int mNetworkSelectionDisableReason;
/**
@@ -1273,12 +1529,6 @@ public class WifiConfiguration implements Parcelable {
private String mConnectChoice;
/**
- * The system timestamp when we records the connectChoice. This value is obtained from
- * System.currentTimeMillis
- */
- private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
-
- /**
* Used to cache the temporary candidate during the network selection procedure. It will be
* kept updating once a new scan result has a higher score than current one
*/
@@ -1309,30 +1559,9 @@ public class WifiConfiguration implements Parcelable {
private boolean mHasEverConnected;
/**
- * Boolean indicating whether {@link com.android.server.wifi.RecommendedNetworkEvaluator}
- * chose not to connect to this network in the last qualified network selection process.
- */
- private boolean mNotRecommended;
-
- /**
- * Set whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
- * recommend connecting to this network.
- */
- public void setNotRecommended(boolean notRecommended) {
- mNotRecommended = notRecommended;
- }
-
- /**
- * Returns whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
- * recommend connecting to this network.
- */
- public boolean isNotRecommended() {
- return mNotRecommended;
- }
-
- /**
* set whether this network is visible in latest Qualified Network Selection
* @param seen value set to candidate
+ * @hide
*/
public void setSeenInLastQualifiedNetworkSelection(boolean seen) {
mSeenInLastQualifiedNetworkSelection = seen;
@@ -1342,6 +1571,7 @@ public class WifiConfiguration implements Parcelable {
* get whether this network is visible in latest Qualified Network Selection
* @return returns true -- network is visible in latest Qualified Network Selection
* false -- network is invisible in latest Qualified Network Selection
+ * @hide
*/
public boolean getSeenInLastQualifiedNetworkSelection() {
return mSeenInLastQualifiedNetworkSelection;
@@ -1349,6 +1579,7 @@ public class WifiConfiguration implements Parcelable {
/**
* set the temporary candidate of current network selection procedure
* @param scanCandidate {@link ScanResult} the candidate set to mCandidate
+ * @hide
*/
public void setCandidate(ScanResult scanCandidate) {
mCandidate = scanCandidate;
@@ -1358,6 +1589,7 @@ public class WifiConfiguration implements Parcelable {
* get the temporary candidate of current network selection procedure
* @return returns {@link ScanResult} temporary candidate of current network selection
* procedure
+ * @hide
*/
public ScanResult getCandidate() {
return mCandidate;
@@ -1366,6 +1598,7 @@ public class WifiConfiguration implements Parcelable {
/**
* set the score of the temporary candidate of current network selection procedure
* @param score value set to mCandidateScore
+ * @hide
*/
public void setCandidateScore(int score) {
mCandidateScore = score;
@@ -1374,6 +1607,7 @@ public class WifiConfiguration implements Parcelable {
/**
* get the score of the temporary candidate of current network selection procedure
* @return returns score of the temporary candidate of current network selection procedure
+ * @hide
*/
public int getCandidateScore() {
return mCandidateScore;
@@ -1381,7 +1615,8 @@ public class WifiConfiguration implements Parcelable {
/**
* get user preferred choice over this configuration
- *@return returns configKey of user preferred choice over this configuration
+ * @return returns configKey of user preferred choice over this configuration
+ * @hide
*/
public String getConnectChoice() {
return mConnectChoice;
@@ -1390,77 +1625,126 @@ public class WifiConfiguration implements Parcelable {
/**
* set user preferred choice over this configuration
* @param newConnectChoice, the configKey of user preferred choice over this configuration
+ * @hide
*/
public void setConnectChoice(String newConnectChoice) {
mConnectChoice = newConnectChoice;
}
- /**
- * get the timeStamp when user select a choice over this configuration
- * @return returns when current connectChoice is set (time from System.currentTimeMillis)
- */
- public long getConnectChoiceTimestamp() {
- return mConnectChoiceTimestamp;
- }
-
- /**
- * set the timeStamp when user select a choice over this configuration
- * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
- * be obtained from System.currentTimeMillis
- */
- public void setConnectChoiceTimestamp(long timeStamp) {
- mConnectChoiceTimestamp = timeStamp;
- }
-
- /**
- * get current Quality network selection status
- * @return returns current Quality network selection status in String (for debug purpose)
- */
+ /** Get the current Quality network selection status as a String (for debugging). */
+ @NonNull
public String getNetworkStatusString() {
return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
}
+ /** @hide */
public void setHasEverConnected(boolean value) {
mHasEverConnected = value;
}
- public boolean getHasEverConnected() {
+ /** True if the device has ever connected to this network, false otherwise. */
+ public boolean hasEverConnected() {
return mHasEverConnected;
}
+ /** @hide */
public NetworkSelectionStatus() {
// previously stored configs will not have this parameter, so we default to false.
mHasEverConnected = false;
- };
+ }
+
+ /**
+ * NetworkSelectionStatus exports an immutable public API.
+ * However, test code has a need to construct a NetworkSelectionStatus in a specific state.
+ * (Note that mocking using Mockito does not work if the object needs to be parceled and
+ * unparceled.)
+ * Export a @SystemApi Builder to allow tests to construct a NetworkSelectionStatus object
+ * in the desired state, without sacrificing NetworkSelectionStatus's immutability.
+ */
+ @VisibleForTesting
+ public static final class Builder {
+ private final NetworkSelectionStatus mNetworkSelectionStatus =
+ new NetworkSelectionStatus();
+
+ /**
+ * Set the current network selection status.
+ * One of:
+ * {@link #NETWORK_SELECTION_ENABLED},
+ * {@link #NETWORK_SELECTION_TEMPORARY_DISABLED},
+ * {@link #NETWORK_SELECTION_PERMANENTLY_DISABLED}
+ * @see NetworkSelectionStatus#getNetworkSelectionStatus()
+ */
+ @NonNull
+ public Builder setNetworkSelectionStatus(@NetworkEnabledStatus int status) {
+ mNetworkSelectionStatus.setNetworkSelectionStatus(status);
+ return this;
+ }
+
+ /**
+ *
+ * Set the current network's disable reason.
+ * One of the {@link #DISABLED_NONE} or DISABLED_* constants.
+ * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
+ * @see NetworkSelectionStatus#getNetworkSelectionDisableReason()
+ */
+ @NonNull
+ public Builder setNetworkSelectionDisableReason(
+ @NetworkSelectionDisableReason int reason) {
+ mNetworkSelectionStatus.setNetworkSelectionDisableReason(reason);
+ return this;
+ }
+
+ /**
+ * Build a NetworkSelectionStatus object.
+ */
+ @NonNull
+ public NetworkSelectionStatus build() {
+ NetworkSelectionStatus status = new NetworkSelectionStatus();
+ status.copy(mNetworkSelectionStatus);
+ return status;
+ }
+ }
/**
- * @param reason specific error reason
- * @return corresponding network disable reason String (for debug purpose)
+ * Get the network disable reason string for a reason code (for debugging).
+ * @param reason specific error reason. One of the {@link #DISABLED_NONE} or
+ * DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
+ * @return network disable reason string, or null if the reason is invalid.
*/
- public static String getNetworkDisableReasonString(int reason) {
- if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
- return QUALITY_NETWORK_SELECTION_DISABLE_REASON[reason];
- } else {
+ @Nullable
+ public static String getNetworkSelectionDisableReasonString(
+ @NetworkSelectionDisableReason int reason) {
+ DisableReasonInfo info = DISABLE_REASON_INFOS.get(reason);
+ if (info == null) {
return null;
+ } else {
+ return info.mReasonStr;
}
}
/**
* get current network disable reason
* @return current network disable reason in String (for debug purpose)
+ * @hide
*/
- public String getNetworkDisableReasonString() {
- return QUALITY_NETWORK_SELECTION_DISABLE_REASON[mNetworkSelectionDisableReason];
+ public String getNetworkSelectionDisableReasonString() {
+ return getNetworkSelectionDisableReasonString(mNetworkSelectionDisableReason);
}
/**
- * get current network network selection status
- * @return return current network network selection status
+ * Get the current network network selection status.
+ * One of:
+ * {@link #NETWORK_SELECTION_ENABLED},
+ * {@link #NETWORK_SELECTION_TEMPORARY_DISABLED},
+ * {@link #NETWORK_SELECTION_PERMANENTLY_DISABLED}
*/
+ @NetworkEnabledStatus
public int getNetworkSelectionStatus() {
return mStatus;
}
+
/**
- * @return whether current network is enabled to join network selection
+ * True if the current network is enabled to join network selection, false otherwise.
+ * @hide
*/
public boolean isNetworkEnabled() {
return mStatus == NETWORK_SELECTION_ENABLED;
@@ -1468,21 +1752,24 @@ public class WifiConfiguration implements Parcelable {
/**
* @return whether current network is temporary disabled
+ * @hide
*/
public boolean isNetworkTemporaryDisabled() {
return mStatus == NETWORK_SELECTION_TEMPORARY_DISABLED;
}
/**
- * @return returns whether current network is permanently disabled
+ * True if the current network is permanently disabled, false otherwise.
+ * @hide
*/
public boolean isNetworkPermanentlyDisabled() {
return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
}
/**
- * set current networ work selection status
+ * set current network selection status
* @param status network selection status to set
+ * @hide
*/
public void setNetworkSelectionStatus(int status) {
if (status >= 0 && status < NETWORK_SELECTION_STATUS_MAX) {
@@ -1491,17 +1778,21 @@ public class WifiConfiguration implements Parcelable {
}
/**
- * @return returns current network's disable reason
+ * Returns the current network's disable reason.
+ * One of the {@link #DISABLED_NONE} or DISABLED_* constants
+ * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
*/
+ @NetworkSelectionDisableReason
public int getNetworkSelectionDisableReason() {
return mNetworkSelectionDisableReason;
}
/**
* set Network disable reason
- * @param reason Network disable reason
+ * @param reason Network disable reason
+ * @hide
*/
- public void setNetworkSelectionDisableReason(int reason) {
+ public void setNetworkSelectionDisableReason(@NetworkSelectionDisableReason int reason) {
if (reason >= 0 && reason < NETWORK_SELECTION_DISABLED_MAX) {
mNetworkSelectionDisableReason = reason;
} else {
@@ -1510,39 +1801,31 @@ public class WifiConfiguration implements Parcelable {
}
/**
- * check whether network is disabled by this reason
- * @param reason a specific disable reason
- * @return true -- network is disabled for this reason
- * false -- network is not disabled for this reason
- */
- public boolean isDisabledByReason(int reason) {
- return mNetworkSelectionDisableReason == reason;
- }
-
- /**
* @param timeStamp Set when current network is disabled in millisecond since January 1,
* 1970 00:00:00.0 UTC
+ * @hide
*/
public void setDisableTime(long timeStamp) {
mTemporarilyDisabledTimestamp = timeStamp;
}
/**
- * @return returns when current network is disabled in millisecond since January 1,
- * 1970 00:00:00.0 UTC
+ * Returns when the current network was disabled, in milliseconds since January 1,
+ * 1970 00:00:00.0 UTC.
*/
public long getDisableTime() {
return mTemporarilyDisabledTimestamp;
}
/**
- * get the disable counter of a specific reason
- * @param reason specific failure reason
- * @exception throw IllegalArgumentException for illegal input
+ * Get the disable counter of a specific reason.
+ * @param reason specific failure reason. One of the {@link #DISABLED_NONE} or
+ * DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
+ * @exception IllegalArgumentException for invalid reason
* @return counter number for specific error reason.
*/
- public int getDisableReasonCounter(int reason) {
- if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ public int getDisableReasonCounter(@NetworkSelectionDisableReason int reason) {
+ if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) {
return mNetworkSeclectionDisableCounter[reason];
} else {
throw new IllegalArgumentException("Illegal reason value: " + reason);
@@ -1554,9 +1837,10 @@ public class WifiConfiguration implements Parcelable {
* @param reason reason for disable error
* @param value the counter value for this specific reason
* @exception throw IllegalArgumentException for illegal input
+ * @hide
*/
public void setDisableReasonCounter(int reason, int value) {
- if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) {
mNetworkSeclectionDisableCounter[reason] = value;
} else {
throw new IllegalArgumentException("Illegal reason value: " + reason);
@@ -1567,9 +1851,10 @@ public class WifiConfiguration implements Parcelable {
* increment the counter of a specific failure reason
* @param reason a specific failure reason
* @exception throw IllegalArgumentException for illegal input
+ * @hide
*/
public void incrementDisableReasonCounter(int reason) {
- if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) {
mNetworkSeclectionDisableCounter[reason]++;
} else {
throw new IllegalArgumentException("Illegal reason value: " + reason);
@@ -1578,13 +1863,13 @@ public class WifiConfiguration implements Parcelable {
/**
* clear the counter of a specific failure reason
- * @hide
* @param reason a specific failure reason
* @exception throw IllegalArgumentException for illegal input
+ * @hide
*/
public void clearDisableReasonCounter(int reason) {
- if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
- mNetworkSeclectionDisableCounter[reason] = NETWORK_SELECTION_ENABLE;
+ if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+ mNetworkSeclectionDisableCounter[reason] = DISABLED_NONE;
} else {
throw new IllegalArgumentException("Illegal reason value: " + reason);
}
@@ -1592,9 +1877,10 @@ public class WifiConfiguration implements Parcelable {
/**
* clear all the failure reason counters
+ * @hide
*/
public void clearDisableReasonCounter() {
- Arrays.fill(mNetworkSeclectionDisableCounter, NETWORK_SELECTION_ENABLE);
+ Arrays.fill(mNetworkSeclectionDisableCounter, DISABLED_NONE);
}
/**
@@ -1605,6 +1891,7 @@ public class WifiConfiguration implements Parcelable {
/**
* get current network Selection BSSID
* @return current network Selection BSSID
+ * @hide
*/
public String getNetworkSelectionBSSID() {
return mNetworkSelectionBSSID;
@@ -1613,15 +1900,17 @@ public class WifiConfiguration implements Parcelable {
/**
* set network Selection BSSID
* @param bssid The target BSSID for assocaition
+ * @hide
*/
public void setNetworkSelectionBSSID(String bssid) {
mNetworkSelectionBSSID = bssid;
}
+ /** @hide */
public void copy(NetworkSelectionStatus source) {
mStatus = source.mStatus;
mNetworkSelectionDisableReason = source.mNetworkSelectionDisableReason;
- for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
+ for (int index = DISABLED_NONE; index < NETWORK_SELECTION_DISABLED_MAX;
index++) {
mNetworkSeclectionDisableCounter[index] =
source.mNetworkSeclectionDisableCounter[index];
@@ -1632,15 +1921,14 @@ public class WifiConfiguration implements Parcelable {
setCandidate(source.getCandidate());
setCandidateScore(source.getCandidateScore());
setConnectChoice(source.getConnectChoice());
- setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
- setHasEverConnected(source.getHasEverConnected());
- setNotRecommended(source.isNotRecommended());
+ setHasEverConnected(source.hasEverConnected());
}
+ /** @hide */
public void writeToParcel(Parcel dest) {
dest.writeInt(getNetworkSelectionStatus());
dest.writeInt(getNetworkSelectionDisableReason());
- for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
+ for (int index = DISABLED_NONE; index < NETWORK_SELECTION_DISABLED_MAX;
index++) {
dest.writeInt(getDisableReasonCounter(index));
}
@@ -1649,18 +1937,17 @@ public class WifiConfiguration implements Parcelable {
if (getConnectChoice() != null) {
dest.writeInt(CONNECT_CHOICE_EXISTS);
dest.writeString(getConnectChoice());
- dest.writeLong(getConnectChoiceTimestamp());
} else {
dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
}
- dest.writeInt(getHasEverConnected() ? 1 : 0);
- dest.writeInt(isNotRecommended() ? 1 : 0);
+ dest.writeInt(hasEverConnected() ? 1 : 0);
}
+ /** @hide */
public void readFromParcel(Parcel in) {
setNetworkSelectionStatus(in.readInt());
setNetworkSelectionDisableReason(in.readInt());
- for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
+ for (int index = DISABLED_NONE; index < NETWORK_SELECTION_DISABLED_MAX;
index++) {
setDisableReasonCounter(index, in.readInt());
}
@@ -1668,13 +1955,10 @@ public class WifiConfiguration implements Parcelable {
setNetworkSelectionBSSID(in.readString());
if (in.readInt() == CONNECT_CHOICE_EXISTS) {
setConnectChoice(in.readString());
- setConnectChoiceTimestamp(in.readLong());
} else {
setConnectChoice(null);
- setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
}
setHasEverConnected(in.readInt() != 0);
- setNotRecommended(in.readInt() != 0);
}
}
@@ -1685,65 +1969,104 @@ public class WifiConfiguration implements Parcelable {
private NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus();
/**
- * @hide
* This class is intended to store extra failure reason information for the most recent
* connection attempt, so that it may be surfaced to the settings UI
+ * @hide
*/
+ // TODO(b/148626966): called by SUW via reflection, remove once SUW is updated
public static class RecentFailure {
- /**
- * No recent failure, or no specific reason given for the recent connection failure
- */
- public static final int NONE = 0;
- /**
- * Connection to this network recently failed due to Association Rejection Status 17
- * (AP is full)
- */
- public static final int STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17;
+ private RecentFailure() {}
+
/**
* Association Rejection Status code (NONE for success/non-association-rejection-fail)
*/
- private int mAssociationStatus = NONE;
+ @RecentFailureReason
+ private int mAssociationStatus = RECENT_FAILURE_NONE;
/**
* @param status the association status code for the recent failure
*/
- public void setAssociationStatus(int status) {
+ public void setAssociationStatus(@RecentFailureReason int status) {
mAssociationStatus = status;
}
/**
* Sets the RecentFailure to NONE
*/
public void clear() {
- mAssociationStatus = NONE;
+ mAssociationStatus = RECENT_FAILURE_NONE;
}
/**
- * Get the recent failure code
+ * Get the recent failure code. One of {@link #RECENT_FAILURE_NONE} or
+ * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}.
*/
+ @RecentFailureReason
public int getAssociationStatus() {
return mAssociationStatus;
}
}
/**
- * @hide
* RecentFailure member
+ * @hide
*/
- final public RecentFailure recentFailure = new RecentFailure();
+ // TODO(b/148626966): called by SUW via reflection, once SUW is updated, make private and
+ // rename to mRecentFailure
+ @NonNull
+ public final RecentFailure recentFailure = new RecentFailure();
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "RECENT_FAILURE_", value = {
+ RECENT_FAILURE_NONE,
+ RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA})
+ public @interface RecentFailureReason {}
/**
+ * No recent failure, or no specific reason given for the recent connection failure
+ * @hide
+ */
+ @SystemApi
+ public static final int RECENT_FAILURE_NONE = 0;
+ /**
+ * Connection to this network recently failed due to Association Rejection Status 17
+ * (AP is full)
+ * @hide
+ */
+ @SystemApi
+ public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17;
+
+ /**
+ * Get the failure reason for the most recent connection attempt, or
+ * {@link #RECENT_FAILURE_NONE} if there was no failure.
+ *
+ * Failure reasons include:
+ * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}
+ *
* @hide
- * @return network selection status
*/
+ @RecentFailureReason
+ @SystemApi
+ public int getRecentFailureReason() {
+ return recentFailure.getAssociationStatus();
+ }
+
+ /**
+ * Get the network selection status.
+ * @hide
+ */
+ @NonNull
+ @SystemApi
public NetworkSelectionStatus getNetworkSelectionStatus() {
return mNetworkSelectionStatus;
}
/**
- * Set the network selection status
+ * Set the network selection status.
* @hide
*/
- public void setNetworkSelectionStatus(NetworkSelectionStatus status) {
+ @SystemApi
+ public void setNetworkSelectionStatus(@NonNull NetworkSelectionStatus status) {
mNetworkSelectionStatus = status;
}
@@ -1777,8 +2100,6 @@ public class WifiConfiguration implements Parcelable {
wepKeys[i] = null;
}
enterpriseConfig = new WifiEnterpriseConfig();
- selfAdded = false;
- didSelfAdd = false;
ephemeral = false;
osu = false;
trusted = true; // Networks are considered trusted by default.
@@ -1803,7 +2124,8 @@ public class WifiConfiguration implements Parcelable {
return !TextUtils.isEmpty(FQDN)
&& !TextUtils.isEmpty(providerFriendlyName)
&& enterpriseConfig != null
- && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
+ && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE
+ && !TextUtils.isEmpty(mPasspointUniqueId);
}
/**
@@ -1813,8 +2135,8 @@ public class WifiConfiguration implements Parcelable {
public boolean isLinked(WifiConfiguration config) {
if (config != null) {
if (config.linkedConfigurations != null && linkedConfigurations != null) {
- if (config.linkedConfigurations.get(configKey()) != null
- && linkedConfigurations.get(config.configKey()) != null) {
+ if (config.linkedConfigurations.get(getKey()) != null
+ && linkedConfigurations.get(config.getKey()) != null) {
return true;
}
}
@@ -1830,11 +2152,22 @@ public class WifiConfiguration implements Parcelable {
public boolean isEnterprise() {
return (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
|| allowedKeyManagement.get(KeyMgmt.IEEE8021X)
- || allowedKeyManagement.get(KeyMgmt.SUITE_B_192))
+ || allowedKeyManagement.get(KeyMgmt.SUITE_B_192)
+ || allowedKeyManagement.get(KeyMgmt.WAPI_CERT))
&& enterpriseConfig != null
&& enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
}
+ private static String logTimeOfDay(long millis) {
+ Calendar c = Calendar.getInstance();
+ if (millis >= 0) {
+ c.setTimeInMillis(millis);
+ return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c);
+ } else {
+ return Long.toString(millis);
+ }
+ }
+
@Override
public String toString() {
StringBuilder sbuf = new StringBuilder();
@@ -1846,35 +2179,38 @@ public class WifiConfiguration implements Parcelable {
sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
+ .append(" HOME-PROVIDER-NETWORK: ").append(this.isHomeProviderNetwork)
.append(" PRIO: ").append(this.priority)
.append(" HIDDEN: ").append(this.hiddenSSID)
- .append(" PMF: ").append(this.requirePMF)
+ .append(" PMF: ").append(this.requirePmf)
+ .append("CarrierId: ").append(this.carrierId)
.append('\n');
sbuf.append(" NetworkSelectionStatus ")
- .append(mNetworkSelectionStatus.getNetworkStatusString() + "\n");
+ .append(mNetworkSelectionStatus.getNetworkStatusString())
+ .append("\n");
if (mNetworkSelectionStatus.getNetworkSelectionDisableReason() > 0) {
sbuf.append(" mNetworkSelectionDisableReason ")
- .append(mNetworkSelectionStatus.getNetworkDisableReasonString() + "\n");
+ .append(mNetworkSelectionStatus.getNetworkSelectionDisableReasonString())
+ .append("\n");
- for (int index = mNetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
- index < mNetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) {
+ for (int index = NetworkSelectionStatus.DISABLED_NONE;
+ index < NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) {
if (mNetworkSelectionStatus.getDisableReasonCounter(index) != 0) {
- sbuf.append(NetworkSelectionStatus.getNetworkDisableReasonString(index)
- + " counter:" + mNetworkSelectionStatus.getDisableReasonCounter(index)
- + "\n");
+ sbuf.append(
+ NetworkSelectionStatus.getNetworkSelectionDisableReasonString(index))
+ .append(" counter:")
+ .append(mNetworkSelectionStatus.getDisableReasonCounter(index))
+ .append("\n");
}
}
}
if (mNetworkSelectionStatus.getConnectChoice() != null) {
sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
- sbuf.append(" connect choice set time: ")
- .append(TimeUtils.logTimeOfDay(
- mNetworkSelectionStatus.getConnectChoiceTimestamp()));
}
sbuf.append(" hasEverConnected: ")
- .append(mNetworkSelectionStatus.getHasEverConnected()).append("\n");
+ .append(mNetworkSelectionStatus.hasEverConnected()).append("\n");
if (this.numAssociation > 0) {
sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
@@ -1883,14 +2219,6 @@ public class WifiConfiguration implements Parcelable {
sbuf.append(" numNoInternetAccessReports ");
sbuf.append(this.numNoInternetAccessReports).append("\n");
}
- if (this.updateTime != null) {
- sbuf.append(" update ").append(this.updateTime).append("\n");
- }
- if (this.creationTime != null) {
- sbuf.append(" creation ").append(this.creationTime).append("\n");
- }
- if (this.didSelfAdd) sbuf.append(" didSelfAdd");
- if (this.selfAdded) sbuf.append(" selfAdded");
if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
if (this.ephemeral) sbuf.append(" ephemeral");
if (this.osu) sbuf.append(" osu");
@@ -1899,9 +2227,9 @@ public class WifiConfiguration implements Parcelable {
if (this.fromWifiNetworkSpecifier) sbuf.append(" fromWifiNetworkSpecifier");
if (this.meteredHint) sbuf.append(" meteredHint");
if (this.useExternalScores) sbuf.append(" useExternalScores");
- if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
- || this.ephemeral || this.trusted || this.fromWifiNetworkSuggestion
- || this.fromWifiNetworkSpecifier || this.meteredHint || this.useExternalScores) {
+ if (this.validatedInternetAccess || this.ephemeral || this.trusted
+ || this.fromWifiNetworkSuggestion || this.fromWifiNetworkSpecifier
+ || this.meteredHint || this.useExternalScores) {
sbuf.append("\n");
}
if (this.meteredOverride != METERED_OVERRIDE_NONE) {
@@ -1909,6 +2237,9 @@ public class WifiConfiguration implements Parcelable {
}
sbuf.append(" macRandomizationSetting: ").append(macRandomizationSetting).append("\n");
sbuf.append(" mRandomizedMacAddress: ").append(mRandomizedMacAddress).append("\n");
+ sbuf.append(" randomizedMacExpirationTimeMs: ")
+ .append(randomizedMacExpirationTimeMs == 0 ? "<none>"
+ : logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
sbuf.append(" KeyMgmt:");
for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
if (this.allowedKeyManagement.get(k)) {
@@ -2023,13 +2354,15 @@ public class WifiConfiguration implements Parcelable {
if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
if (updateIdentifier != null) sbuf.append(" updateIdentifier=" + updateIdentifier);
sbuf.append(" lcuid=" + lastConnectUid);
- sbuf.append(" userApproved=" + userApprovedAsString(userApproved));
+ sbuf.append(" allowAutojoin=" + allowAutojoin);
sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
+ sbuf.append(" mostRecentlyConnected=" + isMostRecentlyConnected);
+
sbuf.append(" ");
if (this.lastConnected != 0) {
sbuf.append('\n');
- sbuf.append("lastConnected: ").append(TimeUtils.logTimeOfDay(this.lastConnected));
+ sbuf.append("lastConnected: ").append(logTimeOfDay(this.lastConnected));
sbuf.append(" ");
}
sbuf.append('\n');
@@ -2044,8 +2377,13 @@ public class WifiConfiguration implements Parcelable {
return sbuf.toString();
}
- /** {@hide} */
- @UnsupportedAppUsage
+ /**
+ * Get the SSID in a human-readable format, with all additional formatting removed
+ * e.g. quotation marks around the SSID, "P" prefix
+ * @hide
+ */
+ @NonNull
+ @SystemApi
public String getPrintableSsid() {
if (SSID == null) return "";
final int length = SSID.length();
@@ -2053,7 +2391,7 @@ public class WifiConfiguration implements Parcelable {
return SSID.substring(1, length - 1);
}
- /** The ascii-encoded string format is P"<ascii-encoded-string>"
+ /* The ascii-encoded string format is P"<ascii-encoded-string>"
* The decoding is implemented in the supplicant for a newly configured
* network.
*/
@@ -2066,20 +2404,6 @@ public class WifiConfiguration implements Parcelable {
return SSID;
}
- /** @hide **/
- public static String userApprovedAsString(int userApproved) {
- switch (userApproved) {
- case USER_APPROVED:
- return "USER_APPROVED";
- case USER_BANNED:
- return "USER_BANNED";
- case USER_UNSPECIFIED:
- return "USER_UNSPECIFIED";
- default:
- return "INVALID";
- }
- }
-
/**
* Get an identifier for associating credentials with this config
* @param current configuration contains values for additional fields
@@ -2109,11 +2433,13 @@ public class WifiConfiguration implements Parcelable {
if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
keyMgmt += KeyMgmt.strings[KeyMgmt.SUITE_B_192];
}
+ if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
+ keyMgmt += KeyMgmt.strings[KeyMgmt.WAPI_CERT];
+ }
if (TextUtils.isEmpty(keyMgmt)) {
throw new IllegalStateException("Not an EAP network");
}
-
String keyId = trimStringForKeyId(SSID) + "_" + keyMgmt + "_"
+ trimStringForKeyId(enterpriseConfig.getKeyId(current != null
? current.enterpriseConfig : null));
@@ -2156,8 +2482,13 @@ public class WifiConfiguration implements Parcelable {
}
}
- /** @hide */
- @UnsupportedAppUsage
+ /**
+ * Get the authentication type of the network.
+ * @return One of the {@link KeyMgmt} constants. e.g. {@link KeyMgmt#WPA2_PSK}.
+ * @hide
+ */
+ @SystemApi
+ @KeyMgmt.KeyMgmtScheme
public int getAuthType() {
if (allowedKeyManagement.cardinality() > 1) {
throw new IllegalStateException("More than one auth type set");
@@ -2176,36 +2507,32 @@ public class WifiConfiguration implements Parcelable {
return KeyMgmt.OWE;
} else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
return KeyMgmt.SUITE_B_192;
+ } else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
+ return KeyMgmt.WAPI_PSK;
+ } else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
+ return KeyMgmt.WAPI_CERT;
}
return KeyMgmt.NONE;
}
- /* @hide
- * Cache the config key, this seems useful as a speed up since a lot of
- * lookups in the config store are done and based on this key.
+ /**
+ * Return a String that can be used to uniquely identify this WifiConfiguration.
+ * <br />
+ * Note: Do not persist this value! This value is not guaranteed to remain backwards compatible.
*/
- String mCachedConfigKey;
+ @NonNull
+ public String getKey() {
+ // Passpoint ephemeral networks have their unique identifier set. Return it as is to be
+ // able to match internally.
+ if (mPasspointUniqueId != null) {
+ return mPasspointUniqueId;
+ }
- /** @hide
- * return the string used to calculate the hash in WifiConfigStore
- * and uniquely identify this WifiConfiguration
- */
- public String configKey(boolean allowCached) {
- String key;
- if (allowCached && mCachedConfigKey != null) {
- key = mCachedConfigKey;
- } else if (providerFriendlyName != null) {
- key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
- if (!shared) {
- key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
- }
- } else {
- key = getSsidAndSecurityTypeString();
- if (!shared) {
- key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
- }
- mCachedConfigKey = key;
+ String key = getSsidAndSecurityTypeString();
+ if (!shared) {
+ key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
}
+
return key;
}
@@ -2219,7 +2546,8 @@ public class WifiConfiguration implements Parcelable {
} else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
|| allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
- } else if (wepKeys[0] != null) {
+ } else if (wepTxKeyIndex >= 0 && wepTxKeyIndex < wepKeys.length
+ && wepKeys[wepTxKeyIndex] != null) {
key = SSID + "WEP";
} else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
key = SSID + KeyMgmt.strings[KeyMgmt.OWE];
@@ -2227,33 +2555,46 @@ public class WifiConfiguration implements Parcelable {
key = SSID + KeyMgmt.strings[KeyMgmt.SAE];
} else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192];
+ } else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.WAPI_PSK];
+ } else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.WAPI_CERT];
+ } else if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.OSEN];
} else {
key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
}
return key;
}
- /** @hide
- * get configKey, force calculating the config string
+ /**
+ * Get the IpConfiguration object associated with this WifiConfiguration.
+ * @hide
*/
- public String configKey() {
- return configKey(false);
- }
-
- /** @hide */
- @UnsupportedAppUsage
+ @NonNull
+ @SystemApi
public IpConfiguration getIpConfiguration() {
- return mIpConfiguration;
+ return new IpConfiguration(mIpConfiguration);
}
- /** @hide */
- @UnsupportedAppUsage
- public void setIpConfiguration(IpConfiguration ipConfiguration) {
+ /**
+ * Set the {@link IpConfiguration} for this network.
+ * @param ipConfiguration the {@link IpConfiguration} to set, or null to use the default
+ * constructor {@link IpConfiguration#IpConfiguration()}.
+ * @hide
+ */
+ @SystemApi
+ public void setIpConfiguration(@Nullable IpConfiguration ipConfiguration) {
if (ipConfiguration == null) ipConfiguration = new IpConfiguration();
mIpConfiguration = ipConfiguration;
}
- /** @hide */
+ /**
+ * Get the {@link StaticIpConfiguration} for this network.
+ * @return the {@link StaticIpConfiguration}, or null if unset.
+ * @hide
+ */
+ @Nullable
@UnsupportedAppUsage
public StaticIpConfiguration getStaticIpConfiguration() {
return mIpConfiguration.getStaticIpConfiguration();
@@ -2265,28 +2606,36 @@ public class WifiConfiguration implements Parcelable {
mIpConfiguration.setStaticIpConfiguration(staticIpConfiguration);
}
- /** @hide */
+ /**
+ * Get the {@link IpConfiguration.IpAssignment} for this network.
+ * @hide
+ */
+ @NonNull
@UnsupportedAppUsage
public IpConfiguration.IpAssignment getIpAssignment() {
- return mIpConfiguration.ipAssignment;
+ return mIpConfiguration.getIpAssignment();
}
/** @hide */
@UnsupportedAppUsage
public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
- mIpConfiguration.ipAssignment = ipAssignment;
+ mIpConfiguration.setIpAssignment(ipAssignment);
}
- /** @hide */
+ /**
+ * Get the {@link IpConfiguration.ProxySettings} for this network.
+ * @hide
+ */
+ @NonNull
@UnsupportedAppUsage
public IpConfiguration.ProxySettings getProxySettings() {
- return mIpConfiguration.proxySettings;
+ return mIpConfiguration.getProxySettings();
}
/** @hide */
@UnsupportedAppUsage
public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
- mIpConfiguration.proxySettings = proxySettings;
+ mIpConfiguration.setProxySettings(proxySettings);
}
/**
@@ -2295,10 +2644,10 @@ public class WifiConfiguration implements Parcelable {
* WifiConfiguration, or {@code null} if no proxy is specified.
*/
public ProxyInfo getHttpProxy() {
- if (mIpConfiguration.proxySettings == IpConfiguration.ProxySettings.NONE) {
+ if (mIpConfiguration.getProxySettings() == IpConfiguration.ProxySettings.NONE) {
return null;
}
- return new ProxyInfo(mIpConfiguration.httpProxy);
+ return new ProxyInfo(mIpConfiguration.getHttpProxy());
}
/**
@@ -2323,12 +2672,12 @@ public class WifiConfiguration implements Parcelable {
if (!Uri.EMPTY.equals(httpProxy.getPacFileUrl())) {
proxySettingCopy = IpConfiguration.ProxySettings.PAC;
// Construct a new PAC URL Proxy
- httpProxyCopy = new ProxyInfo(httpProxy.getPacFileUrl(), httpProxy.getPort());
+ httpProxyCopy = ProxyInfo.buildPacProxy(httpProxy.getPacFileUrl(), httpProxy.getPort());
} else {
proxySettingCopy = IpConfiguration.ProxySettings.STATIC;
// Construct a new HTTP Proxy
- httpProxyCopy = new ProxyInfo(httpProxy.getHost(), httpProxy.getPort(),
- httpProxy.getExclusionListAsString());
+ httpProxyCopy = ProxyInfo.buildDirectProxy(httpProxy.getHost(), httpProxy.getPort(),
+ Arrays.asList(httpProxy.getExclusionList()));
}
if (!httpProxyCopy.isValid()) {
throw new IllegalArgumentException("Invalid ProxyInfo: " + httpProxyCopy.toString());
@@ -2337,11 +2686,14 @@ public class WifiConfiguration implements Parcelable {
mIpConfiguration.setHttpProxy(httpProxyCopy);
}
- /** @hide */
+ /**
+ * Set the {@link ProxySettings} and {@link ProxyInfo} for this network.
+ * @hide
+ */
@UnsupportedAppUsage
- public void setProxy(ProxySettings settings, ProxyInfo proxy) {
- mIpConfiguration.proxySettings = settings;
- mIpConfiguration.httpProxy = proxy;
+ public void setProxy(@NonNull ProxySettings settings, @NonNull ProxyInfo proxy) {
+ mIpConfiguration.setProxySettings(settings);
+ mIpConfiguration.setHttpProxy(proxy);
}
/** Implement the Parcelable interface {@hide} */
@@ -2359,9 +2711,8 @@ public class WifiConfiguration implements Parcelable {
return mPasspointManagementObjectTree;
}
- /** copy constructor {@hide} */
- @UnsupportedAppUsage
- public WifiConfiguration(WifiConfiguration source) {
+ /** Copy constructor */
+ public WifiConfiguration(@NonNull WifiConfiguration source) {
if (source != null) {
networkId = source.networkId;
status = source.status;
@@ -2403,8 +2754,6 @@ public class WifiConfiguration implements Parcelable {
linkedConfigurations = new HashMap<String, Integer>();
linkedConfigurations.putAll(source.linkedConfigurations);
}
- mCachedConfigKey = null; //force null configKey
- selfAdded = source.selfAdded;
validatedInternetAccess = source.validatedInternetAccess;
isLegacyPasspointConfig = source.isLegacyPasspointConfig;
ephemeral = source.ephemeral;
@@ -2416,7 +2765,6 @@ public class WifiConfiguration implements Parcelable {
meteredOverride = source.meteredOverride;
useExternalScores = source.useExternalScores;
- didSelfAdd = source.didSelfAdd;
lastConnectUid = source.lastConnectUid;
lastUpdateUid = source.lastUpdateUid;
creatorUid = source.creatorUid;
@@ -2429,17 +2777,18 @@ public class WifiConfiguration implements Parcelable {
numScorerOverride = source.numScorerOverride;
numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
numAssociation = source.numAssociation;
- userApproved = source.userApproved;
+ allowAutojoin = source.allowAutojoin;
numNoInternetAccessReports = source.numNoInternetAccessReports;
noInternetAccessExpected = source.noInternetAccessExpected;
- creationTime = source.creationTime;
- updateTime = source.updateTime;
shared = source.shared;
recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus());
mRandomizedMacAddress = source.mRandomizedMacAddress;
macRandomizationSetting = source.macRandomizationSetting;
- requirePMF = source.requirePMF;
+ randomizedMacExpirationTimeMs = source.randomizedMacExpirationTimeMs;
+ requirePmf = source.requirePmf;
updateIdentifier = source.updateIdentifier;
+ carrierId = source.carrierId;
+ mPasspointUniqueId = source.mPasspointUniqueId;
}
}
@@ -2467,7 +2816,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeInt(wepTxKeyIndex);
dest.writeInt(priority);
dest.writeInt(hiddenSSID ? 1 : 0);
- dest.writeInt(requirePMF ? 1 : 0);
+ dest.writeInt(requirePmf ? 1 : 0);
dest.writeString(updateIdentifier);
writeBitSet(dest, allowedKeyManagement);
@@ -2483,8 +2832,6 @@ public class WifiConfiguration implements Parcelable {
dest.writeParcelable(mIpConfiguration, flags);
dest.writeString(dhcpServer);
dest.writeString(defaultGwMacAddress);
- dest.writeInt(selfAdded ? 1 : 0);
- dest.writeInt(didSelfAdd ? 1 : 0);
dest.writeInt(validatedInternetAccess ? 1 : 0);
dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
dest.writeInt(ephemeral ? 1 : 0);
@@ -2502,7 +2849,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeInt(numScorerOverride);
dest.writeInt(numScorerOverrideAndSwitchedNetwork);
dest.writeInt(numAssociation);
- dest.writeInt(userApproved);
+ dest.writeBoolean(allowAutojoin);
dest.writeInt(numNoInternetAccessReports);
dest.writeInt(noInternetAccessExpected ? 1 : 0);
dest.writeInt(shared ? 1 : 0);
@@ -2511,6 +2858,9 @@ public class WifiConfiguration implements Parcelable {
dest.writeParcelable(mRandomizedMacAddress, flags);
dest.writeInt(macRandomizationSetting);
dest.writeInt(osu ? 1 : 0);
+ dest.writeLong(randomizedMacExpirationTimeMs);
+ dest.writeInt(carrierId);
+ dest.writeString(mPasspointUniqueId);
}
/** Implement the Parcelable interface {@hide} */
@@ -2541,7 +2891,7 @@ public class WifiConfiguration implements Parcelable {
config.wepTxKeyIndex = in.readInt();
config.priority = in.readInt();
config.hiddenSSID = in.readInt() != 0;
- config.requirePMF = in.readInt() != 0;
+ config.requirePmf = in.readInt() != 0;
config.updateIdentifier = in.readString();
config.allowedKeyManagement = readBitSet(in);
@@ -2556,8 +2906,6 @@ public class WifiConfiguration implements Parcelable {
config.setIpConfiguration(in.readParcelable(null));
config.dhcpServer = in.readString();
config.defaultGwMacAddress = in.readString();
- config.selfAdded = in.readInt() != 0;
- config.didSelfAdd = in.readInt() != 0;
config.validatedInternetAccess = in.readInt() != 0;
config.isLegacyPasspointConfig = in.readInt() != 0;
config.ephemeral = in.readInt() != 0;
@@ -2575,7 +2923,7 @@ public class WifiConfiguration implements Parcelable {
config.numScorerOverride = in.readInt();
config.numScorerOverrideAndSwitchedNetwork = in.readInt();
config.numAssociation = in.readInt();
- config.userApproved = in.readInt();
+ config.allowAutojoin = in.readBoolean();
config.numNoInternetAccessReports = in.readInt();
config.noInternetAccessExpected = in.readInt() != 0;
config.shared = in.readInt() != 0;
@@ -2584,6 +2932,9 @@ public class WifiConfiguration implements Parcelable {
config.mRandomizedMacAddress = in.readParcelable(null);
config.macRandomizationSetting = in.readInt();
config.osu = in.readInt() != 0;
+ config.randomizedMacExpirationTimeMs = in.readLong();
+ config.carrierId = in.readInt();
+ config.mPasspointUniqueId = in.readString();
return config;
}
@@ -2593,45 +2944,44 @@ public class WifiConfiguration implements Parcelable {
};
/**
- * Serializes the object for backup
+ * Passpoint Unique identifier
* @hide
*/
- public byte[] getBytesForBackup() throws IOException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- DataOutputStream out = new DataOutputStream(baos);
+ private String mPasspointUniqueId = null;
- out.writeInt(BACKUP_VERSION);
- BackupUtils.writeString(out, SSID);
- out.writeInt(apBand);
- out.writeInt(apChannel);
- BackupUtils.writeString(out, preSharedKey);
- out.writeInt(getAuthType());
- out.writeBoolean(hiddenSSID);
- return baos.toByteArray();
+ /**
+ * Set the Passpoint unique identifier
+ * @param uniqueId Passpoint unique identifier to be set
+ * @hide
+ */
+ public void setPasspointUniqueId(String uniqueId) {
+ mPasspointUniqueId = uniqueId;
}
/**
- * Deserializes a byte array into the WiFiConfiguration Object
+ * Set the Passpoint unique identifier
* @hide
*/
- public static WifiConfiguration getWifiConfigFromBackup(DataInputStream in) throws IOException,
- BackupUtils.BadVersionException {
- WifiConfiguration config = new WifiConfiguration();
- int version = in.readInt();
- if (version < 1 || version > BACKUP_VERSION) {
- throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
- }
+ public String getPasspointUniqueId() {
+ return mPasspointUniqueId;
+ }
- if (version == 1) return null; // Version 1 is a bad dataset.
+ /**
+ * If network is one of the most recently connected.
+ * For framework internal use only. Do not parcel.
+ * @hide
+ */
+ public boolean isMostRecentlyConnected = false;
- config.SSID = BackupUtils.readString(in);
- config.apBand = in.readInt();
- config.apChannel = in.readInt();
- config.preSharedKey = BackupUtils.readString(in);
- config.allowedKeyManagement.set(in.readInt());
- if (version >= 3) {
- config.hiddenSSID = in.readBoolean();
- }
- return config;
+ /**
+ * Whether the key mgmt indicates if the WifiConfiguration needs a preSharedKey or not.
+ * @return true if preSharedKey is needed, false otherwise.
+ * @hide
+ */
+ public boolean needsPreSharedKey() {
+ return allowedKeyManagement.get(KeyMgmt.WPA_PSK)
+ || allowedKeyManagement.get(KeyMgmt.SAE)
+ || allowedKeyManagement.get(KeyMgmt.WAPI_PSK);
}
+
}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index a9c2eb57291a..77fa673f1960 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -15,14 +15,18 @@
*/
package android.net.wifi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.security.Credentials;
import android.text.TextUtils;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
@@ -37,6 +41,36 @@ import java.util.Map;
*/
public class WifiEnterpriseConfig implements Parcelable {
+ /** Key prefix for WAPI AS certificates. */
+ public static final String WAPI_AS_CERTIFICATE = "WAPIAS_";
+
+ /** Key prefix for WAPI user certificates. */
+ public static final String WAPI_USER_CERTIFICATE = "WAPIUSR_";
+
+ /**
+ * Intent extra: name for WAPI AS certificates
+ */
+ public static final String EXTRA_WAPI_AS_CERTIFICATE_NAME =
+ "android.net.wifi.extra.WAPI_AS_CERTIFICATE_NAME";
+
+ /**
+ * Intent extra: data for WAPI AS certificates
+ */
+ public static final String EXTRA_WAPI_AS_CERTIFICATE_DATA =
+ "android.net.wifi.extra.WAPI_AS_CERTIFICATE_DATA";
+
+ /**
+ * Intent extra: name for WAPI USER certificates
+ */
+ public static final String EXTRA_WAPI_USER_CERTIFICATE_NAME =
+ "android.net.wifi.extra.WAPI_USER_CERTIFICATE_NAME";
+
+ /**
+ * Intent extra: data for WAPI USER certificates
+ */
+ public static final String EXTRA_WAPI_USER_CERTIFICATE_DATA =
+ "android.net.wifi.extra.WAPI_USER_CERTIFICATE_DATA";
+
/** @hide */
public static final String EMPTY_VALUE = "NULL";
/** @hide */
@@ -57,6 +91,11 @@ public class WifiEnterpriseConfig implements Parcelable {
public static final String DOM_SUFFIX_MATCH_KEY = "domain_suffix_match";
/** @hide */
public static final String OPP_KEY_CACHING = "proactive_key_caching";
+ /** @hide */
+ public static final String EAP_ERP = "eap_erp";
+ /** @hide */
+ public static final String OCSP = "ocsp";
+
/**
* String representing the keystore OpenSSL ENGINE's ID.
* @hide
@@ -88,10 +127,26 @@ public class WifiEnterpriseConfig implements Parcelable {
*/
public static final String ENGINE_DISABLE = "0";
+ /**
+ * Key prefix for CA certificates.
+ * Note: copied from {@link android.security.Credentials#CA_CERTIFICATE} since it is @hide.
+ */
+ private static final String CA_CERTIFICATE = "CACERT_";
+ /**
+ * Key prefix for user certificates.
+ * Note: copied from {@link android.security.Credentials#USER_CERTIFICATE} since it is @hide.
+ */
+ private static final String USER_CERTIFICATE = "USRCERT_";
+ /**
+ * Key prefix for user private and secret keys.
+ * Note: copied from {@link android.security.Credentials#USER_PRIVATE_KEY} since it is @hide.
+ */
+ private static final String USER_PRIVATE_KEY = "USRPKEY_";
+
/** @hide */
- public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
+ public static final String CA_CERT_PREFIX = KEYSTORE_URI + CA_CERTIFICATE;
/** @hide */
- public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE;
+ public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + USER_CERTIFICATE;
/** @hide */
public static final String CLIENT_CERT_KEY = "client_cert";
/** @hide */
@@ -110,6 +165,53 @@ public class WifiEnterpriseConfig implements Parcelable {
public static final String PLMN_KEY = "plmn";
/** @hide */
public static final String CA_CERT_ALIAS_DELIMITER = " ";
+ /** @hide */
+ public static final String WAPI_CERT_SUITE_KEY = "wapi_cert_suite";
+
+ /**
+ * Do not use OCSP stapling (TLS certificate status extension)
+ * @hide
+ */
+ @SystemApi
+ public static final int OCSP_NONE = 0;
+
+ /**
+ * Try to use OCSP stapling, but not require response
+ * @hide
+ */
+ @SystemApi
+ public static final int OCSP_REQUEST_CERT_STATUS = 1;
+
+ /**
+ * Require valid OCSP stapling response
+ * @hide
+ */
+ @SystemApi
+ public static final int OCSP_REQUIRE_CERT_STATUS = 2;
+
+ /**
+ * Require valid OCSP stapling response for all not-trusted certificates in the server
+ * certificate chain
+ * @hide
+ */
+ @SystemApi
+ public static final int OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS = 3;
+
+ /** @hide */
+ @IntDef(prefix = {"OCSP_"}, value = {
+ OCSP_NONE,
+ OCSP_REQUEST_CERT_STATUS,
+ OCSP_REQUIRE_CERT_STATUS,
+ OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Ocsp {}
+
+ /**
+ * Whether to use/require OCSP (Online Certificate Status Protocol) to check server certificate.
+ * @hide
+ */
+ private @Ocsp int mOcsp = OCSP_NONE;
// Fields to copy verbatim from wpa_supplicant.
private static final String[] SUPPLICANT_CONFIG_KEYS = new String[] {
@@ -130,7 +232,8 @@ public class WifiEnterpriseConfig implements Parcelable {
/**
* Fields that have unquoted values in {@link #mFields}.
*/
- private static final List<String> UNQUOTED_KEYS = Arrays.asList(ENGINE_KEY, OPP_KEY_CACHING);
+ private static final List<String> UNQUOTED_KEYS = Arrays.asList(ENGINE_KEY, OPP_KEY_CACHING,
+ EAP_ERP);
@UnsupportedAppUsage
private HashMap<String, String> mFields = new HashMap<String, String>();
@@ -185,6 +288,7 @@ public class WifiEnterpriseConfig implements Parcelable {
mPhase2Method = source.mPhase2Method;
mIsAppInstalledDeviceKeyAndCert = source.mIsAppInstalledDeviceKeyAndCert;
mIsAppInstalledCaCert = source.mIsAppInstalledCaCert;
+ mOcsp = source.mOcsp;
}
/**
@@ -230,6 +334,7 @@ public class WifiEnterpriseConfig implements Parcelable {
ParcelUtil.writeCertificates(dest, mClientCertificateChain);
dest.writeBoolean(mIsAppInstalledDeviceKeyAndCert);
dest.writeBoolean(mIsAppInstalledCaCert);
+ dest.writeInt(mOcsp);
}
public static final @android.annotation.NonNull Creator<WifiEnterpriseConfig> CREATOR =
@@ -251,6 +356,7 @@ public class WifiEnterpriseConfig implements Parcelable {
enterpriseConfig.mClientCertificateChain = ParcelUtil.readCertificates(in);
enterpriseConfig.mIsAppInstalledDeviceKeyAndCert = in.readBoolean();
enterpriseConfig.mIsAppInstalledCaCert = in.readBoolean();
+ enterpriseConfig.mOcsp = in.readInt();
return enterpriseConfig;
}
@@ -280,9 +386,12 @@ public class WifiEnterpriseConfig implements Parcelable {
public static final int AKA_PRIME = 6;
/** Hotspot 2.0 r2 OSEN */
public static final int UNAUTH_TLS = 7;
+ /** WAPI Certificate */
+ public static final int WAPI_CERT = 8;
/** @hide */
public static final String[] strings =
- { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'", "WFA-UNAUTH-TLS" };
+ { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'", "WFA-UNAUTH-TLS",
+ "WAPI_CERT" };
/** Prevent initialization */
private Eap() {}
@@ -375,7 +484,7 @@ public class WifiEnterpriseConfig implements Parcelable {
return false;
}
- if (mEapMethod != Eap.TLS && mPhase2Method != Phase2.NONE) {
+ if (mEapMethod != Eap.TLS && mEapMethod != Eap.UNAUTH_TLS && mPhase2Method != Phase2.NONE) {
boolean is_autheap = mEapMethod == Eap.TTLS && mPhase2Method == Phase2.GTC;
String prefix = is_autheap ? Phase2.AUTHEAP_PREFIX : Phase2.AUTH_PREFIX;
String value = convertToQuotedString(prefix + Phase2.strings[mPhase2Method]);
@@ -426,6 +535,10 @@ public class WifiEnterpriseConfig implements Parcelable {
public void setEapMethod(int eapMethod) {
switch (eapMethod) {
/** Valid methods */
+ case Eap.WAPI_CERT:
+ mEapMethod = eapMethod;
+ setPhase2Method(Phase2.NONE);
+ break;
case Eap.TLS:
case Eap.UNAUTH_TLS:
setPhase2Method(Phase2.NONE);
@@ -588,9 +701,11 @@ public class WifiEnterpriseConfig implements Parcelable {
* <p> See the {@link android.security.KeyChain} for details on installing or choosing
* a certificate.
* </p>
- * @param aliases identifies the certificate
+ * @param aliases identifies the certificate. Can be null to indicate the absence of a
+ * certificate.
* @hide
*/
+ @SystemApi
public void setCaCertificateAliases(@Nullable String[] aliases) {
if (aliases == null) {
setFieldValue(CA_CERT_KEY, null, CA_CERT_PREFIX);
@@ -604,7 +719,7 @@ public class WifiEnterpriseConfig implements Parcelable {
if (i > 0) {
sb.append(CA_CERT_ALIAS_DELIMITER);
}
- sb.append(encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + aliases[i]));
+ sb.append(encodeCaCertificateAlias(CA_CERTIFICATE + aliases[i]));
}
setFieldValue(CA_CERT_KEY, sb.toString(), KEYSTORES_URI);
}
@@ -621,11 +736,13 @@ public class WifiEnterpriseConfig implements Parcelable {
}
/**
- * Get CA certificate aliases
- * @return alias to the CA certificate
+ * Get CA certificate aliases.
+ * @return alias to the CA certificate, or null if unset.
* @hide
*/
- @Nullable public String[] getCaCertificateAliases() {
+ @Nullable
+ @SystemApi
+ public String[] getCaCertificateAliases() {
String value = getFieldValue(CA_CERT_KEY);
if (value.startsWith(CA_CERT_PREFIX)) {
// Backwards compatibility: parse the original alias prefix.
@@ -636,8 +753,8 @@ public class WifiEnterpriseConfig implements Parcelable {
String[] aliases = TextUtils.split(values, CA_CERT_ALIAS_DELIMITER);
for (int i = 0; i < aliases.length; i++) {
aliases[i] = decodeCaCertificateAlias(aliases[i]);
- if (aliases[i].startsWith(Credentials.CA_CERTIFICATE)) {
- aliases[i] = aliases[i].substring(Credentials.CA_CERTIFICATE.length());
+ if (aliases[i].startsWith(CA_CERTIFICATE)) {
+ aliases[i] = aliases[i].substring(CA_CERTIFICATE.length());
}
}
return aliases.length != 0 ? aliases : null;
@@ -654,6 +771,10 @@ public class WifiEnterpriseConfig implements Parcelable {
* certificate when the config is saved and removing the certificate when
* the config is removed.
*
+ * Note: If no certificate is set for an Enterprise configuration, either by not calling this
+ * API (or the {@link #setCaCertificates(X509Certificate[])}, or by calling it with null, then
+ * the server certificate validation is skipped - which means that the connection is not secure.
+ *
* @param cert X.509 CA certificate
* @throws IllegalArgumentException if not a CA certificate
*/
@@ -693,6 +814,11 @@ public class WifiEnterpriseConfig implements Parcelable {
* certificates when the config is saved and removing the certificates when
* the config is removed.
*
+ * Note: If no certificates are set for an Enterprise configuration, either by not calling this
+ * API (or the {@link #setCaCertificate(X509Certificate)}, or by calling it with null, then the
+ * server certificate validation is skipped - which means that the
+ * connection is not secure.
+ *
* @param certs X.509 CA certificates
* @throws IllegalArgumentException if any of the provided certificates is
* not a CA certificate
@@ -744,34 +870,45 @@ public class WifiEnterpriseConfig implements Parcelable {
* like /etc/ssl/certs. If configured, these certificates are added to the
* list of trusted CAs. ca_cert may also be included in that case, but it is
* not required.
- * @param domain The path for CA certificate files
+ *
+ * Note: If no certificate path is set for an Enterprise configuration, either by not calling
+ * this API, or by calling it with null, and no certificate is set by
+ * {@link #setCaCertificate(X509Certificate)} or {@link #setCaCertificates(X509Certificate[])},
+ * then the server certificate validation is skipped - which means that the connection is not
+ * secure.
+ *
+ * @param path The path for CA certificate files, or empty string to clear.
* @hide
*/
- public void setCaPath(String path) {
+ @SystemApi
+ public void setCaPath(@NonNull String path) {
setFieldValue(CA_PATH_KEY, path);
}
/**
- * Get the domain_suffix_match value. See setDomSuffixMatch.
- * @return The path for CA certificate files.
+ * Get the ca_path directive from wpa_supplicant.
+ * @return The path for CA certificate files, or an empty string if unset.
* @hide
*/
+ @NonNull
+ @SystemApi
public String getCaPath() {
return getFieldValue(CA_PATH_KEY);
}
- /** Set Client certificate alias.
+ /**
+ * Set Client certificate alias.
*
* <p> See the {@link android.security.KeyChain} for details on installing or choosing
* a certificate
* </p>
- * @param alias identifies the certificate
+ * @param alias identifies the certificate, or empty string to clear.
* @hide
*/
- @UnsupportedAppUsage
- public void setClientCertificateAlias(String alias) {
+ @SystemApi
+ public void setClientCertificateAlias(@NonNull String alias) {
setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX);
- setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY);
+ setFieldValue(PRIVATE_KEY_ID_KEY, alias, USER_PRIVATE_KEY);
// Also, set engine parameters
if (TextUtils.isEmpty(alias)) {
setFieldValue(ENGINE_KEY, ENGINE_DISABLE);
@@ -783,11 +920,12 @@ public class WifiEnterpriseConfig implements Parcelable {
}
/**
- * Get client certificate alias
- * @return alias to the client certificate
+ * Get client certificate alias.
+ * @return alias to the client certificate, or an empty string if unset.
* @hide
*/
- @UnsupportedAppUsage
+ @NonNull
+ @SystemApi
public String getClientCertificateAlias() {
return getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
}
@@ -911,8 +1049,10 @@ public class WifiEnterpriseConfig implements Parcelable {
}
/**
- * @hide
+ * Get the client private key as supplied in {@link #setClientKeyEntryWithCertificateChain}, or
+ * null if unset.
*/
+ @Nullable
public PrivateKey getClientPrivateKey() {
return mClientPrivateKey;
}
@@ -939,6 +1079,12 @@ public class WifiEnterpriseConfig implements Parcelable {
/**
* Set alternate subject match. This is the substring to be matched against the
* alternate subject of the authentication server certificate.
+ *
+ * Note: If no alternate subject is set for an Enterprise configuration, either by not calling
+ * this API, or by calling it with null, or not setting domain suffix match using the
+ * {@link #setDomainSuffixMatch(String)}, then the server certificate validation is incomplete -
+ * which means that the connection is not secure.
+ *
* @param altSubjectMatch substring to be matched, for example
* DNS:server.example.com;EMAIL:server@example.com
*/
@@ -973,6 +1119,12 @@ public class WifiEnterpriseConfig implements Parcelable {
* ORed ogether.
* <p>For example, domain_suffix_match=example.com would match test.example.com but would not
* match test-example.com.
+ *
+ * Note: If no domain suffix is set for an Enterprise configuration, either by not calling this
+ * API, or by calling it with null, or not setting alternate subject match using the
+ * {@link #setAltSubjectMatch(String)}, then the server certificate
+ * validation is incomplete - which means that the connection is not secure.
+ *
* @param domain The domain value
*/
public void setDomainSuffixMatch(String domain) {
@@ -1141,6 +1293,7 @@ public class WifiEnterpriseConfig implements Parcelable {
if (mPhase2Method > 0 && mPhase2Method < Phase2.strings.length) {
sb.append("phase2_method: ").append(Phase2.strings[mPhase2Method]).append("\n");
}
+ sb.append(" ocsp: ").append(mOcsp).append("\n");
return sb.toString();
}
@@ -1190,4 +1343,103 @@ public class WifiEnterpriseConfig implements Parcelable {
public boolean isAppInstalledCaCert() {
return mIsAppInstalledCaCert;
}
+
+ /**
+ * Set the OCSP type.
+ * @param ocsp is one of {@link ##OCSP_NONE}, {@link #OCSP_REQUEST_CERT_STATUS},
+ * {@link #OCSP_REQUIRE_CERT_STATUS} or
+ * {@link #OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS}
+ * @throws IllegalArgumentException if the OCSP type is invalid
+ * @hide
+ */
+ @SystemApi
+ public void setOcsp(@Ocsp int ocsp) {
+ if (ocsp >= OCSP_NONE && ocsp <= OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS) {
+ mOcsp = ocsp;
+ } else {
+ throw new IllegalArgumentException("Invalid OCSP type.");
+ }
+ }
+
+ /**
+ * Get the OCSP type.
+ * @hide
+ */
+ @SystemApi
+ public @Ocsp int getOcsp() {
+ return mOcsp;
+ }
+
+ /**
+ * Utility method to determine whether the configuration's authentication method is SIM-based.
+ *
+ * @return true if the credential information requires SIM card for current authentication
+ * method, otherwise it returns false.
+ */
+ public boolean isAuthenticationSimBased() {
+ if (mEapMethod == Eap.SIM || mEapMethod == Eap.AKA || mEapMethod == Eap.AKA_PRIME) {
+ return true;
+ }
+ if (mEapMethod == Eap.PEAP) {
+ return mPhase2Method == Phase2.SIM || mPhase2Method == Phase2.AKA
+ || mPhase2Method == Phase2.AKA_PRIME;
+ }
+ return false;
+ }
+
+ /**
+ * Set the WAPI certificate suite name on wpa_supplicant.
+ *
+ * If this field is not specified, WAPI-CERT uses ASU ID from WAI packet
+ * as the certificate suite name automatically.
+ *
+ * @param wapiCertSuite The name for WAPI certificate suite, or empty string to clear.
+ * @hide
+ */
+ @SystemApi
+ public void setWapiCertSuite(@NonNull String wapiCertSuite) {
+ setFieldValue(WAPI_CERT_SUITE_KEY, wapiCertSuite);
+ }
+
+ /**
+ * Get the WAPI certificate suite name
+ * @return the certificate suite name
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public String getWapiCertSuite() {
+ return getFieldValue(WAPI_CERT_SUITE_KEY);
+ }
+
+ /**
+ * Method determines whether the Enterprise configuration is insecure. An insecure
+ * configuration is one where EAP method requires a CA certification, i.e. PEAP, TLS, or
+ * TTLS, and any of the following conditions are met:
+ * - Both certificate and CA path are not configured.
+ * - Both alternative subject match and domain suffix match are not set.
+ *
+ * Note: this method does not exhaustively check security of the configuration - i.e. a return
+ * value of {@code false} is not a guarantee that the configuration is secure.
+ * @hide
+ */
+ public boolean isInsecure() {
+ if (mEapMethod != Eap.PEAP && mEapMethod != Eap.TLS && mEapMethod != Eap.TTLS) {
+ return false;
+ }
+ if (TextUtils.isEmpty(getAltSubjectMatch())
+ && TextUtils.isEmpty(getDomainSuffixMatch())) {
+ // Both subject and domain match are not set, it's insecure.
+ return true;
+ }
+ if (mIsAppInstalledCaCert) {
+ // CA certificate is installed by App, it's secure.
+ return false;
+ }
+ if (getCaCertificateAliases() != null) {
+ // CA certificate alias from keyStore is set, it's secure.
+ return false;
+ }
+ return TextUtils.isEmpty(getCaPath());
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiFrameworkInitializer.java b/wifi/java/android/net/wifi/WifiFrameworkInitializer.java
new file mode 100644
index 000000000000..1507199b0264
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiFrameworkInitializer.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.wifi;
+
+import android.annotation.SystemApi;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+import android.net.wifi.aware.IWifiAwareManager;
+import android.net.wifi.aware.WifiAwareManager;
+import android.net.wifi.p2p.IWifiP2pManager;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.rtt.IWifiRttManager;
+import android.net.wifi.rtt.WifiRttManager;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+/**
+ * Class for performing registration for all Wifi services.
+ *
+ * @hide
+ */
+@SystemApi
+public class WifiFrameworkInitializer {
+
+ /**
+ * A class implementing the lazy holder idiom: the unique static instance
+ * of {@link #INSTANCE} is instantiated in a thread-safe way (guaranteed by
+ * the language specs) the first time that NoPreloadHolder is referenced in getInstanceLooper().
+ *
+ * This is necessary because we can't spawn a new thread in {@link #registerServiceWrappers()}.
+ * {@link #registerServiceWrappers()} is called during the Zygote phase, which disallows
+ * spawning new threads. Naming the class "NoPreloadHolder" ensures that the classloader will
+ * not preload this class, inadvertently spawning the thread too early.
+ */
+ private static class NoPreloadHolder {
+ private static final HandlerThread INSTANCE = createInstance();
+
+ private static HandlerThread createInstance() {
+ HandlerThread thread = new HandlerThread("WifiManagerThread");
+ thread.start();
+ return thread;
+ }
+ }
+
+ private static Looper getInstanceLooper() {
+ return NoPreloadHolder.INSTANCE.getLooper();
+ }
+
+ private WifiFrameworkInitializer() {}
+
+ /**
+ * Called by {@link SystemServiceRegistry}'s static initializer and registers all Wifi services
+ * to {@link Context}, so that {@link Context#getSystemService} can return them.
+ *
+ * @throws IllegalStateException if this is called from anywhere besides
+ * {@link SystemServiceRegistry}
+ */
+ public static void registerServiceWrappers() {
+ SystemServiceRegistry.registerContextAwareService(
+ Context.WIFI_SERVICE,
+ WifiManager.class,
+ (context, serviceBinder) -> {
+ IWifiManager service = IWifiManager.Stub.asInterface(serviceBinder);
+ return new WifiManager(context, service, getInstanceLooper());
+ }
+ );
+ SystemServiceRegistry.registerStaticService(
+ Context.WIFI_P2P_SERVICE,
+ WifiP2pManager.class,
+ serviceBinder -> {
+ IWifiP2pManager service = IWifiP2pManager.Stub.asInterface(serviceBinder);
+ return new WifiP2pManager(service);
+ }
+ );
+ SystemServiceRegistry.registerContextAwareService(
+ Context.WIFI_AWARE_SERVICE,
+ WifiAwareManager.class,
+ (context, serviceBinder) -> {
+ IWifiAwareManager service = IWifiAwareManager.Stub.asInterface(serviceBinder);
+ return new WifiAwareManager(context, service);
+ }
+ );
+ SystemServiceRegistry.registerContextAwareService(
+ Context.WIFI_SCANNING_SERVICE,
+ WifiScanner.class,
+ (context, serviceBinder) -> {
+ IWifiScanner service = IWifiScanner.Stub.asInterface(serviceBinder);
+ return new WifiScanner(context, service, getInstanceLooper());
+ }
+ );
+ SystemServiceRegistry.registerContextAwareService(
+ Context.WIFI_RTT_RANGING_SERVICE,
+ WifiRttManager.class,
+ (context, serviceBinder) -> {
+ IWifiRttManager service = IWifiRttManager.Stub.asInterface(serviceBinder);
+ return new WifiRttManager(context, service);
+ }
+ );
+ SystemServiceRegistry.registerContextAwareService(
+ Context.WIFI_RTT_SERVICE,
+ RttManager.class,
+ context -> {
+ WifiRttManager wifiRttManager = context.getSystemService(WifiRttManager.class);
+ return new RttManager(context, wifiRttManager);
+ }
+ );
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 0204113b614b..53883674e058 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -17,16 +17,18 @@
package android.net.wifi;
import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.net.module.util.Inet4AddressUtils;
+
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -34,7 +36,7 @@ import java.util.EnumMap;
import java.util.Locale;
/**
- * Describes the state of any Wifi connection that is active or
+ * Describes the state of any Wi-Fi connection that is active or
* is in the process of being set up.
*/
public class WifiInfo implements Parcelable {
@@ -53,7 +55,7 @@ public class WifiInfo implements Parcelable {
*
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
static {
@@ -79,8 +81,12 @@ public class WifiInfo implements Parcelable {
private WifiSsid mWifiSsid;
private int mNetworkId;
- /** @hide **/
- @UnsupportedAppUsage
+ /**
+ * Used to indicate that the RSSI is invalid, for example if no RSSI measurements are available
+ * yet.
+ * @hide
+ */
+ @SystemApi
public static final int INVALID_RSSI = -127;
/** @hide **/
@@ -96,6 +102,11 @@ public class WifiInfo implements Parcelable {
private int mRssi;
/**
+ * Wi-Fi standard for the connection
+ */
+ private @WifiAnnotations.WifiStandard int mWifiStandard;
+
+ /**
* The unit in which links speeds are expressed.
*/
public static final String LINK_SPEED_UNITS = "Mbps";
@@ -112,11 +123,21 @@ public class WifiInfo implements Parcelable {
private int mTxLinkSpeed;
/**
+ * Max supported Tx(transmit) link speed in Mbps
+ */
+ private int mMaxSupportedTxLinkSpeed;
+
+ /**
* Rx(receive) Link speed in Mbps
*/
private int mRxLinkSpeed;
/**
+ * Max supported Rx(receive) link speed in Mbps
+ */
+ private int mMaxSupportedRxLinkSpeed;
+
+ /**
* Frequency in MHz
*/
public static final String FREQUENCY_UNITS = "MHz";
@@ -156,7 +177,7 @@ public class WifiInfo implements Parcelable {
* If connected to a network suggestion or specifier, store the package name of the app,
* else null.
*/
- private String mNetworkSuggestionOrSpecifierPackageName;
+ private String mRequestingPackageName;
/**
* Running total count of lost (not ACKed) transmitted unicast data packets.
@@ -179,32 +200,89 @@ public class WifiInfo implements Parcelable {
*/
public long rxSuccess;
+ private double mLostTxPacketsPerSecond;
+
/**
* Average rate of lost transmitted packets, in units of packets per second.
* @hide
*/
- public double txBadRate;
+ @SystemApi
+ public double getLostTxPacketsPerSecond() {
+ return mLostTxPacketsPerSecond;
+ }
+
+ /** @hide */
+ public void setLostTxPacketsPerSecond(double lostTxPacketsPerSecond) {
+ mLostTxPacketsPerSecond = lostTxPacketsPerSecond;
+ }
+
+ private double mTxRetriedTxPacketsPerSecond;
+
/**
* Average rate of transmitted retry packets, in units of packets per second.
* @hide
*/
- public double txRetriesRate;
+ @SystemApi
+ public double getRetriedTxPacketsPerSecond() {
+ return mTxRetriedTxPacketsPerSecond;
+ }
+
+ /** @hide */
+ public void setRetriedTxPacketsRate(double txRetriedTxPacketsPerSecond) {
+ mTxRetriedTxPacketsPerSecond = txRetriedTxPacketsPerSecond;
+ }
+
+ private double mSuccessfulTxPacketsPerSecond;
+
/**
* Average rate of successfully transmitted unicast packets, in units of packets per second.
* @hide
*/
- public double txSuccessRate;
+ @SystemApi
+ public double getSuccessfulTxPacketsPerSecond() {
+ return mSuccessfulTxPacketsPerSecond;
+ }
+
+ /** @hide */
+ public void setSuccessfulTxPacketsPerSecond(double successfulTxPacketsPerSecond) {
+ mSuccessfulTxPacketsPerSecond = successfulTxPacketsPerSecond;
+ }
+
+ private double mSuccessfulRxPacketsPerSecond;
+
/**
* Average rate of received unicast data packets, in units of packets per second.
* @hide
*/
- public double rxSuccessRate;
+ @SystemApi
+ public double getSuccessfulRxPacketsPerSecond() {
+ return mSuccessfulRxPacketsPerSecond;
+ }
+
+ /** @hide */
+ public void setSuccessfulRxPacketsPerSecond(double successfulRxPacketsPerSecond) {
+ mSuccessfulRxPacketsPerSecond = successfulRxPacketsPerSecond;
+ }
+
+ /** @hide */
+ @UnsupportedAppUsage
+ public int score;
/**
+ * The current Wifi score.
+ * NOTE: this value should only be used for debugging purposes. Do not rely on this value for
+ * any computations. The meaning of this value can and will change at any time without warning.
* @hide
*/
- @UnsupportedAppUsage
- public int score;
+ @SystemApi
+ public int getScore() {
+ return score;
+ }
+
+ /** @hide */
+ public void setScore(int score) {
+ this.score = score;
+ }
/**
* Flag indicating that AP has hinted that upstream connection is metered,
@@ -212,6 +290,11 @@ public class WifiInfo implements Parcelable {
*/
private boolean mMeteredHint;
+ /**
+ * Passpoint unique key
+ */
+ private String mPasspointUniqueId;
+
/** @hide */
@UnsupportedAppUsage
public WifiInfo() {
@@ -234,21 +317,24 @@ public class WifiInfo implements Parcelable {
setLinkSpeed(LINK_SPEED_UNKNOWN);
setTxLinkSpeedMbps(LINK_SPEED_UNKNOWN);
setRxLinkSpeedMbps(LINK_SPEED_UNKNOWN);
+ setMaxSupportedTxLinkSpeedMbps(LINK_SPEED_UNKNOWN);
+ setMaxSupportedRxLinkSpeedMbps(LINK_SPEED_UNKNOWN);
setFrequency(-1);
setMeteredHint(false);
setEphemeral(false);
setOsuAp(false);
- setNetworkSuggestionOrSpecifierPackageName(null);
+ setRequestingPackageName(null);
setFQDN(null);
setProviderFriendlyName(null);
+ setPasspointUniqueId(null);
txBad = 0;
txSuccess = 0;
rxSuccess = 0;
txRetries = 0;
- txBadRate = 0;
- txSuccessRate = 0;
- rxSuccessRate = 0;
- txRetriesRate = 0;
+ mLostTxPacketsPerSecond = 0;
+ mSuccessfulTxPacketsPerSecond = 0;
+ mSuccessfulRxPacketsPerSecond = 0;
+ mTxRetriedTxPacketsPerSecond = 0;
score = 0;
}
@@ -272,8 +358,8 @@ public class WifiInfo implements Parcelable {
mMeteredHint = source.mMeteredHint;
mEphemeral = source.mEphemeral;
mTrusted = source.mTrusted;
- mNetworkSuggestionOrSpecifierPackageName =
- source.mNetworkSuggestionOrSpecifierPackageName;
+ mRequestingPackageName =
+ source.mRequestingPackageName;
mOsuAp = source.mOsuAp;
mFqdn = source.mFqdn;
mProviderFriendlyName = source.mProviderFriendlyName;
@@ -281,11 +367,68 @@ public class WifiInfo implements Parcelable {
txRetries = source.txRetries;
txSuccess = source.txSuccess;
rxSuccess = source.rxSuccess;
- txBadRate = source.txBadRate;
- txRetriesRate = source.txRetriesRate;
- txSuccessRate = source.txSuccessRate;
- rxSuccessRate = source.rxSuccessRate;
+ mLostTxPacketsPerSecond = source.mLostTxPacketsPerSecond;
+ mTxRetriedTxPacketsPerSecond = source.mTxRetriedTxPacketsPerSecond;
+ mSuccessfulTxPacketsPerSecond = source.mSuccessfulTxPacketsPerSecond;
+ mSuccessfulRxPacketsPerSecond = source.mSuccessfulRxPacketsPerSecond;
score = source.score;
+ mWifiStandard = source.mWifiStandard;
+ mMaxSupportedTxLinkSpeed = source.mMaxSupportedTxLinkSpeed;
+ mMaxSupportedRxLinkSpeed = source.mMaxSupportedRxLinkSpeed;
+ mPasspointUniqueId = source.mPasspointUniqueId;
+ }
+ }
+
+ /** Builder for WifiInfo */
+ public static final class Builder {
+ private final WifiInfo mWifiInfo = new WifiInfo();
+
+ /**
+ * Set the SSID, in the form of a raw byte array.
+ * @see WifiInfo#getSSID()
+ */
+ @NonNull
+ public Builder setSsid(@NonNull byte[] ssid) {
+ mWifiInfo.setSSID(WifiSsid.createFromByteArray(ssid));
+ return this;
+ }
+
+ /**
+ * Set the BSSID.
+ * @see WifiInfo#getBSSID()
+ */
+ @NonNull
+ public Builder setBssid(@NonNull String bssid) {
+ mWifiInfo.setBSSID(bssid);
+ return this;
+ }
+
+ /**
+ * Set the RSSI, in dBm.
+ * @see WifiInfo#getRssi()
+ */
+ @NonNull
+ public Builder setRssi(int rssi) {
+ mWifiInfo.setRssi(rssi);
+ return this;
+ }
+
+ /**
+ * Set the network ID.
+ * @see WifiInfo#getNetworkId()
+ */
+ @NonNull
+ public Builder setNetworkId(int networkId) {
+ mWifiInfo.setNetworkId(networkId);
+ return this;
+ }
+
+ /**
+ * Build a WifiInfo object.
+ */
+ @NonNull
+ public WifiInfo build() {
+ return new WifiInfo(mWifiInfo);
}
}
@@ -299,9 +442,8 @@ public class WifiInfo implements Parcelable {
* <p>
* If the SSID can be decoded as UTF-8, it will be returned surrounded by double
* quotation marks. Otherwise, it is returned as a string of hex digits.
- * The SSID may be
- * <lt>&lt;unknown ssid&gt;, if there is no network currently connected or if the caller has
- * insufficient permissions to access the SSID.<lt>
+ * The SSID may be {@link WifiManager#UNKNOWN_SSID}, if there is no network currently connected
+ * or if the caller has insufficient permissions to access the SSID.
* </p>
* <p>
* Prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method
@@ -317,10 +459,10 @@ public class WifiInfo implements Parcelable {
return "\"" + unicode + "\"";
} else {
String hex = mWifiSsid.getHexString();
- return (hex != null) ? hex : WifiSsid.NONE;
+ return (hex != null) ? hex : WifiManager.UNKNOWN_SSID;
}
}
- return WifiSsid.NONE;
+ return WifiManager.UNKNOWN_SSID;
}
/** @hide */
@@ -374,6 +516,22 @@ public class WifiInfo implements Parcelable {
}
/**
+ * Sets the Wi-Fi standard
+ * @hide
+ */
+ public void setWifiStandard(@WifiAnnotations.WifiStandard int wifiStandard) {
+ mWifiStandard = wifiStandard;
+ }
+
+ /**
+ * Get connection Wi-Fi standard
+ * @return the connection Wi-Fi standard
+ */
+ public @WifiAnnotations.WifiStandard int getWifiStandard() {
+ return mWifiStandard;
+ }
+
+ /**
* Returns the current link speed in {@link #LINK_SPEED_UNITS}.
* @return the link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is unknown.
* @see #LINK_SPEED_UNITS
@@ -400,6 +558,15 @@ public class WifiInfo implements Parcelable {
}
/**
+ * Returns the maximum supported transmit link speed in Mbps
+ * @return the max supported tx link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is
+ * unknown. @see #LINK_SPEED_UNKNOWN
+ */
+ public int getMaxSupportedTxLinkSpeedMbps() {
+ return mMaxSupportedTxLinkSpeed;
+ }
+
+ /**
* Update the last transmitted packet bit rate in Mbps.
* @hide
*/
@@ -408,6 +575,14 @@ public class WifiInfo implements Parcelable {
}
/**
+ * Set the maximum supported transmit link speed in Mbps
+ * @hide
+ */
+ public void setMaxSupportedTxLinkSpeedMbps(int maxSupportedTxLinkSpeed) {
+ mMaxSupportedTxLinkSpeed = maxSupportedTxLinkSpeed;
+ }
+
+ /**
* Returns the current receive link speed in Mbps.
* @return the Rx link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is unknown.
* @see #LINK_SPEED_UNKNOWN
@@ -418,6 +593,15 @@ public class WifiInfo implements Parcelable {
}
/**
+ * Returns the maximum supported receive link speed in Mbps
+ * @return the max supported Rx link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is
+ * unknown. @see #LINK_SPEED_UNKNOWN
+ */
+ public int getMaxSupportedRxLinkSpeedMbps() {
+ return mMaxSupportedRxLinkSpeed;
+ }
+
+ /**
* Update the last received packet bit rate in Mbps.
* @hide
*/
@@ -426,6 +610,14 @@ public class WifiInfo implements Parcelable {
}
/**
+ * Set the maximum supported receive link speed in Mbps
+ * @hide
+ */
+ public void setMaxSupportedRxLinkSpeedMbps(int maxSupportedRxLinkSpeed) {
+ mMaxSupportedRxLinkSpeed = maxSupportedRxLinkSpeed;
+ }
+
+ /**
* Returns the current frequency in {@link #FREQUENCY_UNITS}.
* @return the frequency.
* @see #FREQUENCY_UNITS
@@ -441,7 +633,6 @@ public class WifiInfo implements Parcelable {
/**
* @hide
- * TODO: makes real freq boundaries
*/
public boolean is24GHz() {
return ScanResult.is24GHz(mFrequency);
@@ -449,7 +640,6 @@ public class WifiInfo implements Parcelable {
/**
* @hide
- * TODO: makes real freq boundaries
*/
@UnsupportedAppUsage
public boolean is5GHz() {
@@ -457,6 +647,13 @@ public class WifiInfo implements Parcelable {
}
/**
+ * @hide
+ */
+ public boolean is6GHz() {
+ return ScanResult.is6GHz(mFrequency);
+ }
+
+ /**
* Record the MAC address of the WLAN interface
* @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
* @hide
@@ -501,8 +698,15 @@ public class WifiInfo implements Parcelable {
mEphemeral = ephemeral;
}
- /** {@hide} */
- @UnsupportedAppUsage
+ /**
+ * Returns true if the current Wifi network is ephemeral, false otherwise.
+ * An ephemeral network is a network that is temporary and not persisted in the system.
+ * Ephemeral networks cannot be forgotten, only disabled with
+ * {@link WifiManager#disableEphemeralNetwork(String)}.
+ *
+ * @hide
+ */
+ @SystemApi
public boolean isEphemeral() {
return mEphemeral;
}
@@ -541,6 +745,11 @@ public class WifiInfo implements Parcelable {
/**
* Returns the Fully Qualified Domain Name of the network if it is a Passpoint network.
+ * <p>
+ * The FQDN may be
+ * <lt>{@code null} if no network currently connected, currently connected network is not
+ * passpoint network or the caller has insufficient permissions to access the FQDN.</lt>
+ * </p>
*/
public @Nullable String getPasspointFqdn() {
return mFqdn;
@@ -553,19 +762,31 @@ public class WifiInfo implements Parcelable {
/**
* Returns the Provider Friendly Name of the network if it is a Passpoint network.
+ * <p>
+ * The Provider Friendly Name may be
+ * <lt>{@code null} if no network currently connected, currently connected network is not
+ * passpoint network or the caller has insufficient permissions to access the Provider Friendly
+ * Name. </lt>
+ * </p>
*/
public @Nullable String getPasspointProviderFriendlyName() {
return mProviderFriendlyName;
}
/** {@hide} */
- public void setNetworkSuggestionOrSpecifierPackageName(@Nullable String packageName) {
- mNetworkSuggestionOrSpecifierPackageName = packageName;
+ public void setRequestingPackageName(@Nullable String packageName) {
+ mRequestingPackageName = packageName;
}
- /** {@hide} */
- public @Nullable String getNetworkSuggestionOrSpecifierPackageName() {
- return mNetworkSuggestionOrSpecifierPackageName;
+ /**
+ * If this network was created in response to an app request (e.g. through Network Suggestion
+ * or Network Specifier), return the package name of the app that made the request.
+ * Null otherwise.
+ * @hide
+ */
+ @SystemApi
+ public @Nullable String getRequestingPackageName() {
+ return mRequestingPackageName;
}
@@ -612,7 +833,7 @@ public class WifiInfo implements Parcelable {
public int getIpAddress() {
int result = 0;
if (mIpAddress instanceof Inet4Address) {
- result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress);
+ result = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) mIpAddress);
}
return result;
}
@@ -626,7 +847,7 @@ public class WifiInfo implements Parcelable {
return mWifiSsid.isHidden();
}
- /**
+ /**
* Map a supplicant state into a fine-grained network connectivity state.
* @param suppState the supplicant state
* @return the corresponding {@link DetailedState}
@@ -686,15 +907,20 @@ public class WifiInfo implements Parcelable {
StringBuffer sb = new StringBuffer();
String none = "<none>";
- sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid)
+ sb.append("SSID: ").append(mWifiSsid == null ? WifiManager.UNKNOWN_SSID : mWifiSsid)
.append(", BSSID: ").append(mBSSID == null ? none : mBSSID)
.append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
.append(", Supplicant state: ")
.append(mSupplicantState == null ? none : mSupplicantState)
+ .append(", Wi-Fi standard: ").append(mWifiStandard)
.append(", RSSI: ").append(mRssi)
.append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS)
.append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS)
+ .append(", Max Supported Tx Link speed: ")
+ .append(mMaxSupportedTxLinkSpeed).append(LINK_SPEED_UNITS)
.append(", Rx Link speed: ").append(mRxLinkSpeed).append(LINK_SPEED_UNITS)
+ .append(", Max Supported Rx Link speed: ")
+ .append(mMaxSupportedRxLinkSpeed).append(LINK_SPEED_UNITS)
.append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS)
.append(", Net ID: ").append(mNetworkId)
.append(", Metered hint: ").append(mMeteredHint)
@@ -734,18 +960,22 @@ public class WifiInfo implements Parcelable {
dest.writeInt(mTrusted ? 1 : 0);
dest.writeInt(score);
dest.writeLong(txSuccess);
- dest.writeDouble(txSuccessRate);
+ dest.writeDouble(mSuccessfulTxPacketsPerSecond);
dest.writeLong(txRetries);
- dest.writeDouble(txRetriesRate);
+ dest.writeDouble(mTxRetriedTxPacketsPerSecond);
dest.writeLong(txBad);
- dest.writeDouble(txBadRate);
+ dest.writeDouble(mLostTxPacketsPerSecond);
dest.writeLong(rxSuccess);
- dest.writeDouble(rxSuccessRate);
+ dest.writeDouble(mSuccessfulRxPacketsPerSecond);
mSupplicantState.writeToParcel(dest, flags);
dest.writeInt(mOsuAp ? 1 : 0);
- dest.writeString(mNetworkSuggestionOrSpecifierPackageName);
+ dest.writeString(mRequestingPackageName);
dest.writeString(mFqdn);
dest.writeString(mProviderFriendlyName);
+ dest.writeInt(mWifiStandard);
+ dest.writeInt(mMaxSupportedTxLinkSpeed);
+ dest.writeInt(mMaxSupportedRxLinkSpeed);
+ dest.writeString(mPasspointUniqueId);
}
/** Implement the Parcelable interface {@hide} */
@@ -775,18 +1005,22 @@ public class WifiInfo implements Parcelable {
info.mTrusted = in.readInt() != 0;
info.score = in.readInt();
info.txSuccess = in.readLong();
- info.txSuccessRate = in.readDouble();
+ info.mSuccessfulTxPacketsPerSecond = in.readDouble();
info.txRetries = in.readLong();
- info.txRetriesRate = in.readDouble();
+ info.mTxRetriedTxPacketsPerSecond = in.readDouble();
info.txBad = in.readLong();
- info.txBadRate = in.readDouble();
+ info.mLostTxPacketsPerSecond = in.readDouble();
info.rxSuccess = in.readLong();
- info.rxSuccessRate = in.readDouble();
+ info.mSuccessfulRxPacketsPerSecond = in.readDouble();
info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
info.mOsuAp = in.readInt() != 0;
- info.mNetworkSuggestionOrSpecifierPackageName = in.readString();
+ info.mRequestingPackageName = in.readString();
info.mFqdn = in.readString();
info.mProviderFriendlyName = in.readString();
+ info.mWifiStandard = in.readInt();
+ info.mMaxSupportedTxLinkSpeed = in.readInt();
+ info.mMaxSupportedRxLinkSpeed = in.readInt();
+ info.mPasspointUniqueId = in.readString();
return info;
}
@@ -794,4 +1028,24 @@ public class WifiInfo implements Parcelable {
return new WifiInfo[size];
}
};
+
+ /**
+ * Set the Passpoint unique identifier for the current connection
+ *
+ * @param passpointUniqueId Unique identifier
+ * @hide
+ */
+ public void setPasspointUniqueId(@Nullable String passpointUniqueId) {
+ mPasspointUniqueId = passpointUniqueId;
+ }
+
+ /**
+ * Get the Passpoint unique identifier for the current connection
+ *
+ * @return Passpoint unique identifier
+ * @hide
+ */
+ public @Nullable String getPasspointUniqueId() {
+ return mPasspointUniqueId;
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 29e09a11590b..fb6af5b550b0 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -22,11 +22,13 @@ import static android.Manifest.permission.READ_WIFI_CREDENTIAL;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.ActivityManager;
@@ -35,9 +37,8 @@ import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
+import android.net.MacAddress;
import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
import android.net.NetworkStack;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
@@ -46,26 +47,24 @@ import android.net.wifi.hotspot2.ProvisioningCallback;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
import android.os.RemoteException;
import android.os.WorkSource;
+import android.os.connectivity.WifiActivityEnergyInfo;
+import android.text.TextUtils;
+import android.util.CloseGuard;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.Protocol;
-import com.android.server.net.NetworkPinner;
-
-import dalvik.system.CloseGuard;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.util.ArrayList;
@@ -73,8 +72,9 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.CountDownLatch;
+import java.util.StringTokenizer;
import java.util.concurrent.Executor;
/**
@@ -153,12 +153,11 @@ public class WifiManager {
@Deprecated
public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
- /**
- * Maximum number of active network suggestions allowed per app.
- * @hide
- */
- public static final int NETWORK_SUGGESTIONS_MAX_PER_APP =
- ActivityManager.isLowRamDeviceStatic() ? 256 : 1024;
+ /** @hide */
+ public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM = 256;
+
+ /** @hide */
+ public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM = 1024;
/**
* Reason code if all of the network suggestions were successfully added or removed.
@@ -180,6 +179,8 @@ public class WifiManager {
/**
* Reason code if one or more of the network suggestions added already exists in platform's
* database.
+ * Note: this code will not be returned with Android 11 as in-place modification is allowed,
+ * please check {@link #addNetworkSuggestions(List)}.
* @see WifiNetworkSuggestion#equals(Object)
*/
public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3;
@@ -187,6 +188,8 @@ public class WifiManager {
/**
* Reason code if the number of network suggestions provided by the app crosses the max
* threshold set per app.
+ * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)} if
+ * the total size exceeds the limit.
* @see #getMaxNumberOfNetworkSuggestionsPerApp()
*/
public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4;
@@ -194,9 +197,30 @@ public class WifiManager {
/**
* Reason code if one or more of the network suggestions removed does not exist in platform's
* database.
+ * The framework won't remove any suggestions if one or more of suggestions provided
+ * by {@link #removeNetworkSuggestions(List)} does not exist in database.
+ * @see WifiNetworkSuggestion#equals(Object)
*/
public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
+ /**
+ * Reason code if one or more of the network suggestions added is not allowed.
+ * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
+ * if one or more of them is not allowed.
+ * This error may be caused by suggestion is using SIM-based encryption method, but calling app
+ * is not carrier privileged.
+ */
+ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED = 6;
+
+ /**
+ * Reason code if one or more of the network suggestions added is invalid. Framework will reject
+ * all the suggestions in the list.
+ * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
+ * if one or more of them is invalid.
+ * Please use {@link WifiNetworkSuggestion.Builder} to create network suggestions.
+ */
+ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID = 7;
+
/** @hide */
@IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
STATUS_NETWORK_SUGGESTIONS_SUCCESS,
@@ -205,21 +229,54 @@ public class WifiManager {
STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE,
STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP,
STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID,
+ STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED,
+ STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID,
})
@Retention(RetentionPolicy.SOURCE)
public @interface NetworkSuggestionsStatusCode {}
/**
- * Broadcast intent action indicating whether Wi-Fi scanning is allowed currently
- * @hide
+ * Reason code if suggested network connection attempt failed with an unknown failure.
+ */
+ public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN = 0;
+ /**
+ * Reason code if suggested network connection attempt failed with association failure.
*/
- public static final String WIFI_SCAN_AVAILABLE = "wifi_scan_available";
+ public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1;
+ /**
+ * Reason code if suggested network connection attempt failed with an authentication failure.
+ */
+ public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2;
+ /**
+ * Reason code if suggested network connection attempt failed with an IP provision failure.
+ */
+ public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3;
+
+ /** @hide */
+ @IntDef(prefix = {"STATUS_SUGGESTION_CONNECTION_FAILURE_"},
+ value = {STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN,
+ STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION,
+ STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION,
+ STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SuggestionConnectionStatusCode {}
/**
- * Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED
- * @hide
+ * Broadcast intent action indicating whether Wi-Fi scanning is currently available.
+ * Available extras:
+ * - {@link #EXTRA_SCAN_AVAILABLE}
*/
- public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_WIFI_SCAN_AVAILABILITY_CHANGED =
+ "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED";
+
+ /**
+ * A boolean extra indicating whether scanning is currently available.
+ * Sent in the broadcast {@link #ACTION_WIFI_SCAN_AVAILABILITY_CHANGED}.
+ * Its value is true if scanning is currently available, false otherwise.
+ */
+ public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE";
/**
* Broadcast intent action indicating that the credential of a Wi-Fi network
@@ -355,14 +412,6 @@ public class WifiManager {
* @hide
*/
public static final String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
- /**
- * String representation of an URL.
- *
- * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
- *
- * @hide
- */
- public static final String EXTRA_URL = "android.net.wifi.extra.URL";
/**
* Broadcast intent action indicating a Passpoint subscription remediation frame has been
@@ -395,34 +444,49 @@ public class WifiManager {
"android.net.wifi.extra.SUBSCRIPTION_REMEDIATION_METHOD";
/**
- * Activity Action: lunch OSU (Online Sign Up) view.
+ * Activity Action: Receiver should launch Passpoint OSU (Online Sign Up) view.
* Included extras:
*
* {@link #EXTRA_OSU_NETWORK}: {@link Network} instance associated with OSU AP.
* {@link #EXTRA_URL}: String representation of a server URL used for OSU process.
*
- * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
- * components will be launched.
- *
* @hide
*/
+ @SystemApi
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW =
"android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
/**
- * The lookup key for a {@link android.net.Network} associated with OSU server.
+ * The lookup key for a {@link android.net.Network} associated with a Passpoint OSU server.
+ * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
*
* Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
*
* @hide
*/
+ @SystemApi
public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
/**
+ * String representation of an URL for Passpoint OSU.
+ * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
+ *
+ * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_URL = "android.net.wifi.extra.URL";
+
+ /**
* Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
* enabling, disabling, or unknown. One extra provides this state as an int.
- * Another extra provides the previous state, if available.
+ * Another extra provides the previous state, if available. No network-related
+ * permissions are required to subscribe to this broadcast.
+ *
+ * <p class="note">This broadcast is not delivered to manifest receivers in
+ * applications that target API version 26 or later.
*
* @see #EXTRA_WIFI_STATE
* @see #EXTRA_PREVIOUS_WIFI_STATE
@@ -515,14 +579,22 @@ public class WifiManager {
public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
/**
- * The look up key for an int that indicates why softAP started failed
- * currently support general and no_channel
- * @see #SAP_START_FAILURE_GENERAL
- * @see #SAP_START_FAILURE_NO_CHANNEL
+ * An extra containing the int error code for Soft AP start failure.
+ * Can be obtained from the {@link #WIFI_AP_STATE_CHANGED_ACTION} using
+ * {@link android.content.Intent#getIntExtra}.
+ * This extra will only be attached if {@link #EXTRA_WIFI_AP_STATE} is
+ * attached and is equal to {@link #WIFI_AP_STATE_FAILED}.
+ *
+ * The error code will be one of:
+ * {@link #SAP_START_FAILURE_GENERAL},
+ * {@link #SAP_START_FAILURE_NO_CHANNEL},
+ * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
*
* @hide
*/
- public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code";
+ @SystemApi
+ public static final String EXTRA_WIFI_AP_FAILURE_REASON =
+ "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
/**
* The previous Wi-Fi state.
*
@@ -622,15 +694,18 @@ public class WifiManager {
@IntDef(flag = false, prefix = { "SAP_START_FAILURE_" }, value = {
SAP_START_FAILURE_GENERAL,
SAP_START_FAILURE_NO_CHANNEL,
+ SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SapStartFailure {}
/**
- * All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL}.
+ * All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL} and
+ * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
*
* @hide
*/
+ @SystemApi
public static final int SAP_START_FAILURE_GENERAL= 0;
/**
@@ -639,8 +714,57 @@ public class WifiManager {
*
* @hide
*/
+ @SystemApi
public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
+ /**
+ * If Wi-Fi AP start failed, this reason code means that the specified configuration
+ * is not supported by the current HAL version.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2;
+
+
+ /** @hide */
+ @IntDef(flag = false, prefix = { "SAP_CLIENT_BLOCKED_REASON_" }, value = {
+ SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER,
+ SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SapClientBlockedReason {}
+
+ /**
+ * If Soft Ap client is blocked, this reason code means that client doesn't exist in the
+ * specified configuration {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
+ * and {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
+ * and the {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
+ * is configured as well.
+ * @hide
+ */
+ @SystemApi
+ public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0;
+
+ /**
+ * If Soft Ap client is blocked, this reason code means that no more clients can be
+ * associated to this AP since it reached maximum capacity. The maximum capacity is
+ * the minimum of {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} and
+ * {@link SoftApCapability#getMaxSupportedClients} which get from
+ * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1;
+
+ /**
+ * Client disconnected for unspecified reason. This could for example be because the AP is being
+ * shut down.
+ * @hide
+ */
+ public static final int SAP_CLIENT_DISCONNECT_REASON_CODE_UNSPECIFIED = 2;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"IFACE_IP_MODE_"}, value = {
@@ -693,9 +817,14 @@ public class WifiManager {
/**
* Broadcast intent action indicating that the wifi network settings
* had been reset.
+ *
+ * Note: This intent is sent as a directed broadcast to each manifest registered receiver.
+ * Intent will not be received by dynamically registered receivers.
* @hide
*/
- public static final String WIFI_NETWORK_SETTINGS_RESET_ACTION =
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
+ public static final String ACTION_NETWORK_SETTINGS_RESET =
"android.net.wifi.action.NETWORK_SETTINGS_RESET";
/**
@@ -723,7 +852,11 @@ public class WifiManager {
/**
* Broadcast intent action indicating that the state of Wi-Fi connectivity
* has changed. An extra provides the new state
- * in the form of a {@link android.net.NetworkInfo} object.
+ * in the form of a {@link android.net.NetworkInfo} object. No network-related
+ * permissions are required to subscribe to this broadcast.
+ *
+ * <p class="note">This broadcast is not delivered to manifest receivers in
+ * applications that target API version 26 or later.
* @see #EXTRA_NETWORK_INFO
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -795,19 +928,26 @@ public class WifiManager {
/**
* Broadcast intent action indicating that the configured networks changed.
- * This can be as a result of adding/updating/deleting a network. If
- * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set to true the new configuration
- * can be retreived with the {@link #EXTRA_WIFI_CONFIGURATION} extra. If multiple
- * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present.
+ * This can be as a result of adding/updating/deleting a network.
+ * <br />
+ * {@link #EXTRA_CHANGE_REASON} contains whether the configuration was added/changed/removed.
+ * {@link #EXTRA_WIFI_CONFIGURATION} is never set starting in Android 11.
+ * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set for backwards compatibility reasons, but
+ * its value is always true, even if only a single network changed.
+ * <br />
+ * The {@link android.Manifest.permission#ACCESS_WIFI_STATE ACCESS_WIFI_STATE} permission is
+ * required to receive this broadcast.
+ *
* @hide
*/
@SystemApi
public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
"android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
/**
- * The lookup key for a (@link android.net.wifi.WifiConfiguration} object representing
+ * The lookup key for a {@link android.net.wifi.WifiConfiguration} object representing
* the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
* broadcast is sent.
+ * Note: this extra is never set starting in Android 11.
* @hide
*/
@SystemApi
@@ -815,14 +955,16 @@ public class WifiManager {
/**
* Multiple network configurations have changed.
* @see #CONFIGURED_NETWORKS_CHANGED_ACTION
- *
+ * Note: this extra is always true starting in Android 11.
* @hide
*/
@SystemApi
public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
/**
* The lookup key for an integer indicating the reason a Wi-Fi network configuration
- * has changed. Only present if {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is {@code false}
+ * has changed. One of {@link #CHANGE_REASON_ADDED}, {@link #CHANGE_REASON_REMOVED},
+ * {@link #CHANGE_REASON_CONFIG_CHANGE}.
+ *
* @see #CONFIGURED_NETWORKS_CHANGED_ACTION
* @hide
*/
@@ -902,21 +1044,37 @@ public class WifiManager {
public static final String EXTRA_NEW_RSSI = "newRssi";
/**
- * Broadcast intent action indicating that the link configuration
- * changed on wifi.
+ * @see #ACTION_LINK_CONFIGURATION_CHANGED
* @hide
*/
@UnsupportedAppUsage
public static final String LINK_CONFIGURATION_CHANGED_ACTION =
- "android.net.wifi.LINK_CONFIGURATION_CHANGED";
+ "android.net.wifi.LINK_CONFIGURATION_CHANGED";
+
+ /**
+ * Broadcast intent action indicating that the link configuration changed on wifi.
+ * <br />Included Extras:
+ * <br />{@link #EXTRA_LINK_PROPERTIES}: {@link android.net.LinkProperties} object associated
+ * with the Wi-Fi network.
+ * <br /> No permissions are required to listen to this broadcast.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_LINK_CONFIGURATION_CHANGED =
+ // should be android.net.wifi.action.LINK_CONFIGURATION_CHANGED, but due to
+ // @UnsupportedAppUsage leaving it as android.net.wifi.LINK_CONFIGURATION_CHANGED.
+ LINK_CONFIGURATION_CHANGED_ACTION;
/**
* The lookup key for a {@link android.net.LinkProperties} object associated with the
- * Wi-Fi network. Retrieve with
- * {@link android.content.Intent#getParcelableExtra(String)}.
+ * Wi-Fi network.
+ * Included in the {@link #ACTION_LINK_CONFIGURATION_CHANGED} broadcast.
+ *
+ * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
* @hide
*/
- public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
+ @SystemApi
+ public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
/**
* The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
@@ -956,24 +1114,26 @@ public class WifiManager {
public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
/**
- * Activity Action: Show UI to get user approval to enable WiFi.
+ * Activity Action: Receiver should show UI to get user approval to enable WiFi.
* <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
* the name of the app requesting the action.
* <p>Output: Nothing.
- *
+ * <p>No permissions are required to send this action.
* @hide
*/
+ @SystemApi
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
/**
- * Activity Action: Show UI to get user approval to disable WiFi.
+ * Activity Action: Receiver should show UI to get user approval to disable WiFi.
* <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
* the name of the app requesting the action.
* <p>Output: Nothing.
- *
+ * <p>No permissions are required to send this action.
* @hide
*/
+ @SystemApi
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
@@ -1015,7 +1175,7 @@ public class WifiManager {
* @deprecated This API is non-functional and will have no impact.
*/
@Deprecated
- public static final int WIFI_MODE_FULL = WifiProtoEnums.WIFI_MODE_FULL; // 1
+ public static final int WIFI_MODE_FULL = 1;
/**
* In this Wi-Fi lock mode, Wi-Fi will be kept active,
@@ -1029,7 +1189,7 @@ public class WifiManager {
* @deprecated This API is non-functional and will have no impact.
*/
@Deprecated
- public static final int WIFI_MODE_SCAN_ONLY = WifiProtoEnums.WIFI_MODE_SCAN_ONLY; // 2
+ public static final int WIFI_MODE_SCAN_ONLY = 2;
/**
* In this Wi-Fi lock mode, Wi-Fi will not go to power save.
@@ -1048,7 +1208,7 @@ public class WifiManager {
* When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF}
* lock will have no impact.
*/
- public static final int WIFI_MODE_FULL_HIGH_PERF = WifiProtoEnums.WIFI_MODE_FULL_HIGH_PERF; // 3
+ public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
/**
* In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
@@ -1078,8 +1238,8 @@ public class WifiManager {
* lock will be effective when app is running in foreground and screen is on,
* while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise.
*/
- public static final int WIFI_MODE_FULL_LOW_LATENCY =
- WifiProtoEnums.WIFI_MODE_FULL_LOW_LATENCY; // 4
+ public static final int WIFI_MODE_FULL_LOW_LATENCY = 4;
+
/** Anything worse than or equal to this will show 0 bars. */
@UnsupportedAppUsage
@@ -1090,13 +1250,16 @@ public class WifiManager {
private static final int MAX_RSSI = -55;
/**
- * Number of RSSI levels used in the framework to initiate
- * {@link #RSSI_CHANGED_ACTION} broadcast
+ * Number of RSSI levels used in the framework to initiate {@link #RSSI_CHANGED_ACTION}
+ * broadcast, where each level corresponds to a range of RSSI values.
+ * The {@link #RSSI_CHANGED_ACTION} broadcast will only fire if the RSSI
+ * change is significant enough to change the RSSI signal level.
* @hide
*/
@UnsupportedAppUsage
public static final int RSSI_LEVELS = 5;
+ //TODO (b/146346676): This needs to be removed, not used in the code.
/**
* Auto settings in the driver. The driver could choose to operate on both
* 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
@@ -1122,7 +1285,8 @@ public class WifiManager {
/** @hide */
public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
- /* Maximum number of active locks we allow.
+ /**
+ * Maximum number of active locks we allow.
* This limit was added to prevent apps from creating a ridiculous number
* of locks and crashing the system by overflowing the global ref table.
*/
@@ -1131,6 +1295,10 @@ public class WifiManager {
/** Indicates an invalid SSID. */
public static final String UNKNOWN_SSID = "<unknown ssid>";
+ /** @hide */
+ public static final MacAddress ALL_ZEROS_MAC_ADDRESS =
+ MacAddress.fromString("00:00:00:00:00:00");
+
/* Number of currently active WifiLocks and MulticastLocks */
@UnsupportedAppUsage
private int mActiveLockCount;
@@ -1140,26 +1308,9 @@ public class WifiManager {
IWifiManager mService;
private final int mTargetSdkVersion;
- private static final int INVALID_KEY = 0;
- private int mListenerKey = 1;
- private final SparseArray mListenerMap = new SparseArray();
- private final Object mListenerMapLock = new Object();
-
- private AsyncChannel mAsyncChannel;
- private CountDownLatch mConnected;
private Looper mLooper;
private boolean mVerboseLoggingEnabled = false;
- /* LocalOnlyHotspot callback message types */
- /** @hide */
- public static final int HOTSPOT_STARTED = 0;
- /** @hide */
- public static final int HOTSPOT_STOPPED = 1;
- /** @hide */
- public static final int HOTSPOT_FAILED = 2;
- /** @hide */
- public static final int HOTSPOT_OBSERVER_REGISTERED = 3;
-
private final Object mLock = new Object(); // lock guarding access to the following vars
@GuardedBy("mLock")
private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy;
@@ -1169,14 +1320,17 @@ public class WifiManager {
/**
* Create a new WifiManager instance.
* Applications will almost always want to use
- * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
+ * {@link android.content.Context#getSystemService Context.getSystemService} to retrieve
* the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
+ *
* @param context the application context
* @param service the Binder interface
+ * @param looper the Looper used to deliver callbacks
* @hide - hide this because it takes in a parameter of type IWifiManager, which
* is a system private class.
*/
- public WifiManager(Context context, IWifiManager service, Looper looper) {
+ public WifiManager(@NonNull Context context, @NonNull IWifiManager service,
+ @NonNull Looper looper) {
mContext = context;
mService = service;
mLooper = looper;
@@ -1212,10 +1366,12 @@ public class WifiManager {
* {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
* when auto-connecting to wifi.
* <b>Compatibility Note:</b> For applications targeting
- * {@link android.os.Build.VERSION_CODES#Q} or above, this API will return an empty list,
- * except for:
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return an
+ * empty list.
+ * <p>
+ * Deprecation Exemptions:
* <ul>
- * <li>Device Owner (DO) & Profile Owner (PO) apps will have access to the full list.
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps will have access to the full list.
* <li>Callers with Carrier privilege will receive a restricted list only containing
* configurations which they created.
* </ul>
@@ -1225,7 +1381,8 @@ public class WifiManager {
public List<WifiConfiguration> getConfiguredNetworks() {
try {
ParceledListSlice<WifiConfiguration> parceledList =
- mService.getConfiguredNetworks(mContext.getOpPackageName());
+ mService.getConfiguredNetworks(mContext.getOpPackageName(),
+ mContext.getAttributionTag());
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1241,7 +1398,8 @@ public class WifiManager {
public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
try {
ParceledListSlice<WifiConfiguration> parceledList =
- mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName());
+ mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
+ mContext.getAttributionTag());
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1273,8 +1431,7 @@ public class WifiManager {
List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
try {
Map<String, Map<Integer, List<ScanResult>>> results =
- mService.getAllMatchingFqdnsForScanResults(
- scanResults);
+ mService.getAllMatchingPasspointProfilesForScanResults(scanResults);
if (results.isEmpty()) {
return configs;
}
@@ -1282,8 +1439,8 @@ public class WifiManager {
mService.getWifiConfigsForPasspointProfiles(
new ArrayList<>(results.keySet()));
for (WifiConfiguration configuration : wifiConfigurations) {
- Map<Integer, List<ScanResult>> scanResultsPerNetworkType = results.get(
- configuration.FQDN);
+ Map<Integer, List<ScanResult>> scanResultsPerNetworkType =
+ results.get(configuration.getKey());
if (scanResultsPerNetworkType != null) {
configs.add(Pair.create(configuration, scanResultsPerNetworkType));
}
@@ -1296,6 +1453,36 @@ public class WifiManager {
}
/**
+ * Retrieve a list of {@link WifiConfiguration} for available {@link WifiNetworkSuggestion}
+ * matching the given list of {@link ScanResult}.
+ *
+ * An available {@link WifiNetworkSuggestion} must satisfy:
+ * <ul>
+ * <li> Matching one of the {@link ScanResult} from the given list.
+ * <li> and {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} set
+ * to true.
+ * </ul>
+ *
+ * @param scanResults a list of scanResult.
+ * @return a list of @link WifiConfiguration} for available {@link WifiNetworkSuggestion}
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD
+ })
+ @NonNull
+ public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
+ @NonNull List<ScanResult> scanResults) {
+ try {
+ return mService.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(scanResults);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* Returns a list of unique Hotspot 2.0 OSU (Online Sign-Up) providers associated with a given
* list of ScanResult.
*
@@ -1374,7 +1561,13 @@ public class WifiManager {
* {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
* when auto-connecting to wifi.
* <b>Compatibility Note:</b> For applications targeting
- * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
+ * {@code -1}.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
@Deprecated
public int addNetwork(WifiConfiguration config) {
@@ -1409,7 +1602,13 @@ public class WifiManager {
* {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
* when auto-connecting to wifi.
* <b>Compatibility Note:</b> For applications targeting
- * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
+ * {@code -1}.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
@Deprecated
public int updateNetwork(WifiConfiguration config) {
@@ -1446,40 +1645,45 @@ public class WifiManager {
* {@link #reject()} to return the user's selection back to the platform via this callback.
* @hide
*/
+ @SystemApi
public interface NetworkRequestUserSelectionCallback {
/**
* User selected this network to connect to.
* @param wifiConfiguration WifiConfiguration object corresponding to the network
* user selected.
*/
- void select(@NonNull WifiConfiguration wifiConfiguration);
+ @SuppressLint("CallbackMethodName")
+ default void select(@NonNull WifiConfiguration wifiConfiguration) {}
/**
* User rejected the app's request.
*/
- void reject();
+ @SuppressLint("CallbackMethodName")
+ default void reject() {}
}
/**
* Interface for network request callback. Should be implemented by applications and passed when
- * calling {@link #registerNetworkRequestMatchCallback(NetworkRequestMatchCallback, Handler)}.
+ * calling {@link #registerNetworkRequestMatchCallback(Executor,
+ * WifiManager.NetworkRequestMatchCallback)}.
*
* This is meant to be implemented by a UI component to present the user with a list of networks
* matching the app's request. The user is allowed to pick one of these networks to connect to
* or reject the request by the app.
* @hide
*/
+ @SystemApi
public interface NetworkRequestMatchCallback {
/**
* Invoked to register a callback to be invoked to convey user selection. The callback
- * object paased in this method is to be invoked by the UI component after the service sends
+ * object passed in this method is to be invoked by the UI component after the service sends
* a list of matching scan networks using {@link #onMatch(List)} and user picks a network
* from that list.
*
* @param userSelectionCallback Callback object to send back the user selection.
*/
- void onUserSelectionCallbackRegistration(
- @NonNull NetworkRequestUserSelectionCallback userSelectionCallback);
+ default void onUserSelectionCallbackRegistration(
+ @NonNull NetworkRequestUserSelectionCallback userSelectionCallback) {}
/**
* Invoked when the active network request is aborted, either because
@@ -1488,7 +1692,7 @@ public class WifiManager {
* This signals the end of processing for the current request and should stop the UI
* component. No subsequent calls from the UI component will be handled by the platform.
*/
- void onAbort();
+ default void onAbort() {}
/**
* Invoked when a network request initiated by an app matches some networks in scan results.
@@ -1498,7 +1702,7 @@ public class WifiManager {
* @param scanResults List of {@link ScanResult} objects corresponding to the networks
* matching the request.
*/
- void onMatch(@NonNull List<ScanResult> scanResults);
+ default void onMatch(@NonNull List<ScanResult> scanResults) {}
/**
* Invoked on a successful connection with the network that the user selected
@@ -1507,7 +1711,7 @@ public class WifiManager {
* @param wifiConfiguration WifiConfiguration object corresponding to the network that the
* user selected.
*/
- void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration);
+ default void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration) {}
/**
* Invoked on failure to establish connection with the network that the user selected
@@ -1516,7 +1720,7 @@ public class WifiManager {
* @param wifiConfiguration WifiConfiguration object corresponding to the network
* user selected.
*/
- void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration);
+ default void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration) {}
}
/**
@@ -1565,11 +1769,11 @@ public class WifiManager {
* @hide
*/
private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
- private final Handler mHandler;
+ private final Executor mExecutor;
private final NetworkRequestMatchCallback mCallback;
- NetworkRequestMatchCallbackProxy(Looper looper, NetworkRequestMatchCallback callback) {
- mHandler = new Handler(looper);
+ NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback) {
+ mExecutor = executor;
mCallback = callback;
}
@@ -1580,7 +1784,8 @@ public class WifiManager {
Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
+ "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
}
- mHandler.post(() -> {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
mCallback.onUserSelectionCallbackRegistration(
new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
});
@@ -1591,7 +1796,8 @@ public class WifiManager {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "NetworkRequestMatchCallbackProxy: onAbort");
}
- mHandler.post(() -> {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
mCallback.onAbort();
});
}
@@ -1602,7 +1808,8 @@ public class WifiManager {
Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch scanResults: "
+ scanResults);
}
- mHandler.post(() -> {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
mCallback.onMatch(scanResults);
});
}
@@ -1613,7 +1820,8 @@ public class WifiManager {
Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
+ " wificonfiguration: " + wifiConfiguration);
}
- mHandler.post(() -> {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
});
}
@@ -1624,7 +1832,8 @@ public class WifiManager {
Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
+ " wificonfiguration: " + wifiConfiguration);
}
- mHandler.post(() -> {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
mCallback.onUserSelectionConnectFailure(wifiConfiguration);
});
}
@@ -1640,23 +1849,24 @@ public class WifiManager {
* without the permission will trigger a {@link java.lang.SecurityException}.
* <p>
*
- * @param callback Callback for network match events
- * @param handler The Handler on whose thread to execute the callbacks of the {@code callback}
- * object. If null, then the application's main thread will be used.
+ * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
+ * object.
+ * @param callback Callback for network match events to register.
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void registerNetworkRequestMatchCallback(@NonNull NetworkRequestMatchCallback callback,
- @Nullable Handler handler) {
+ public void registerNetworkRequestMatchCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull NetworkRequestMatchCallback callback) {
+ if (executor == null) throw new IllegalArgumentException("executor cannot be null");
if (callback == null) throw new IllegalArgumentException("callback cannot be null");
Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
- + ", handler=" + handler);
+ + ", executor=" + executor);
- Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
Binder binder = new Binder();
try {
mService.registerNetworkRequestMatchCallback(
- binder, new NetworkRequestMatchCallbackProxy(looper, callback),
+ binder, new NetworkRequestMatchCallbackProxy(executor, callback),
callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1671,9 +1881,10 @@ public class WifiManager {
* without the permission will trigger a {@link java.lang.SecurityException}.
* <p>
*
- * @param callback Callback for network match events
+ * @param callback Callback for network match events to unregister.
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void unregisterNetworkRequestMatchCallback(
@NonNull NetworkRequestMatchCallback callback) {
@@ -1692,30 +1903,41 @@ public class WifiManager {
* for a detailed explanation of the parameters.
* When the device decides to connect to one of the provided network suggestions, platform sends
* a directed broadcast {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} to the app if
- * the network was created with {@link WifiNetworkSuggestion.Builder
- * #setIsAppInteractionRequired()} flag set and the app holds
- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
+ * the network was created with
+ * {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(boolean)} flag set and the
+ * app holds {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
+ * permission.
*<p>
* NOTE:
* <li> These networks are just a suggestion to the platform. The platform will ultimately
* decide on which network the device connects to. </li>
- * <li> When an app is uninstalled, all its suggested networks are discarded. If the device is
- * currently connected to a suggested network which is being removed then the device will
- * disconnect from that network.</li>
- * <li> No in-place modification of existing suggestions are allowed. Apps are expected to
- * remove suggestions using {@link #removeNetworkSuggestions(List)} and then add the modified
- * suggestion back using this API.</li>
+ * <li> When an app is uninstalled or disabled, all its suggested networks are discarded.
+ * If the device is currently connected to a suggested network which is being removed then the
+ * device will disconnect from that network.</li>
+ * <li> If user reset network settings, all added suggestions will be discarded. Apps can use
+ * {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li>
+ * <li> In-place modification of existing suggestions are allowed.
+ * <li> If the provided suggestions include any previously provided suggestions by the app,
+ * previous suggestions will be updated.</li>
+ * <li>If one of the provided suggestions marks a previously unmetered suggestion as metered and
+ * the device is currently connected to that suggested network, then the device will disconnect
+ * from that network. The system will immediately re-evaluate all the network candidates
+ * and possibly reconnect back to the same suggestion. This disconnect is to make sure that any
+ * traffic flowing over unmetered networks isn't accidentally continued over a metered network.
+ * </li>
+ * </li>
*
* @param networkSuggestions List of network suggestions provided by the app.
* @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
- * {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app.
* @throws {@link SecurityException} if the caller is missing required permissions.
+ * @see WifiNetworkSuggestion#equals(Object)
*/
@RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
@NonNull List<WifiNetworkSuggestion> networkSuggestions) {
try {
- return mService.addNetworkSuggestions(networkSuggestions, mContext.getOpPackageName());
+ return mService.addNetworkSuggestions(
+ networkSuggestions, mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1723,6 +1945,9 @@ public class WifiManager {
/**
* Remove some or all of the network suggestions that were previously provided by the app.
+ * If one of the suggestions being removed was used to establish connection to the current
+ * network, then the device will immediately disconnect from that network.
+ *
* See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
* See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
*
@@ -1744,12 +1969,35 @@ public class WifiManager {
}
/**
+ * Get all network suggestions provided by the calling app.
+ * See {@link #addNetworkSuggestions(List)}
+ * See {@link #removeNetworkSuggestions(List)}
+ * @return a list of {@link WifiNetworkSuggestion}
+ */
+ @RequiresPermission(ACCESS_WIFI_STATE)
+ public @NonNull List<WifiNetworkSuggestion> getNetworkSuggestions() {
+ try {
+ return mService.getNetworkSuggestions(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* Returns the max number of network suggestions that are allowed per app on the device.
* @see #addNetworkSuggestions(List)
* @see #removeNetworkSuggestions(List)
*/
public int getMaxNumberOfNetworkSuggestionsPerApp() {
- return NETWORK_SUGGESTIONS_MAX_PER_APP;
+ return getMaxNumberOfNetworkSuggestionsPerApp(
+ mContext.getSystemService(ActivityManager.class).isLowRamDevice());
+ }
+
+ /** @hide */
+ public static int getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice) {
+ return isLowRamDevice
+ ? NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM
+ : NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM;
}
/**
@@ -1757,13 +2005,29 @@ public class WifiManager {
* for connecting to Passpoint networks that are operated by the Passpoint
* service provider specified in the configuration.
*
- * Each configuration is uniquely identified by its FQDN (Fully Qualified Domain
- * Name). In the case when there is an existing configuration with the same
- * FQDN, the new configuration will replace the existing configuration.
+ * Each configuration is uniquely identified by a unique key which depends on the contents of
+ * the configuration. This allows the caller to install multiple profiles with the same FQDN
+ * (Fully qualified domain name). Therefore, in order to update an existing profile, it is
+ * first required to remove it using {@link WifiManager#removePasspointConfiguration(String)}.
+ * Otherwise, a new profile will be added with both configuration.
*
* @param config The Passpoint configuration to be added
* @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
* the device.
+ *
+ * Deprecated for general app usage - except DO/PO apps.
+ * See {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} to
+ * create a passpoint suggestion.
+ * See {@link #addNetworkSuggestions(List)}, {@link #removeNetworkSuggestions(List)} for new
+ * API to add Wi-Fi networks for consideration when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#R} or above, this API will always fail and throw
+ * {@link IllegalArgumentException}.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
try {
@@ -1785,7 +2049,10 @@ public class WifiManager {
* @deprecated This will be non-functional in a future release.
*/
@Deprecated
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
+ })
public void removePasspointConfiguration(String fqdn) {
try {
if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
@@ -1856,6 +2123,8 @@ public class WifiManager {
* @param holdoff hold off time in milliseconds
* @param ess set if the hold off pertains to an ESS rather than a BSS
* @hide
+ *
+ * TODO (140167680): This needs to be removed, the implementation is empty!
*/
public void deauthenticateNetwork(long holdoff, boolean ess) {
try {
@@ -1884,7 +2153,13 @@ public class WifiManager {
* {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
* when auto-connecting to wifi.
* <b>Compatibility Note:</b> For applications targeting
- * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
+ * {@code false}.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
@Deprecated
public boolean removeNetwork(int netId) {
@@ -1928,32 +2203,20 @@ public class WifiManager {
* {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
* when auto-connecting to wifi.
* <b>Compatibility Note:</b> For applications targeting
- * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
+ * {@code false}.
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
@Deprecated
public boolean enableNetwork(int netId, boolean attemptConnect) {
- final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
- if (pin) {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- NetworkPinner.pin(mContext, request);
- }
-
- boolean success;
try {
- success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
+ return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- if (pin && !success) {
- NetworkPinner.unpin();
- }
-
- return success;
}
/**
@@ -1975,7 +2238,13 @@ public class WifiManager {
* {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
* when auto-connecting to wifi.
* <b>Compatibility Note:</b> For applications targeting
- * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
+ * {@code false}.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
@Deprecated
public boolean disableNetwork(int netId) {
@@ -1998,7 +2267,13 @@ public class WifiManager {
* {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
* when auto-connecting to wifi.
* <b>Compatibility Note:</b> For applications targeting
- * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
+ * {@code false}.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
@Deprecated
public boolean disconnect() {
@@ -2022,7 +2297,13 @@ public class WifiManager {
* {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
* when auto-connecting to wifi.
* <b>Compatibility Note:</b> For applications targeting
- * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
+ * {@code false}.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
@Deprecated
public boolean reconnect() {
@@ -2071,8 +2352,6 @@ public class WifiManager {
/** @hide */
public static final long WIFI_FEATURE_INFRA = 0x0001L; // Basic infrastructure mode
/** @hide */
- public static final long WIFI_FEATURE_INFRA_5G = 0x0002L; // Support for 5 GHz Band
- /** @hide */
public static final long WIFI_FEATURE_PASSPOINT = 0x0004L; // Support for GAS/ANQP
/** @hide */
public static final long WIFI_FEATURE_P2P = 0x0008L; // Wifi-Direct
@@ -2133,7 +2412,23 @@ public class WifiManager {
/** @hide */
public static final long WIFI_FEATURE_DPP = 0x80000000L; // DPP (Easy-Connect)
/** @hide */
- public static final long WIFI_FEATURE_P2P_RAND_MAC = 0x100000000L; // Random P2P MAC
+ public static final long WIFI_FEATURE_P2P_RAND_MAC = 0x100000000L; // Random P2P MAC
+ /** @hide */
+ public static final long WIFI_FEATURE_CONNECTED_RAND_MAC = 0x200000000L; // Random STA MAC
+ /** @hide */
+ public static final long WIFI_FEATURE_AP_RAND_MAC = 0x400000000L; // Random AP MAC
+ /** @hide */
+ public static final long WIFI_FEATURE_MBO = 0x800000000L; // MBO Support
+ /** @hide */
+ public static final long WIFI_FEATURE_OCE = 0x1000000000L; // OCE Support
+ /** @hide */
+ public static final long WIFI_FEATURE_WAPI = 0x2000000000L; // WAPI
+
+ /** @hide */
+ public static final long WIFI_FEATURE_FILS_SHA256 = 0x4000000000L; // FILS-SHA256
+
+ /** @hide */
+ public static final long WIFI_FEATURE_FILS_SHA384 = 0x8000000000L; // FILS-SHA384
private long getSupportedFeatures() {
try {
@@ -2146,12 +2441,6 @@ public class WifiManager {
private boolean isFeatureSupported(long feature) {
return (getSupportedFeatures() & feature) == feature;
}
- /**
- * @return true if this adapter supports 5 GHz band
- */
- public boolean is5GHzBandSupported() {
- return isFeatureSupported(WIFI_FEATURE_INFRA_5G);
- }
/**
* @return true if this adapter supports Passpoint
@@ -2195,6 +2484,15 @@ public class WifiManager {
}
/**
+ * Query whether the device supports Station (STA) + Access point (AP) concurrency or not.
+ *
+ * @return true if this device supports STA + AP concurrency, false otherwise.
+ */
+ public boolean isStaApConcurrencySupported() {
+ return isFeatureSupported(WIFI_FEATURE_AP_STA);
+ }
+
+ /**
* @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
* with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT} and
* {@link android.content.pm.PackageManager#FEATURE_WIFI_AWARE}.
@@ -2257,20 +2555,132 @@ public class WifiManager {
}
/**
- * Return the record of {@link WifiActivityEnergyInfo} object that
- * has the activity and energy info. This can be used to ascertain what
- * the controller has been up to, since the last sample.
- *
- * @return a record with {@link WifiActivityEnergyInfo} or null if
- * report is unavailable or unsupported
+ * @return true if this device supports connected MAC randomization.
* @hide
*/
- public WifiActivityEnergyInfo getControllerActivityEnergyInfo() {
- if (mService == null) return null;
+ @SystemApi
+ public boolean isConnectedMacRandomizationSupported() {
+ return isFeatureSupported(WIFI_FEATURE_CONNECTED_RAND_MAC);
+ }
+
+ /**
+ * @return true if this device supports connected MAC randomization.
+ * @hide
+ */
+ @SystemApi
+ public boolean isApMacRandomizationSupported() {
+ return isFeatureSupported(WIFI_FEATURE_AP_RAND_MAC);
+ }
+
+ /**
+ * Check if the chipset supports 5GHz band.
+ * @return {@code true} if supported, {@code false} otherwise.
+ */
+ public boolean is5GHzBandSupported() {
try {
- synchronized(this) {
- return mService.reportActivityInfo();
+ return mService.is5GHzBandSupported();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Check if the chipset supports 6GHz band.
+ * @return {@code true} if supported, {@code false} otherwise.
+ */
+ public boolean is6GHzBandSupported() {
+ try {
+ return mService.is6GHzBandSupported();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Check if the chipset supports a certain Wi-Fi standard.
+ * @param standard the IEEE 802.11 standard to check on.
+ * valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
+ * @return {@code true} if supported, {@code false} otherwise.
+ */
+ public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) {
+ try {
+ return mService.isWifiStandardSupported(standard);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
+ * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface OnWifiActivityEnergyInfoListener {
+ /**
+ * Called when Wi-Fi activity energy info is available.
+ * Note: this listener is triggered at most once for each call to
+ * {@link #getWifiActivityEnergyInfoAsync}.
+ *
+ * @param info the latest {@link WifiActivityEnergyInfo}, or null if unavailable.
+ */
+ void onWifiActivityEnergyInfo(@Nullable WifiActivityEnergyInfo info);
+ }
+
+ private static class OnWifiActivityEnergyInfoProxy
+ extends IOnWifiActivityEnergyInfoListener.Stub {
+ private final Object mLock = new Object();
+ @Nullable @GuardedBy("mLock") private Executor mExecutor;
+ @Nullable @GuardedBy("mLock") private OnWifiActivityEnergyInfoListener mListener;
+
+ OnWifiActivityEnergyInfoProxy(Executor executor,
+ OnWifiActivityEnergyInfoListener listener) {
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onWifiActivityEnergyInfo(WifiActivityEnergyInfo info) {
+ Executor executor;
+ OnWifiActivityEnergyInfoListener listener;
+ synchronized (mLock) {
+ if (mExecutor == null || mListener == null) {
+ return;
+ }
+ executor = mExecutor;
+ listener = mListener;
+ // null out to allow garbage collection, prevent triggering listener more than once
+ mExecutor = null;
+ mListener = null;
}
+ Binder.clearCallingIdentity();
+ executor.execute(() -> listener.onWifiActivityEnergyInfo(info));
+ }
+ }
+
+ /**
+ * Request to get the current {@link WifiActivityEnergyInfo} asynchronously.
+ * Note: This method will return null if {@link #isEnhancedPowerReportingSupported()} returns
+ * false.
+ *
+ * @param executor the executor that the listener will be invoked on
+ * @param listener the listener that will receive the {@link WifiActivityEnergyInfo} object
+ * when it becomes available. The listener will be triggered at most once for
+ * each call to this method.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(ACCESS_WIFI_STATE)
+ public void getWifiActivityEnergyInfoAsync(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnWifiActivityEnergyInfoListener listener) {
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
+ try {
+ mService.getWifiActivityEnergyInfoAsync(
+ new OnWifiActivityEnergyInfoProxy(executor, listener));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2309,7 +2719,8 @@ public class WifiManager {
public boolean startScan(WorkSource workSource) {
try {
String packageName = mContext.getOpPackageName();
- return mService.startScan(packageName);
+ String attributionTag = mContext.getAttributionTag();
+ return mService.startScan(packageName, attributionTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2333,12 +2744,15 @@ public class WifiManager {
* the same permissions as {@link #getScanResults}. If such access is not allowed,
* {@link WifiInfo#getSSID} will return {@link #UNKNOWN_SSID} and
* {@link WifiInfo#getBSSID} will return {@code "02:00:00:00:00:00"}.
+ * {@link WifiInfo#getPasspointFqdn()} will return null.
+ * {@link WifiInfo#getPasspointProviderFriendlyName()} will return null.
*
* @return the Wi-Fi information, contained in {@link WifiInfo}.
*/
public WifiInfo getConnectionInfo() {
try {
- return mService.getConnectionInfo(mContext.getOpPackageName());
+ return mService.getConnectionInfo(mContext.getOpPackageName(),
+ mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2352,7 +2766,59 @@ public class WifiManager {
*/
public List<ScanResult> getScanResults() {
try {
- return mService.getScanResults(mContext.getOpPackageName());
+ return mService.getScanResults(mContext.getOpPackageName(),
+ mContext.getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the filtered ScanResults which match the network configurations specified by the
+ * {@code networkSuggestionsToMatch}. Suggestions which use {@link WifiConfiguration} use
+ * SSID and the security type to match. Suggestions which use {@link PasspointConfigration}
+ * use the matching rules of Hotspot 2.0.
+ * @param networkSuggestionsToMatch The list of {@link WifiNetworkSuggestion} to match against.
+ * These may or may not be suggestions which are installed on the device.
+ * @param scanResults The scan results to be filtered. Optional - if not provided(empty list),
+ * the Wi-Fi service will use the most recent scan results which the system has.
+ * @return The map of {@link WifiNetworkSuggestion} to the list of {@link ScanResult}
+ * corresponding to networks which match them.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
+ @NonNull
+ public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
+ @NonNull List<WifiNetworkSuggestion> networkSuggestionsToMatch,
+ @Nullable List<ScanResult> scanResults) {
+ if (networkSuggestionsToMatch == null) {
+ throw new IllegalArgumentException("networkSuggestions must not be null.");
+ }
+ try {
+ return mService.getMatchingScanResults(
+ networkSuggestionsToMatch, scanResults,
+ mContext.getOpPackageName(), mContext.getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set if scanning is always available.
+ *
+ * If set to {@code true}, apps can issue {@link #startScan} and fetch scan results
+ * even when Wi-Fi is turned off.
+ *
+ * @param isAvailable true to enable, false to disable.
+ * @hide
+ * @see #isScanAlwaysAvailable()
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setScanAlwaysAvailable(boolean isAvailable) {
+ try {
+ mService.setScanAlwaysAvailable(isAvailable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2395,57 +2861,17 @@ public class WifiManager {
}
/**
- * Set the country code.
- * @param countryCode country code in ISO 3166 format.
- *
+ * Get the country code.
+ * @return the country code in ISO 3166 alpha-2 (2-letter) uppercase format, or null if
+ * there is no country code configured.
* @hide
*/
- public void setCountryCode(@NonNull String country) {
- try {
- mService.setCountryCode(country);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * get the country code.
- * @return the country code in ISO 3166 format.
- *
- * @hide
- */
- @UnsupportedAppUsage
+ @Nullable
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String getCountryCode() {
- try {
- String country = mService.getCountryCode();
- return country;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
- * @return {@code true} if supported, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage
- public boolean isDualBandSupported() {
- try {
- return mService.isDualBandSupported();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Check if the chipset requires conversion of 5GHz Only apBand to ANY.
- * @return {@code true} if required, {@code false} otherwise.
- * @hide
- */
- public boolean isDualModeSupported() {
try {
- return mService.needs5GHzToAnyApBandConversion();
+ return mService.getCountryCode();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2478,9 +2904,14 @@ public class WifiManager {
* @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
* enable/disable Wi-Fi.
* <b>Compatibility Note:</b> For applications targeting
- * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code false}
- * and will have no effect. If apps are targeting an older SDK (
- * {@link android.os.Build.VERSION_CODES#P} or below), they can continue to use this API.
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
+ * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#P}
+ * or below), they can continue to use this API.
+ * <p>
+ * Deprecation Exemptions:
+ * <ul>
+ * <li>Device Owner (DO), Profile Owner (PO) and system apps.
+ * </ul>
*/
@Deprecated
public boolean setWifiEnabled(boolean enabled) {
@@ -2516,25 +2947,17 @@ public class WifiManager {
}
/**
- * Return TX packet counter, for CTS test of WiFi watchdog.
- * @param listener is the interface to receive result
- *
- * @hide for CTS test only
- */
- public void getTxPacketCount(TxPacketCountListener listener) {
- getChannel().sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
- }
-
- /**
* Calculates the level of the signal. This should be used any time a signal
* is being shown.
*
* @param rssi The power of the signal measured in RSSI.
- * @param numLevels The number of levels to consider in the calculated
- * level.
- * @return A level of the signal, given in the range of 0 to numLevels-1
- * (both inclusive).
+ * @param numLevels The number of levels to consider in the calculated level.
+ * @return A level of the signal, given in the range of 0 to numLevels-1 (both inclusive).
+ * @deprecated Callers should use {@link #calculateSignalLevel(int)} instead to get the
+ * signal level using the system default RSSI thresholds, or otherwise compute the RSSI level
+ * themselves using their own formula.
*/
+ @Deprecated
public static int calculateSignalLevel(int rssi, int numLevels) {
if (rssi <= MIN_RSSI) {
return 0;
@@ -2548,6 +2971,32 @@ public class WifiManager {
}
/**
+ * Given a raw RSSI, return the RSSI signal quality rating using the system default RSSI
+ * quality rating thresholds.
+ * @param rssi a raw RSSI value, in dBm, usually between -55 and -90
+ * @return the RSSI signal quality rating, in the range
+ * [0, {@link #getMaxSignalLevel()}], where 0 is the lowest (worst signal) RSSI
+ * rating and {@link #getMaxSignalLevel()} is the highest (best signal) RSSI rating.
+ */
+ @IntRange(from = 0)
+ public int calculateSignalLevel(int rssi) {
+ try {
+ return mService.calculateSignalLevel(rssi);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the system default maximum signal level.
+ * This is the maximum RSSI level returned by {@link #calculateSignalLevel(int)}.
+ */
+ @IntRange(from = 0)
+ public int getMaxSignalLevel() {
+ return calculateSignalLevel(Integer.MAX_VALUE);
+ }
+
+ /**
* Compares two signal strengths.
*
* @param rssiA The power of the first signal measured in RSSI.
@@ -2586,7 +3035,7 @@ public class WifiManager {
}
/**
- * Start Soft AP (hotspot) mode with the specified configuration.
+ * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
* Note that starting Soft AP mode may disable station mode operation if the device does not
* support concurrency.
* @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to
@@ -2596,7 +3045,6 @@ public class WifiManager {
*
* @hide
*/
- @SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STACK,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
@@ -2610,6 +3058,31 @@ public class WifiManager {
}
/**
+ * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
+ * Note that starting Soft AP mode may disable station mode operation if the device does not
+ * support concurrency.
+ * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP,
+ * or null to use the persisted Soft AP configuration that was previously
+ * set using {@link #setSoftApConfiguration(softApConfiguration)}.
+ * @return {@code true} if the operation succeeded, {@code false} otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
+ try {
+ return mService.startTetheredHotspot(softApConfig);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
* Stop SoftAp mode.
* Note that stopping softap mode will restore the previous wifi mode.
* @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -2641,7 +3114,7 @@ public class WifiManager {
* Each application can make a single active call to this method. The {@link
* LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} callback supplies the
* requestor with a {@link LocalOnlyHotspotReservation} that contains a
- * {@link WifiConfiguration} with the SSID, security type and credentials needed to connect
+ * {@link SoftApConfiguration} with the SSID, security type and credentials needed to connect
* to the hotspot. Communicating this information is up to the application.
* <p>
* If the LocalOnlyHotspot cannot be created, the {@link LocalOnlyHotspotCallback#onFailed(int)}
@@ -2684,19 +3157,70 @@ public class WifiManager {
* @param handler Handler to be used for callbacks. If the caller passes a null Handler, the
* main thread will be used.
*/
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.CHANGE_WIFI_STATE,
+ android.Manifest.permission.ACCESS_FINE_LOCATION})
public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
@Nullable Handler handler) {
+ Executor executor = handler == null ? null : new HandlerExecutor(handler);
+ startLocalOnlyHotspotInternal(null, executor, callback);
+ }
+
+ /**
+ * Starts a local-only hotspot with a specific configuration applied. See
+ * {@link #startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}.
+ *
+ * Applications need either {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} or
+ * {@link android.Manifest.permission#NETWORK_SETTINGS} to call this method.
+ *
+ * Since custom configuration settings may be incompatible with each other, the hotspot started
+ * through this method cannot coexist with another hotspot created through
+ * startLocalOnlyHotspot. If this is attempted, the first hotspot request wins and others
+ * receive {@link LocalOnlyHotspotCallback#ERROR_GENERIC} through
+ * {@link LocalOnlyHotspotCallback#onFailed}.
+ *
+ * @param config Custom configuration for the hotspot. See {@link SoftApConfiguration}.
+ * @param executor Executor to run callback methods on, or null to use the main thread.
+ * @param callback Callback object for updates about hotspot status, or null for no updates.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD})
+ public void startLocalOnlyHotspot(@NonNull SoftApConfiguration config,
+ @Nullable Executor executor,
+ @Nullable LocalOnlyHotspotCallback callback) {
+ Objects.requireNonNull(config);
+ startLocalOnlyHotspotInternal(config, executor, callback);
+ }
+
+ /**
+ * Common implementation of both configurable and non-configurable LOHS.
+ *
+ * @param config App-specified configuration, or null. When present, additional privileges are
+ * required, and the hotspot cannot be shared with other clients.
+ * @param executor Executor to run callback methods on, or null to use the main thread.
+ * @param callback Callback object for updates about hotspot status, or null for no updates.
+ */
+ private void startLocalOnlyHotspotInternal(
+ @Nullable SoftApConfiguration config,
+ @Nullable Executor executor,
+ @Nullable LocalOnlyHotspotCallback callback) {
+ if (executor == null) {
+ executor = mContext.getMainExecutor();
+ }
synchronized (mLock) {
- Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
LocalOnlyHotspotCallbackProxy proxy =
- new LocalOnlyHotspotCallbackProxy(this, looper, callback);
+ new LocalOnlyHotspotCallbackProxy(this, executor, callback);
try {
String packageName = mContext.getOpPackageName();
- int returnCode = mService.startLocalOnlyHotspot(
- proxy.getMessenger(), new Binder(), packageName);
+ String featureId = mContext.getAttributionTag();
+ int returnCode = mService.startLocalOnlyHotspot(proxy, packageName, featureId,
+ config);
if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
// Send message to the proxy to make sure we call back on the correct thread
- proxy.notifyFailed(returnCode);
+ proxy.onHotspotFailed(returnCode);
return;
}
mLOHSCallbackProxy = proxy;
@@ -2755,7 +3279,7 @@ public class WifiManager {
* Allow callers (Settings UI) to watch LocalOnlyHotspot state changes. Callers will
* receive a {@link LocalOnlyHotspotSubscription} object as a parameter of the
* {@link LocalOnlyHotspotObserver#onRegistered(LocalOnlyHotspotSubscription)}. The registered
- * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(WifiConfiguration)} and
+ * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(SoftApConfiguration)} and
* {@link LocalOnlyHotspotObserver#onStopped()} callbacks.
* <p>
* Applications should have the
@@ -2770,12 +3294,13 @@ public class WifiManager {
*/
public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
@Nullable Handler handler) {
+ Executor executor = handler == null ? mContext.getMainExecutor()
+ : new HandlerExecutor(handler);
synchronized (mLock) {
- Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
- mLOHSObserverProxy = new LocalOnlyHotspotObserverProxy(this, looper, observer);
+ mLOHSObserverProxy =
+ new LocalOnlyHotspotObserverProxy(this, executor, observer);
try {
- mService.startWatchLocalOnlyHotspot(
- mLOHSObserverProxy.getMessenger(), new Binder());
+ mService.startWatchLocalOnlyHotspot(mLOHSObserverProxy);
mLOHSObserverProxy.registered();
} catch (RemoteException e) {
mLOHSObserverProxy = null;
@@ -2806,7 +3331,7 @@ public class WifiManager {
}
/**
- * Gets the Wi-Fi enabled state.
+ * Gets the tethered Wi-Fi hotspot enabled state.
* @return One of {@link #WIFI_AP_STATE_DISABLED},
* {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
* {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
@@ -2825,8 +3350,8 @@ public class WifiManager {
}
/**
- * Return whether Wi-Fi AP is enabled or disabled.
- * @return {@code true} if Wi-Fi AP is enabled
+ * Return whether tethered Wi-Fi AP is enabled or disabled.
+ * @return {@code true} if tethered Wi-Fi AP is enabled
* @see #getWifiApState()
*
* @hide
@@ -2838,13 +3363,19 @@ public class WifiManager {
}
/**
- * Gets the Wi-Fi AP Configuration.
+ * Gets the tethered Wi-Fi AP Configuration.
* @return AP details in WifiConfiguration
*
+ * Note that AP detail may contain configuration which is cannot be represented
+ * by the legacy WifiConfiguration, in such cases a null will be returned.
+ *
+ * @deprecated This API is deprecated. Use {@link #getSoftApConfiguration()} instead.
* @hide
*/
+ @Nullable
@SystemApi
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+ @Deprecated
public WifiConfiguration getWifiApConfiguration() {
try {
return mService.getWifiApConfiguration();
@@ -2854,14 +3385,33 @@ public class WifiManager {
}
/**
- * Sets the Wi-Fi AP Configuration. The AP configuration must either be open or
- * WPA2 PSK networks.
+ * Gets the Wi-Fi tethered AP Configuration.
+ * @return AP details in {@link SoftApConfiguration}
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public SoftApConfiguration getSoftApConfiguration() {
+ try {
+ return mService.getSoftApConfiguration();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the tethered Wi-Fi AP Configuration.
* @return {@code true} if the operation succeeded, {@code false} otherwise
*
+ * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
+ * instead.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
+ @Deprecated
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
try {
return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
@@ -2871,15 +3421,30 @@ public class WifiManager {
}
/**
- * Method that triggers a notification to the user about a conversion to their saved AP config.
+ * Sets the tethered Wi-Fi AP Configuration.
+ *
+ * If the API is called while the tethered soft AP is enabled, the configuration will apply to
+ * the current soft AP if the new configuration only includes
+ * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
+ * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}
+ * or {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
+ * or {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
+ * or {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
+ *
+ * Otherwise, the configuration changes will be applied when the Soft AP is next started
+ * (the framework will not stop/start the AP).
+ *
+ * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP.
+ * @return {@code true} if the operation succeeded, {@code false} otherwise
*
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void notifyUserOfApBandConversion() {
- Log.d(TAG, "apBand was converted, notify the user");
+ public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
try {
- mService.notifyUserOfApBandConversion(mContext.getOpPackageName());
+ return mService.setSoftApConfiguration(
+ softApConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2927,76 +3492,6 @@ public class WifiManager {
}
}
- /* TODO: deprecate synchronous API and open up the following API */
-
- private static final int BASE = Protocol.BASE_WIFI_MANAGER;
-
- /* Commands to WifiService */
- /** @hide */
- public static final int CONNECT_NETWORK = BASE + 1;
- /** @hide */
- public static final int CONNECT_NETWORK_FAILED = BASE + 2;
- /** @hide */
- public static final int CONNECT_NETWORK_SUCCEEDED = BASE + 3;
-
- /** @hide */
- public static final int FORGET_NETWORK = BASE + 4;
- /** @hide */
- public static final int FORGET_NETWORK_FAILED = BASE + 5;
- /** @hide */
- public static final int FORGET_NETWORK_SUCCEEDED = BASE + 6;
-
- /** @hide */
- public static final int SAVE_NETWORK = BASE + 7;
- /** @hide */
- public static final int SAVE_NETWORK_FAILED = BASE + 8;
- /** @hide */
- public static final int SAVE_NETWORK_SUCCEEDED = BASE + 9;
-
- /** @hide
- * @deprecated This is deprecated
- */
- public static final int START_WPS = BASE + 10;
- /** @hide
- * @deprecated This is deprecated
- */
- public static final int START_WPS_SUCCEEDED = BASE + 11;
- /** @hide
- * @deprecated This is deprecated
- */
- public static final int WPS_FAILED = BASE + 12;
- /** @hide
- * @deprecated This is deprecated
- */
- public static final int WPS_COMPLETED = BASE + 13;
-
- /** @hide
- * @deprecated This is deprecated
- */
- public static final int CANCEL_WPS = BASE + 14;
- /** @hide
- * @deprecated This is deprecated
- */
- public static final int CANCEL_WPS_FAILED = BASE + 15;
- /** @hide
- * @deprecated This is deprecated
- */
- public static final int CANCEL_WPS_SUCCEDED = BASE + 16;
-
- /** @hide */
- public static final int DISABLE_NETWORK = BASE + 17;
- /** @hide */
- public static final int DISABLE_NETWORK_FAILED = BASE + 18;
- /** @hide */
- public static final int DISABLE_NETWORK_SUCCEEDED = BASE + 19;
-
- /** @hide */
- public static final int RSSI_PKTCNT_FETCH = BASE + 20;
- /** @hide */
- public static final int RSSI_PKTCNT_FETCH_SUCCEEDED = BASE + 21;
- /** @hide */
- public static final int RSSI_PKTCNT_FETCH_FAILED = BASE + 22;
-
/**
* Passed with {@link ActionListener#onFailure}.
* Indicates that the operation failed due to an internal error.
@@ -3019,6 +3514,11 @@ public class WifiManager {
*/
public static final int BUSY = 2;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ERROR, IN_PROGRESS, BUSY})
+ public @interface ActionListenerFailureReason {}
+
/* WPS specific errors */
/** WPS overlap detected
* @deprecated This is deprecated
@@ -3063,20 +3563,13 @@ public class WifiManager {
public interface ActionListener {
/**
* The operation succeeded.
- * This is called when the scan request has been validated and ready
- * to sent to driver.
*/
- public void onSuccess();
+ void onSuccess();
/**
* The operation failed.
- * This is called when the scan request failed.
- * @param reason The reason for failure could be one of the following:
- * {@link #REASON_INVALID_REQUEST}} is specified when scan request parameters are invalid.
- * {@link #REASON_NOT_AUTHORIZED} is specified when requesting app doesn't have the required
- * permission to request a scan.
- * {@link #REASON_UNSPECIFIED} is specified when driver reports a scan failure.
+ * @param reason The reason for failure depends on the operation.
*/
- public void onFailure(int reason);
+ void onFailure(@ActionListenerFailureReason int reason);
}
/** Interface for callback invocation on a start WPS action
@@ -3105,21 +3598,6 @@ public class WifiManager {
public abstract void onFailed(int reason);
}
- /** Interface for callback invocation on a TX packet count poll action {@hide} */
- public interface TxPacketCountListener {
- /**
- * The operation succeeded
- * @param count TX packet counter
- */
- public void onSuccess(int count);
- /**
- * The operation failed
- * @param reason The reason for failure could be one of
- * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
- */
- public void onFailure(int reason);
- }
-
/**
* Base class for soft AP callback. Should be extended by applications and set when calling
* {@link WifiManager#registerSoftApCallback(Executor, SoftApCallback)}.
@@ -3131,22 +3609,57 @@ public class WifiManager {
/**
* Called when soft AP state changes.
*
- * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
+ * @param state the new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
* {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
* {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
* @param failureReason reason when in failed state. One of
* {@link #SAP_START_FAILURE_GENERAL},
- * {@link #SAP_START_FAILURE_NO_CHANNEL}
+ * {@link #SAP_START_FAILURE_NO_CHANNEL},
+ * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
*/
- void onStateChanged(@WifiApState int state,
- @SapStartFailure int failureReason);
+ default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {}
/**
* Called when the connected clients to soft AP changes.
*
* @param clients the currently connected clients
*/
- void onConnectedClientsChanged(@NonNull List<WifiClient> clients);
+ default void onConnectedClientsChanged(@NonNull List<WifiClient> clients) {}
+
+ /**
+ * Called when information of softap changes.
+ *
+ * @param softApInfo is the softap information. {@link SoftApInfo}
+ */
+ default void onInfoChanged(@NonNull SoftApInfo softApInfo) {
+ // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
+ }
+
+ /**
+ * Called when capability of softap changes.
+ *
+ * @param softApCapability is the softap capability. {@link SoftApCapability}
+ */
+ default void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
+ // Do nothing: can be updated to add SoftApCapability details (e.g. meximum supported
+ // client number) to the UI.
+ }
+
+ /**
+ * Called when client trying to connect but device blocked the client with specific reason.
+ *
+ * Can be used to ask user to update client to allowed list or blocked list
+ * when reason is {@link SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER}, or
+ * indicate the block due to maximum supported client number limitation when reason is
+ * {@link SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS}.
+ *
+ * @param client the currently blocked client.
+ * @param blockedReason one of blocked reason from {@link SapClientBlockedReason}
+ */
+ default void onBlockedClientConnecting(@NonNull WifiClient client,
+ @SapClientBlockedReason int blockedReason) {
+ // Do nothing: can be used to ask user to update client to allowed list or blocked list.
+ }
}
/**
@@ -3188,14 +3701,60 @@ public class WifiManager {
mCallback.onConnectedClientsChanged(clients);
});
}
+
+ @Override
+ public void onInfoChanged(SoftApInfo softApInfo) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "SoftApCallbackProxy: onInfoChange: softApInfo=" + softApInfo);
+ }
+
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
+ mCallback.onInfoChanged(softApInfo);
+ });
+ }
+
+ @Override
+ public void onCapabilityChanged(SoftApCapability capability) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "SoftApCallbackProxy: onCapabilityChanged: SoftApCapability="
+ + capability);
+ }
+
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
+ mCallback.onCapabilityChanged(capability);
+ });
+ }
+
+ @Override
+ public void onBlockedClientConnecting(@NonNull WifiClient client, int blockedReason) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "SoftApCallbackProxy: onBlockedClientConnecting: client=" + client
+ + " with reason = " + blockedReason);
+ }
+
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
+ mCallback.onBlockedClientConnecting(client, blockedReason);
+ });
+ }
}
/**
- * Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the current
- * soft AP state and number of connected devices immediately after a successful call to this API
- * via callback. Note that receiving an immediate WIFI_AP_STATE_FAILED value for soft AP state
- * indicates that the latest attempt to start soft AP has failed. Caller can unregister a
- * previously registered callback using {@link #unregisterSoftApCallback}
+ * Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the
+ * following callbacks on registration:
+ * <ul>
+ * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
+ * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
+ * <li> {@link SoftApCallback#onInfoChanged(SoftApInfo)}</li>
+ * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
+ * </ul>
+ * These will be dispatched on registration to provide the caller with the current state
+ * (and are not an indication of any current change). Note that receiving an immediate
+ * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
+ * soft AP has failed. Caller can unregister a previously registered callback using
+ * {@link #unregisterSoftApCallback}
* <p>
* Applications should have the
* {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
@@ -3205,21 +3764,20 @@ public class WifiManager {
* @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
* object.
* @param callback Callback for soft AP events
- *
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void registerSoftApCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull SoftApCallback callback) {
+ @NonNull SoftApCallback callback) {
if (executor == null) throw new IllegalArgumentException("executor cannot be null");
if (callback == null) throw new IllegalArgumentException("callback cannot be null");
Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
Binder binder = new Binder();
try {
- mService.registerSoftApCallback(binder, new SoftApCallbackProxy(executor, callback),
- callback.hashCode());
+ mService.registerSoftApCallback(
+ binder, new SoftApCallbackProxy(executor, callback), callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3233,6 +3791,7 @@ public class WifiManager {
*
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void unregisterSoftApCallback(@NonNull SoftApCallback callback) {
if (callback == null) throw new IllegalArgumentException("callback cannot be null");
@@ -3246,13 +3805,13 @@ public class WifiManager {
}
/**
- * LocalOnlyHotspotReservation that contains the {@link WifiConfiguration} for the active
+ * LocalOnlyHotspotReservation that contains the {@link SoftApConfiguration} for the active
* LocalOnlyHotspot request.
* <p>
* Applications requesting LocalOnlyHotspot for sharing will receive an instance of the
* LocalOnlyHotspotReservation in the
* {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call. This
- * reservation contains the relevant {@link WifiConfiguration}.
+ * reservation contains the relevant {@link SoftApConfiguration}.
* When an application is done with the LocalOnlyHotspot, they should call {@link
* LocalOnlyHotspotReservation#close()}. Once this happens, the application will not receive
* any further callbacks. If the LocalOnlyHotspot is stopped due to a
@@ -3261,19 +3820,39 @@ public class WifiManager {
*/
public class LocalOnlyHotspotReservation implements AutoCloseable {
- private final CloseGuard mCloseGuard = CloseGuard.get();
- private final WifiConfiguration mConfig;
+ private final CloseGuard mCloseGuard = new CloseGuard();
+ private final SoftApConfiguration mSoftApConfig;
+ private final WifiConfiguration mWifiConfig;
private boolean mClosed = false;
/** @hide */
@VisibleForTesting
- public LocalOnlyHotspotReservation(WifiConfiguration config) {
- mConfig = config;
+ public LocalOnlyHotspotReservation(SoftApConfiguration config) {
+ mSoftApConfig = config;
+ mWifiConfig = config.toWifiConfiguration();
mCloseGuard.open("close");
}
+ /**
+ * Returns the {@link WifiConfiguration} of the current Local Only Hotspot (LOHS).
+ * May be null if hotspot enabled and security type is not
+ * {@code WifiConfiguration.KeyMgmt.None} or {@code WifiConfiguration.KeyMgmt.WPA2_PSK}.
+ *
+ * @deprecated Use {@code WifiManager#getSoftApConfiguration()} to get the
+ * LOHS configuration.
+ */
+ @Deprecated
+ @Nullable
public WifiConfiguration getWifiConfiguration() {
- return mConfig;
+ return mWifiConfig;
+ }
+
+ /**
+ * Returns the {@link SoftApConfiguration} of the current Local Only Hotspot (LOHS).
+ */
+ @NonNull
+ public SoftApConfiguration getSoftApConfiguration() {
+ return mSoftApConfig;
}
@Override
@@ -3288,6 +3867,8 @@ public class WifiManager {
}
} catch (Exception e) {
Log.e(TAG, "Failed to stop Local Only Hotspot.");
+ } finally {
+ Reference.reachabilityFence(this);
}
}
@@ -3345,82 +3926,63 @@ public class WifiManager {
/**
* Callback proxy for LocalOnlyHotspotCallback objects.
*/
- private static class LocalOnlyHotspotCallbackProxy {
- private final Handler mHandler;
+ private static class LocalOnlyHotspotCallbackProxy extends ILocalOnlyHotspotCallback.Stub {
private final WeakReference<WifiManager> mWifiManager;
- private final Looper mLooper;
- private final Messenger mMessenger;
+ private final Executor mExecutor;
+ private final LocalOnlyHotspotCallback mCallback;
/**
- * Constructs a {@link LocalOnlyHotspotCallback} using the specified looper. All callbacks
- * will be delivered on the thread of the specified looper.
+ * Constructs a {@link LocalOnlyHotspotCallbackProxy} using the specified executor. All
+ * callbacks will run using the given executor.
*
* @param manager WifiManager
- * @param looper Looper for delivering callbacks
- * @param callback LocalOnlyHotspotCallback to notify the calling application.
+ * @param executor Executor for delivering callbacks.
+ * @param callback LocalOnlyHotspotCallback to notify the calling application, or null.
*/
- LocalOnlyHotspotCallbackProxy(WifiManager manager, Looper looper,
- final LocalOnlyHotspotCallback callback) {
+ LocalOnlyHotspotCallbackProxy(
+ @NonNull WifiManager manager,
+ @NonNull Executor executor,
+ @Nullable LocalOnlyHotspotCallback callback) {
mWifiManager = new WeakReference<>(manager);
- mLooper = looper;
-
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- Log.d(TAG, "LocalOnlyHotspotCallbackProxy: handle message what: "
- + msg.what + " msg: " + msg);
-
- WifiManager manager = mWifiManager.get();
- if (manager == null) {
- Log.w(TAG, "LocalOnlyHotspotCallbackProxy: handle message post GC");
- return;
- }
+ mExecutor = executor;
+ mCallback = callback;
+ }
- switch (msg.what) {
- case HOTSPOT_STARTED:
- WifiConfiguration config = (WifiConfiguration) msg.obj;
- if (config == null) {
- Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
- callback.onFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
- return;
- }
- callback.onStarted(manager.new LocalOnlyHotspotReservation(config));
- break;
- case HOTSPOT_STOPPED:
- Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
- callback.onStopped();
- break;
- case HOTSPOT_FAILED:
- int reasonCode = msg.arg1;
- Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start. reason: "
- + reasonCode);
- callback.onFailed(reasonCode);
- Log.w(TAG, "done with the callback...");
- break;
- default:
- Log.e(TAG, "LocalOnlyHotspotCallbackProxy unhandled message. type: "
- + msg.what);
- }
- }
- };
- mMessenger = new Messenger(mHandler);
+ @Override
+ public void onHotspotStarted(SoftApConfiguration config) {
+ WifiManager manager = mWifiManager.get();
+ if (manager == null) return;
+
+ if (config == null) {
+ Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
+ onHotspotFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
+ return;
+ }
+ final LocalOnlyHotspotReservation reservation =
+ manager.new LocalOnlyHotspotReservation(config);
+ if (mCallback == null) return;
+ mExecutor.execute(() -> mCallback.onStarted(reservation));
}
- public Messenger getMessenger() {
- return mMessenger;
+ @Override
+ public void onHotspotStopped() {
+ WifiManager manager = mWifiManager.get();
+ if (manager == null) return;
+
+ Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
+ if (mCallback == null) return;
+ mExecutor.execute(() -> mCallback.onStopped());
}
- /**
- * Helper method allowing the the incoming application call to move the onFailed callback
- * over to the desired callback thread.
- *
- * @param reason int representing the error type
- */
- public void notifyFailed(int reason) throws RemoteException {
- Message msg = Message.obtain();
- msg.what = HOTSPOT_FAILED;
- msg.arg1 = reason;
- mMessenger.send(msg);
+ @Override
+ public void onHotspotFailed(int reason) {
+ WifiManager manager = mWifiManager.get();
+ if (manager == null) return;
+
+ Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start. reason: "
+ + reason);
+ if (mCallback == null) return;
+ mExecutor.execute(() -> mCallback.onFailed(reason));
}
}
@@ -3431,7 +3993,7 @@ public class WifiManager {
* @hide
*/
public class LocalOnlyHotspotSubscription implements AutoCloseable {
- private final CloseGuard mCloseGuard = CloseGuard.get();
+ private final CloseGuard mCloseGuard = new CloseGuard();
/** @hide */
@VisibleForTesting
@@ -3446,6 +4008,8 @@ public class WifiManager {
mCloseGuard.close();
} catch (Exception e) {
Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver.");
+ } finally {
+ Reference.reachabilityFence(this);
}
}
@@ -3477,7 +4041,7 @@ public class WifiManager {
/**
* LocalOnlyHotspot started with the supplied config.
*/
- public void onStarted(WifiConfiguration config) {};
+ public void onStarted(SoftApConfiguration config) {};
/**
* LocalOnlyHotspot stopped.
@@ -3488,191 +4052,111 @@ public class WifiManager {
/**
* Callback proxy for LocalOnlyHotspotObserver objects.
*/
- private static class LocalOnlyHotspotObserverProxy {
- private final Handler mHandler;
+ private static class LocalOnlyHotspotObserverProxy extends ILocalOnlyHotspotCallback.Stub {
private final WeakReference<WifiManager> mWifiManager;
- private final Looper mLooper;
- private final Messenger mMessenger;
+ private final Executor mExecutor;
+ private final LocalOnlyHotspotObserver mObserver;
/**
* Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper.
* All callbacks will be delivered on the thread of the specified looper.
*
* @param manager WifiManager
- * @param looper Looper for delivering callbacks
+ * @param executor Executor for delivering callbacks
* @param observer LocalOnlyHotspotObserver to notify the calling application.
*/
- LocalOnlyHotspotObserverProxy(WifiManager manager, Looper looper,
+ LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor,
final LocalOnlyHotspotObserver observer) {
mWifiManager = new WeakReference<>(manager);
- mLooper = looper;
-
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- Log.d(TAG, "LocalOnlyHotspotObserverProxy: handle message what: "
- + msg.what + " msg: " + msg);
-
- WifiManager manager = mWifiManager.get();
- if (manager == null) {
- Log.w(TAG, "LocalOnlyHotspotObserverProxy: handle message post GC");
- return;
- }
-
- switch (msg.what) {
- case HOTSPOT_OBSERVER_REGISTERED:
- observer.onRegistered(manager.new LocalOnlyHotspotSubscription());
- break;
- case HOTSPOT_STARTED:
- WifiConfiguration config = (WifiConfiguration) msg.obj;
- if (config == null) {
- Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
- return;
- }
- observer.onStarted(config);
- break;
- case HOTSPOT_STOPPED:
- observer.onStopped();
- break;
- default:
- Log.e(TAG, "LocalOnlyHotspotObserverProxy unhandled message. type: "
- + msg.what);
- }
- }
- };
- mMessenger = new Messenger(mHandler);
- }
-
- public Messenger getMessenger() {
- return mMessenger;
+ mExecutor = executor;
+ mObserver = observer;
}
public void registered() throws RemoteException {
- Message msg = Message.obtain();
- msg.what = HOTSPOT_OBSERVER_REGISTERED;
- mMessenger.send(msg);
- }
- }
+ WifiManager manager = mWifiManager.get();
+ if (manager == null) return;
- // Ensure that multiple ServiceHandler threads do not interleave message dispatch.
- private static final Object sServiceHandlerDispatchLock = new Object();
-
- private class ServiceHandler extends Handler {
- ServiceHandler(Looper looper) {
- super(looper);
+ mExecutor.execute(() ->
+ mObserver.onRegistered(manager.new LocalOnlyHotspotSubscription()));
}
@Override
- public void handleMessage(Message message) {
- synchronized (sServiceHandlerDispatchLock) {
- dispatchMessageToListeners(message);
+ public void onHotspotStarted(SoftApConfiguration config) {
+ WifiManager manager = mWifiManager.get();
+ if (manager == null) return;
+
+ if (config == null) {
+ Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
+ return;
}
+ mExecutor.execute(() -> mObserver.onStarted(config));
}
- private void dispatchMessageToListeners(Message message) {
- Object listener = removeListener(message.arg2);
- switch (message.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
- } else {
- Log.e(TAG, "Failed to set up channel connection");
- // This will cause all further async API calls on the WifiManager
- // to fail and throw an exception
- mAsyncChannel = null;
- }
- mConnected.countDown();
- break;
- case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
- // Ignore
- break;
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- Log.e(TAG, "Channel connection lost");
- // This will cause all further async API calls on the WifiManager
- // to fail and throw an exception
- mAsyncChannel = null;
- getLooper().quit();
- break;
- /* ActionListeners grouped together */
- case WifiManager.CONNECT_NETWORK_FAILED:
- case WifiManager.FORGET_NETWORK_FAILED:
- case WifiManager.SAVE_NETWORK_FAILED:
- case WifiManager.DISABLE_NETWORK_FAILED:
- if (listener != null) {
- ((ActionListener) listener).onFailure(message.arg1);
- }
- break;
- /* ActionListeners grouped together */
- case WifiManager.CONNECT_NETWORK_SUCCEEDED:
- case WifiManager.FORGET_NETWORK_SUCCEEDED:
- case WifiManager.SAVE_NETWORK_SUCCEEDED:
- case WifiManager.DISABLE_NETWORK_SUCCEEDED:
- if (listener != null) {
- ((ActionListener) listener).onSuccess();
- }
- break;
- case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
- if (listener != null) {
- RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj;
- if (info != null)
- ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad);
- else
- ((TxPacketCountListener) listener).onFailure(ERROR);
- }
- break;
- case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
- if (listener != null) {
- ((TxPacketCountListener) listener).onFailure(message.arg1);
- }
- break;
- default:
- //ignore
- break;
- }
+ @Override
+ public void onHotspotStopped() {
+ WifiManager manager = mWifiManager.get();
+ if (manager == null) return;
+
+ mExecutor.execute(() -> mObserver.onStopped());
}
- }
- private int putListener(Object listener) {
- if (listener == null) return INVALID_KEY;
- int key;
- synchronized (mListenerMapLock) {
- do {
- key = mListenerKey++;
- } while (key == INVALID_KEY);
- mListenerMap.put(key, listener);
+ @Override
+ public void onHotspotFailed(int reason) {
+ // do nothing
}
- return key;
}
- private Object removeListener(int key) {
- if (key == INVALID_KEY) return null;
- synchronized (mListenerMapLock) {
- Object listener = mListenerMap.get(key);
- mListenerMap.remove(key);
- return listener;
+ /**
+ * Callback proxy for ActionListener objects.
+ */
+ private class ActionListenerProxy extends IActionListener.Stub {
+ private final String mActionTag;
+ private final Handler mHandler;
+ private final ActionListener mCallback;
+
+ ActionListenerProxy(String actionTag, Looper looper, ActionListener callback) {
+ mActionTag = actionTag;
+ mHandler = new Handler(looper);
+ mCallback = callback;
}
- }
- private synchronized AsyncChannel getChannel() {
- if (mAsyncChannel == null) {
- Messenger messenger = getWifiServiceMessenger();
- if (messenger == null) {
- throw new IllegalStateException(
- "getWifiServiceMessenger() returned null! This is invalid.");
+ @Override
+ public void onSuccess() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onSuccess");
}
+ mHandler.post(() -> {
+ mCallback.onSuccess();
+ });
+ }
- mAsyncChannel = new AsyncChannel();
- mConnected = new CountDownLatch(1);
-
- Handler handler = new ServiceHandler(mLooper);
- mAsyncChannel.connect(mContext, handler, messenger);
- try {
- mConnected.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "interrupted wait at init");
+ @Override
+ public void onFailure(@ActionListenerFailureReason int reason) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onFailure=" + reason);
}
+ mHandler.post(() -> {
+ mCallback.onFailure(reason);
+ });
+ }
+ }
+
+ private void connectInternal(@Nullable WifiConfiguration config, int networkId,
+ @Nullable ActionListener listener) {
+ ActionListenerProxy listenerProxy = null;
+ Binder binder = null;
+ if (listener != null) {
+ listenerProxy = new ActionListenerProxy("connect", mLooper, listener);
+ binder = new Binder();
+ }
+ try {
+ mService.connect(config, networkId, binder, listenerProxy,
+ listener == null ? 0 : listener.hashCode());
+ } catch (RemoteException e) {
+ if (listenerProxy != null) listenerProxy.onFailure(ERROR);
+ } catch (SecurityException e) {
+ if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);
}
- return mAsyncChannel;
}
/**
@@ -3698,10 +4182,7 @@ public class WifiManager {
})
public void connect(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
- // Use INVALID_NETWORK_ID for arg1 when passing a config object
- // arg1 is used to pass network id when the network already exists
- getChannel().sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
- putListener(listener), config);
+ connectInternal(config, WifiConfiguration.INVALID_NETWORK_ID, listener);
}
/**
@@ -3709,6 +4190,10 @@ public class WifiManager {
*
* This function is used instead of a enableNetwork() and reconnect()
*
+ * <li> This API will cause reconnect if the credentials of the current active
+ * connection has been changed.</li>
+ * <li> This API will cause reconnect if the current active connection is marked metered.</li>
+ *
* @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
* getConfiguredNetworks}.
* @param listener for callbacks on success or failure. Can be null.
@@ -3724,7 +4209,7 @@ public class WifiManager {
})
public void connect(int networkId, @Nullable ActionListener listener) {
if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
- getChannel().sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
+ connectInternal(null, networkId, listener);
}
/**
@@ -3737,8 +4222,9 @@ public class WifiManager {
*
* For an existing network, it accomplishes the task of updateNetwork()
*
- * This API will cause reconnect if the crecdentials of the current active
- * connection has been changed.
+ * <li> This API will cause reconnect if the credentials of the current active
+ * connection has been changed.</li>
+ * <li> This API will cause disconnect if the current active connection is marked metered.</li>
*
* @param config the set of variables that describe the configuration,
* contained in a {@link WifiConfiguration} object.
@@ -3755,7 +4241,20 @@ public class WifiManager {
})
public void save(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
- getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
+ ActionListenerProxy listenerProxy = null;
+ Binder binder = null;
+ if (listener != null) {
+ listenerProxy = new ActionListenerProxy("save", mLooper, listener);
+ binder = new Binder();
+ }
+ try {
+ mService.save(config, binder, listenerProxy,
+ listener == null ? 0 : listener.hashCode());
+ } catch (RemoteException e) {
+ if (listenerProxy != null) listenerProxy.onFailure(ERROR);
+ } catch (SecurityException e) {
+ if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);
+ }
}
/**
@@ -3779,7 +4278,20 @@ public class WifiManager {
})
public void forget(int netId, @Nullable ActionListener listener) {
if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
- getChannel().sendMessage(FORGET_NETWORK, netId, putListener(listener));
+ ActionListenerProxy listenerProxy = null;
+ Binder binder = null;
+ if (listener != null) {
+ listenerProxy = new ActionListenerProxy("forget", mLooper, listener);
+ binder = new Binder();
+ }
+ try {
+ mService.forget(netId, binder, listenerProxy,
+ listener == null ? 0 : listener.hashCode());
+ } catch (RemoteException e) {
+ if (listenerProxy != null) listenerProxy.onFailure(ERROR);
+ } catch (SecurityException e) {
+ if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);
+ }
}
/**
@@ -3789,6 +4301,7 @@ public class WifiManager {
* @param listener for callbacks on success or failure. Can be null.
* @throws IllegalStateException if the WifiManager instance needs to be
* initialized again
+ * @deprecated This API is deprecated. Use {@link #disableNetwork(int)} instead.
* @hide
*/
@SystemApi
@@ -3797,25 +4310,131 @@ public class WifiManager {
android.Manifest.permission.NETWORK_SETUP_WIZARD,
android.Manifest.permission.NETWORK_STACK
})
+ @Deprecated
public void disable(int netId, @Nullable ActionListener listener) {
if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
- getChannel().sendMessage(DISABLE_NETWORK, netId, putListener(listener));
+ // Simple wrapper which forwards the call to disableNetwork. This is a temporary
+ // implementation until we can remove this API completely.
+ boolean status = disableNetwork(netId);
+ if (listener != null) {
+ if (status) {
+ listener.onSuccess();
+ } else {
+ listener.onFailure(ERROR);
+ }
+ }
}
/**
- * Disable ephemeral Network
+ * Enable/disable auto-join globally.
*
- * @param SSID, in the format of WifiConfiguration's SSID.
+ * @param allowAutojoin true to allow auto-join, false to disallow auto-join
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void allowAutojoinGlobal(boolean allowAutojoin) {
+ try {
+ mService.allowAutojoinGlobal(allowAutojoin);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
+ * Sets the user choice for allowing auto-join to a network.
+ * The updated choice will be made available through the updated config supplied by the
+ * CONFIGURED_NETWORKS_CHANGED broadcast.
+ *
+ * @param netId the id of the network to allow/disallow auto-join for.
+ * @param allowAutojoin true to allow auto-join, false to disallow auto-join
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void allowAutojoin(int netId, boolean allowAutojoin) {
+ try {
+ mService.allowAutojoin(netId, allowAutojoin);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Configure auto-join settings for a Passpoint profile.
+ *
+ * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
+ * @param allowAutojoin true to enable auto-join, false to disable auto-join.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void allowAutojoinPasspoint(@NonNull String fqdn, boolean allowAutojoin) {
+ try {
+ mService.allowAutojoinPasspoint(fqdn, allowAutojoin);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Configure MAC randomization setting for a Passpoint profile.
+ * MAC randomization is enabled by default.
+ *
+ * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
+ * @param enable true to enable MAC randomization, false to disable MAC randomization.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setMacRandomizationSettingPasspointEnabled(@NonNull String fqdn, boolean enable) {
+ try {
+ mService.setMacRandomizationSettingPasspointEnabled(fqdn, enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the user's choice of metered override for a Passpoint profile.
+ *
+ * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
+ * @param meteredOverride One of three values: {@link WifiConfiguration#METERED_OVERRIDE_NONE},
+ * {@link WifiConfiguration#METERED_OVERRIDE_METERED},
+ * {@link WifiConfiguration#METERED_OVERRIDE_NOT_METERED}
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setPasspointMeteredOverride(@NonNull String fqdn,
+ @WifiConfiguration.MeteredOverride int meteredOverride) {
+ try {
+ mService.setPasspointMeteredOverride(fqdn, meteredOverride);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Temporarily disable a network. Should always trigger with user disconnect network.
+ *
+ * @param network Input can be SSID or FQDN. And caller must ensure that the SSID passed thru
+ * this API matched the WifiConfiguration.SSID rules, and thus be surrounded by
+ * quotes.
+ * @hide
+ */
+ @SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_SETTINGS,
android.Manifest.permission.NETWORK_STACK
})
- public void disableEphemeralNetwork(String SSID) {
- if (SSID == null) throw new IllegalArgumentException("SSID cannot be null");
+ public void disableEphemeralNetwork(@NonNull String network) {
+ if (TextUtils.isEmpty(network)) {
+ throw new IllegalArgumentException("SSID cannot be null or empty!");
+ }
try {
- mService.disableEphemeralNetwork(SSID, mContext.getOpPackageName());
+ mService.disableEphemeralNetwork(network, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3851,22 +4470,6 @@ public class WifiManager {
}
/**
- * Get a reference to WifiService handler. This is used by a client to establish
- * an AsyncChannel communication with WifiService
- *
- * @return Messenger pointing to the WifiService handler
- */
- @UnsupportedAppUsage
- private Messenger getWifiServiceMessenger() {
- try {
- return mService.getWifiServiceMessenger(mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
-
- /**
* Allows an application to keep the Wi-Fi radio awake.
* Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
* Acquiring a WifiLock will keep the radio on until the lock is released. Multiple
@@ -4002,7 +4605,7 @@ public class WifiManager {
if (ws == null) {
mWorkSource = null;
} else {
- ws.clearNames();
+ ws = ws.withoutNames();
if (mWorkSource == null) {
changed = mWorkSource != null;
mWorkSource = new WorkSource(ws);
@@ -4298,22 +4901,25 @@ public class WifiManager {
}
}
- protected void finalize() throws Throwable {
- try {
- if (mAsyncChannel != null) {
- mAsyncChannel.disconnect();
- }
- } finally {
- super.finalize();
- }
- }
-
/**
- * Set wifi verbose log. Called from developer settings.
+ * Set Wi-Fi verbose logging level from developer settings.
+ *
+ * @param enable true to enable verbose logging, false to disable.
+ *
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setVerboseLoggingEnabled(boolean enable) {
+ enableVerboseLogging(enable ? 1 : 0);
+ }
+
+ /** @hide */
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.Q,
+ publicAlternatives = "Use {@code #setVerboseLoggingEnabled(boolean)} instead."
+ )
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- @UnsupportedAppUsage
public void enableVerboseLogging (int verbose) {
try {
mService.enableVerboseLogging(verbose);
@@ -4324,11 +4930,26 @@ public class WifiManager {
}
/**
- * Get the WiFi verbose logging level.This is used by settings
- * to decide what to show within the picker.
+ * Get the persisted Wi-Fi verbose logging level, set by
+ * {@link #setVerboseLoggingEnabled(boolean)}.
+ * No permissions are required to call this method.
+ *
+ * @return true to indicate that verbose logging is enabled, false to indicate that verbose
+ * logging is disabled.
+ *
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ public boolean isVerboseLoggingEnabled() {
+ return getVerboseLoggingLevel() > 0;
+ }
+
+ /** @hide */
+ // TODO(b/145484145): remove once SUW stops calling this via reflection
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.Q,
+ publicAlternatives = "Use {@code #isVerboseLoggingEnabled()} instead."
+ )
public int getVerboseLoggingLevel() {
try {
return mService.getVerboseLoggingLevel();
@@ -4338,10 +4959,13 @@ public class WifiManager {
}
/**
- * Removes all saved wifi networks.
+ * Removes all saved Wi-Fi networks, Passpoint configurations, ephemeral networks, Network
+ * Requests, and Network Suggestions.
*
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void factoryReset() {
try {
mService.factoryReset(mContext.getOpPackageName());
@@ -4351,11 +4975,15 @@ public class WifiManager {
}
/**
- * Get Network object of current wifi network
- * @return Get Network object of current wifi network
+ * Get {@link Network} object of current wifi network, or null if not connected.
* @hide
*/
- @UnsupportedAppUsage
+ @Nullable
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD
+ })
public Network getCurrentNetwork() {
try {
return mService.getCurrentNetwork();
@@ -4385,36 +5013,67 @@ public class WifiManager {
}
/**
- * Enable/disable WifiConnectivityManager
+ * Returns a byte stream representing the data that needs to be backed up to save the
+ * current Wifi state.
+ * This Wifi state can be restored by calling {@link #restoreBackupData(byte[])}.
* @hide
*/
- public void enableWifiConnectivityManager(boolean enabled) {
+ @NonNull
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public byte[] retrieveBackupData() {
try {
- mService.enableWifiConnectivityManager(enabled);
+ return mService.retrieveBackupData();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Retrieve the data to be backed to save the current state.
+ * Restore state from the backed up data.
+ * @param data byte stream in the same format produced by {@link #retrieveBackupData()}
* @hide
*/
- public byte[] retrieveBackupData() {
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void restoreBackupData(@NonNull byte[] data) {
try {
- return mService.retrieveBackupData();
+ mService.restoreBackupData(data);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Restore state from the backed up data.
+ * Returns a byte stream representing the data that needs to be backed up to save the
+ * current soft ap config data.
+ *
+ * This soft ap config can be restored by calling {@link #restoreSoftApBackupData(byte[])}
* @hide
*/
- public void restoreBackupData(byte[] data) {
+ @NonNull
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public byte[] retrieveSoftApBackupData() {
try {
- mService.restoreBackupData(data);
+ return mService.retrieveSoftApBackupData();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns soft ap config from the backed up data or null if data is invalid.
+ * @param data byte stream in the same format produced by {@link #retrieveSoftApBackupData()}
+ *
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public SoftApConfiguration restoreSoftApBackupData(@NonNull byte[] data) {
+ try {
+ return mService.restoreSoftApBackupData(data);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4424,11 +5083,14 @@ public class WifiManager {
* Restore state from the older version of back up data.
* The old backup data was essentially a backup of wpa_supplicant.conf
* and ipconfig.txt file.
- * @deprecated this is no longer supported.
+ * @param supplicantData bytes representing wpa_supplicant.conf
+ * @param ipConfigData bytes representing ipconfig.txt
* @hide
*/
- @Deprecated
- public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void restoreSupplicantBackupData(
+ @NonNull byte[] supplicantData, @NonNull byte[] ipConfigData) {
try {
mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
} catch (RemoteException e) {
@@ -4495,22 +5157,29 @@ public class WifiManager {
}
/**
- * Base class for Traffic state callback. Should be extended by applications and set when
- * calling {@link WifiManager#registerTrafficStateCallback(TrafficStateCallback, Handler)}.
+ * Interface for Traffic state callback. Should be extended by applications and set when
+ * calling {@link #registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)}.
* @hide
*/
+ @SystemApi
public interface TrafficStateCallback {
- /**
- * Lowest bit indicates data reception and the second lowest
- * bit indicates data transmitted
- */
/** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"DATA_ACTIVITY_"}, value = {
+ DATA_ACTIVITY_NONE,
+ DATA_ACTIVITY_IN,
+ DATA_ACTIVITY_OUT,
+ DATA_ACTIVITY_INOUT})
+ @interface DataActivity {}
+
+ // Lowest bit indicates data reception and the second lowest bit indicates data transmitted
+ /** No data in or out */
int DATA_ACTIVITY_NONE = 0x00;
- /** @hide */
+ /** Data in, no data out */
int DATA_ACTIVITY_IN = 0x01;
- /** @hide */
+ /** Data out, no data in */
int DATA_ACTIVITY_OUT = 0x02;
- /** @hide */
+ /** Data in and out */
int DATA_ACTIVITY_INOUT = 0x03;
/**
@@ -4518,9 +5187,8 @@ public class WifiManager {
*
* @param state One of the values: {@link #DATA_ACTIVITY_NONE}, {@link #DATA_ACTIVITY_IN},
* {@link #DATA_ACTIVITY_OUT} & {@link #DATA_ACTIVITY_INOUT}.
- * @hide
*/
- void onStateChanged(int state);
+ void onStateChanged(@DataActivity int state);
}
/**
@@ -4529,11 +5197,11 @@ public class WifiManager {
* @hide
*/
private class TrafficStateCallbackProxy extends ITrafficStateCallback.Stub {
- private final Handler mHandler;
+ private final Executor mExecutor;
private final TrafficStateCallback mCallback;
- TrafficStateCallbackProxy(Looper looper, TrafficStateCallback callback) {
- mHandler = new Handler(looper);
+ TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback) {
+ mExecutor = executor;
mCallback = callback;
}
@@ -4542,7 +5210,8 @@ public class WifiManager {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "TrafficStateCallbackProxy: onStateChanged state=" + state);
}
- mHandler.post(() -> {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
mCallback.onStateChanged(state);
});
}
@@ -4559,22 +5228,23 @@ public class WifiManager {
* without the permission will trigger a {@link java.lang.SecurityException}.
* <p>
*
+ * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
+ * object.
* @param callback Callback for traffic state events
- * @param handler The Handler on whose thread to execute the callbacks of the {@code callback}
- * object. If null, then the application's main thread will be used.
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void registerTrafficStateCallback(@NonNull TrafficStateCallback callback,
- @Nullable Handler handler) {
+ public void registerTrafficStateCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull TrafficStateCallback callback) {
+ if (executor == null) throw new IllegalArgumentException("executor cannot be null");
if (callback == null) throw new IllegalArgumentException("callback cannot be null");
- Log.v(TAG, "registerTrafficStateCallback: callback=" + callback + ", handler=" + handler);
+ Log.v(TAG, "registerTrafficStateCallback: callback=" + callback + ", executor=" + executor);
- Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
Binder binder = new Binder();
try {
mService.registerTrafficStateCallback(
- binder, new TrafficStateCallbackProxy(looper, callback), callback.hashCode());
+ binder, new TrafficStateCallbackProxy(executor, callback), callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4587,6 +5257,7 @@ public class WifiManager {
* @param callback Callback to unregister for traffic state events
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void unregisterTrafficStateCallback(@NonNull TrafficStateCallback callback) {
if (callback == null) throw new IllegalArgumentException("callback cannot be null");
@@ -4604,7 +5275,7 @@ public class WifiManager {
* level from wifi service.
*/
private void updateVerboseLoggingEnabledFromService() {
- mVerboseLoggingEnabled = getVerboseLoggingLevel() > 0;
+ mVerboseLoggingEnabled = isVerboseLoggingEnabled();
}
/**
@@ -4641,11 +5312,20 @@ public class WifiManager {
}
/**
+ * @return true if this device supports WAPI.
+ */
+ public boolean isWapiSupported() {
+ return isFeatureSupported(WIFI_FEATURE_WAPI);
+ }
+
+ /**
* Gets the factory Wi-Fi MAC addresses.
* @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
* if failed.
* @hide
*/
+ @NonNull
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String[] getFactoryMacAddresses() {
try {
@@ -4845,6 +5525,7 @@ public class WifiManager {
@Override
public void onSuccessConfigReceived(int newNetworkId) {
Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
+ Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
});
@@ -4853,22 +5534,28 @@ public class WifiManager {
@Override
public void onSuccess(int status) {
Log.d(TAG, "Easy Connect onSuccess callback");
+ Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mEasyConnectStatusCallback.onConfiguratorSuccess(status);
});
}
@Override
- public void onFailure(int status) {
+ public void onFailure(int status, String ssid, String channelList,
+ int[] operatingClassArray) {
Log.d(TAG, "Easy Connect onFailure callback");
+ Binder.clearCallingIdentity();
mExecutor.execute(() -> {
- mEasyConnectStatusCallback.onFailure(status);
+ SparseArray<int[]> channelListArray = parseDppChannelList(channelList);
+ mEasyConnectStatusCallback.onFailure(status, ssid, channelListArray,
+ operatingClassArray);
});
}
@Override
public void onProgress(int status) {
Log.d(TAG, "Easy Connect onProgress callback");
+ Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mEasyConnectStatusCallback.onProgress(status);
});
@@ -4929,9 +5616,9 @@ public class WifiManager {
Log.v(TAG, "OnWifiUsabilityStatsListener: "
+ "onWifiUsabilityStats: seqNum=" + seqNum);
}
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() -> listener.onWifiUsabilityStats(seqNum,
- isSameBssidAndFreq, stats)));
+ Binder.clearCallingIdentity();
+ executor.execute(() -> listener.onWifiUsabilityStats(
+ seqNum, isSameBssidAndFreq, stats));
}
},
listener.hashCode()
@@ -4985,4 +5672,564 @@ public class WifiManager {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Abstract class for scan results callback. Should be extended by applications and set when
+ * calling {@link WifiManager#registerScanResultsCallback(Executor, ScanResultsCallback)}.
+ */
+ public abstract static class ScanResultsCallback {
+ private final ScanResultsCallbackProxy mScanResultsCallbackProxy;
+
+ public ScanResultsCallback() {
+ mScanResultsCallbackProxy = new ScanResultsCallbackProxy();
+ }
+
+ /**
+ * Called when new scan results are available.
+ * Clients should use {@link WifiManager#getScanResults()} to get the scan results.
+ */
+ public abstract void onScanResultsAvailable();
+
+ /*package*/ @NonNull ScanResultsCallbackProxy getProxy() {
+ return mScanResultsCallbackProxy;
+ }
+
+ private static class ScanResultsCallbackProxy extends IScanResultsCallback.Stub {
+ private final Object mLock = new Object();
+ @Nullable @GuardedBy("mLock") private Executor mExecutor;
+ @Nullable @GuardedBy("mLock") private ScanResultsCallback mCallback;
+
+ ScanResultsCallbackProxy() {
+ mCallback = null;
+ mExecutor = null;
+ }
+
+ /*package*/ void initProxy(@NonNull Executor executor,
+ @NonNull ScanResultsCallback callback) {
+ synchronized (mLock) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+ }
+
+ /*package*/ void cleanUpProxy() {
+ synchronized (mLock) {
+ mExecutor = null;
+ mCallback = null;
+ }
+ }
+
+ @Override
+ public void onScanResultsAvailable() {
+ ScanResultsCallback callback;
+ Executor executor;
+ synchronized (mLock) {
+ executor = mExecutor;
+ callback = mCallback;
+ }
+ if (callback == null || executor == null) {
+ return;
+ }
+ Binder.clearCallingIdentity();
+ executor.execute(callback::onScanResultsAvailable);
+ }
+ }
+
+ }
+
+ /**
+ * Register a callback for Scan Results. See {@link ScanResultsCallback}.
+ * Caller will receive the event when scan results are available.
+ * Caller should use {@link WifiManager#getScanResults()} requires
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} to get the scan results.
+ * Caller can remove a previously registered callback using
+ * {@link WifiManager#unregisterScanResultsCallback(ScanResultsCallback)}
+ * Same caller can add multiple listeners.
+ * <p>
+ * Applications should have the
+ * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission. Callers
+ * without the permission will trigger a {@link java.lang.SecurityException}.
+ * <p>
+ *
+ * @param executor The executor to execute the callback of the {@code callback} object.
+ * @param callback callback for Scan Results events
+ */
+
+ @RequiresPermission(ACCESS_WIFI_STATE)
+ public void registerScanResultsCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull ScanResultsCallback callback) {
+ if (executor == null) throw new IllegalArgumentException("executor cannot be null");
+ if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+
+ Log.v(TAG, "registerScanResultsCallback: callback=" + callback
+ + ", executor=" + executor);
+ ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
+ proxy.initProxy(executor, callback);
+ try {
+ mService.registerScanResultsCallback(proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Allow callers to unregister a previously registered callback. After calling this method,
+ * applications will no longer receive Scan Results events.
+ *
+ * @param callback callback to unregister for Scan Results events
+ */
+ @RequiresPermission(ACCESS_WIFI_STATE)
+ public void unregisterScanResultsCallback(@NonNull ScanResultsCallback callback) {
+ if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+ Log.v(TAG, "unregisterScanResultsCallback: Callback=" + callback);
+ ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
+ try {
+ mService.unregisterScanResultsCallback(proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } finally {
+ proxy.cleanUpProxy();
+ }
+ }
+
+ /**
+ * Interface for suggestion connection status listener.
+ * Should be implemented by applications and set when calling
+ * {@link WifiManager#addSuggestionConnectionStatusListener(
+ * Executor, SuggestionConnectionStatusListener)}.
+ */
+ public interface SuggestionConnectionStatusListener {
+
+ /**
+ * Called when the framework attempted to connect to a suggestion provided by the
+ * registering app, but the connection to the suggestion failed.
+ * @param wifiNetworkSuggestion The suggestion which failed to connect.
+ * @param failureReason the connection failure reason code. One of
+ * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION},
+ * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION},
+ * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING}
+ * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN}
+ */
+ void onConnectionStatus(
+ @NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
+ @SuggestionConnectionStatusCode int failureReason);
+ }
+
+ private class SuggestionConnectionStatusListenerProxy extends
+ ISuggestionConnectionStatusListener.Stub {
+ private final Executor mExecutor;
+ private final SuggestionConnectionStatusListener mListener;
+
+ SuggestionConnectionStatusListenerProxy(@NonNull Executor executor,
+ @NonNull SuggestionConnectionStatusListener listener) {
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onConnectionStatus(@NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
+ int failureReason) {
+ mExecutor.execute(() ->
+ mListener.onConnectionStatus(wifiNetworkSuggestion, failureReason));
+ }
+
+ }
+
+ /**
+ * Add a listener for suggestion networks. See {@link SuggestionConnectionStatusListener}.
+ * Caller will receive the event when suggested network have connection failure.
+ * Caller can remove a previously registered listener using
+ * {@link WifiManager#removeSuggestionConnectionStatusListener(
+ * SuggestionConnectionStatusListener)}
+ * Same caller can add multiple listeners to monitor the event.
+ * <p>
+ * Applications should have the
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
+ * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permissions.
+ * Callers without the permission will trigger a {@link java.lang.SecurityException}.
+ * <p>
+ *
+ * @param executor The executor to execute the listener of the {@code listener} object.
+ * @param listener listener for suggestion network connection failure.
+ */
+ @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
+ public void addSuggestionConnectionStatusListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull SuggestionConnectionStatusListener listener) {
+ if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
+ if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
+ Log.v(TAG, "addSuggestionConnectionStatusListener listener=" + listener
+ + ", executor=" + executor);
+ try {
+ mService.registerSuggestionConnectionStatusListener(new Binder(),
+ new SuggestionConnectionStatusListenerProxy(executor, listener),
+ listener.hashCode(), mContext.getOpPackageName(), mContext.getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ }
+
+ /**
+ * Allow callers to remove a previously registered listener. After calling this method,
+ * applications will no longer receive suggestion connection events through that listener.
+ *
+ * @param listener listener to remove.
+ */
+ @RequiresPermission(ACCESS_WIFI_STATE)
+ public void removeSuggestionConnectionStatusListener(
+ @NonNull SuggestionConnectionStatusListener listener) {
+ if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
+ Log.v(TAG, "removeSuggestionConnectionStatusListener: listener=" + listener);
+ try {
+ mService.unregisterSuggestionConnectionStatusListener(listener.hashCode(),
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Parse the list of channels the DPP enrollee reports when it fails to find an AP.
+ *
+ * @param channelList List of channels in the format defined in the DPP specification.
+ * @return A parsed sparse array, where the operating class is the key.
+ * @hide
+ */
+ @VisibleForTesting
+ public static SparseArray<int[]> parseDppChannelList(String channelList) {
+ SparseArray<int[]> channelListArray = new SparseArray<>();
+
+ if (TextUtils.isEmpty(channelList)) {
+ return channelListArray;
+ }
+ StringTokenizer str = new StringTokenizer(channelList, ",");
+ String classStr = null;
+ List<Integer> channelsInClass = new ArrayList<>();
+
+ try {
+ while (str.hasMoreElements()) {
+ String cur = str.nextToken();
+
+ /**
+ * Example for a channel list:
+ *
+ * 81/1,2,3,4,5,6,7,8,9,10,11,115/36,40,44,48,118/52,56,60,64,121/100,104,108,112,
+ * 116,120,124,128,132,136,140,0/144,124/149,153,157,161,125/165
+ *
+ * Detect operating class by the delimiter of '/' and use a string tokenizer with
+ * ',' as a delimiter.
+ */
+ int classDelim = cur.indexOf('/');
+ if (classDelim != -1) {
+ if (classStr != null) {
+ // Store the last channel array in the sparse array, where the operating
+ // class is the key (as an integer).
+ int[] channelsArray = new int[channelsInClass.size()];
+ for (int i = 0; i < channelsInClass.size(); i++) {
+ channelsArray[i] = channelsInClass.get(i);
+ }
+ channelListArray.append(Integer.parseInt(classStr), channelsArray);
+ channelsInClass = new ArrayList<>();
+ }
+
+ // Init a new operating class and store the first channel
+ classStr = cur.substring(0, classDelim);
+ String channelStr = cur.substring(classDelim + 1);
+ channelsInClass.add(Integer.parseInt(channelStr));
+ } else {
+ if (classStr == null) {
+ // Invalid format
+ Log.e(TAG, "Cannot parse DPP channel list");
+ return new SparseArray<>();
+ }
+ channelsInClass.add(Integer.parseInt(cur));
+ }
+ }
+
+ // Store the last array
+ if (classStr != null) {
+ int[] channelsArray = new int[channelsInClass.size()];
+ for (int i = 0; i < channelsInClass.size(); i++) {
+ channelsArray[i] = channelsInClass.get(i);
+ }
+ channelListArray.append(Integer.parseInt(classStr), channelsArray);
+ }
+ return channelListArray;
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Cannot parse DPP channel list");
+ return new SparseArray<>();
+ }
+ }
+
+ /**
+ * Callback interface for framework to receive network status updates and trigger of updating
+ * {@link WifiUsabilityStatsEntry}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface ScoreUpdateObserver {
+ /**
+ * Called by applications to indicate network status.
+ *
+ * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
+ * @param score The score representing link quality of current Wi-Fi network connection.
+ * Populated by connected network scorer in applications..
+ */
+ void notifyScoreUpdate(int sessionId, int score);
+
+ /**
+ * Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
+ * To receive update applications need to add WifiUsabilityStatsEntry listener. See
+ * {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
+ *
+ * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
+ */
+ void triggerUpdateOfWifiUsabilityStats(int sessionId);
+ }
+
+ /**
+ * Callback proxy for {@link ScoreUpdateObserver} objects.
+ *
+ * @hide
+ */
+ private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
+ private final IScoreUpdateObserver mScoreUpdateObserver;
+
+ private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
+ mScoreUpdateObserver = observer;
+ }
+
+ @Override
+ public void notifyScoreUpdate(int sessionId, int score) {
+ try {
+ mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
+ try {
+ mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Interface for Wi-Fi connected network scorer. Should be implemented by applications and set
+ * when calling
+ * {@link WifiManager#setWifiConnectedNetworkScorer(Executor, WifiConnectedNetworkScorer)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface WifiConnectedNetworkScorer {
+ /**
+ * Called by framework to indicate the start of a network connection.
+ * @param sessionId The ID to indicate current Wi-Fi network connection.
+ */
+ void onStart(int sessionId);
+
+ /**
+ * Called by framework to indicate the end of a network connection.
+ * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
+ */
+ void onStop(int sessionId);
+
+ /**
+ * Framework sets callback for score change events after application sets its scorer.
+ * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
+ * implemented and instantiated by framework.
+ */
+ void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
+ }
+
+ /**
+ * Callback proxy for {@link WifiConnectedNetworkScorer} objects.
+ *
+ * @hide
+ */
+ private class WifiConnectedNetworkScorerProxy extends IWifiConnectedNetworkScorer.Stub {
+ private Executor mExecutor;
+ private WifiConnectedNetworkScorer mScorer;
+
+ WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer) {
+ mExecutor = executor;
+ mScorer = scorer;
+ }
+
+ @Override
+ public void onStart(int sessionId) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionId=" + sessionId);
+ }
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mScorer.onStart(sessionId));
+ }
+
+ @Override
+ public void onStop(int sessionId) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
+ }
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mScorer.onStop(sessionId));
+ }
+
+ @Override
+ public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "WifiConnectedNetworkScorer: "
+ + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
+ }
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
+ new ScoreUpdateObserverProxy(observerImpl)));
+ }
+ }
+
+ /**
+ * Set a callback for Wi-Fi connected network scorer. See {@link WifiConnectedNetworkScorer}.
+ * Only a single scorer can be set. Caller will be invoked periodically by framework to inform
+ * client about start and stop of Wi-Fi connection. Caller can clear a previously set scorer
+ * using {@link clearWifiConnectedNetworkScorer()}.
+ *
+ * @param executor The executor on which callback will be invoked.
+ * @param scorer Scorer for Wi-Fi network implemented by application.
+ * @return true Scorer is set successfully.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
+ public boolean setWifiConnectedNetworkScorer(@NonNull @CallbackExecutor Executor executor,
+ @NonNull WifiConnectedNetworkScorer scorer) {
+ if (executor == null) throw new IllegalArgumentException("executor cannot be null");
+ if (scorer == null) throw new IllegalArgumentException("scorer cannot be null");
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "setWifiConnectedNetworkScorer: scorer=" + scorer);
+ }
+ try {
+ return mService.setWifiConnectedNetworkScorer(new Binder(),
+ new WifiConnectedNetworkScorerProxy(executor, scorer));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Allow caller to clear a previously set scorer. After calling this method,
+ * client will no longer receive information about start and stop of Wi-Fi connection.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
+ public void clearWifiConnectedNetworkScorer() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "clearWifiConnectedNetworkScorer");
+ }
+ try {
+ mService.clearWifiConnectedNetworkScorer();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Enable/disable wifi scan throttling from 3rd party apps.
+ *
+ * <p>
+ * The throttling limits for apps are described in
+ * <a href="Wi-Fi Scan Throttling">
+ * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
+ * </p>
+ *
+ * @param enable true to allow scan throttling, false to disallow scan throttling.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setScanThrottleEnabled(boolean enable) {
+ try {
+ mService.setScanThrottleEnabled(enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the persisted Wi-Fi scan throttle state. Defaults to true, unless changed by the user via
+ * Developer options.
+ *
+ * <p>
+ * The throttling limits for apps are described in
+ * <a href="Wi-Fi Scan Throttling">
+ * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
+ * </p>
+ *
+ * @return true to indicate that scan throttling is enabled, false to indicate that scan
+ * throttling is disabled.
+ */
+ @RequiresPermission(ACCESS_WIFI_STATE)
+ public boolean isScanThrottleEnabled() {
+ try {
+ return mService.isScanThrottleEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Enable/disable wifi auto wakeup feature.
+ *
+ * <p>
+ * The feature is described in
+ * <a href="Wi-Fi Turn on automatically">
+ * https://source.android.com/devices/tech/connect/wifi-infrastructure
+ * #turn_on_wi-fi_automatically
+ * </a>
+ *
+ * @param enable true to enable, false to disable.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setAutoWakeupEnabled(boolean enable) {
+ try {
+ mService.setAutoWakeupEnabled(enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the persisted Wi-Fi auto wakeup feature state. Defaults to false, unless changed by the
+ * user via Settings.
+ *
+ * <p>
+ * The feature is described in
+ * <a href="Wi-Fi Turn on automatically">
+ * https://source.android.com/devices/tech/connect/wifi-infrastructure
+ * #turn_on_wi-fi_automatically
+ * </a>
+ *
+ * @return true to indicate that wakeup feature is enabled, false to indicate that wakeup
+ * feature is disabled.
+ */
+ @RequiresPermission(ACCESS_WIFI_STATE)
+ public boolean isAutoWakeupEnabled() {
+ try {
+ return mService.isAutoWakeupEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiMigration.java b/wifi/java/android/net/wifi/WifiMigration.java
new file mode 100755
index 000000000000..5792d27a94f9
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiMigration.java
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static android.os.Environment.getDataMiscCeDirectory;
+import static android.os.Environment.getDataMiscDirectory;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.AtomicFile;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Class used to provide one time hooks for existing OEM devices to migrate their config store
+ * data and other settings to the wifi apex.
+ * @hide
+ */
+@SystemApi
+public final class WifiMigration {
+ /**
+ * Directory to read the wifi config store files from under.
+ */
+ private static final String LEGACY_WIFI_STORE_DIRECTORY_NAME = "wifi";
+ /**
+ * Config store file for general shared store file.
+ * AOSP Path on Android 10: /data/misc/wifi/WifiConfigStore.xml
+ */
+ public static final int STORE_FILE_SHARED_GENERAL = 0;
+ /**
+ * Config store file for softap shared store file.
+ * AOSP Path on Android 10: /data/misc/wifi/softap.conf
+ */
+ public static final int STORE_FILE_SHARED_SOFTAP = 1;
+ /**
+ * Config store file for general user store file.
+ * AOSP Path on Android 10: /data/misc_ce/<userId>/wifi/WifiConfigStore.xml
+ */
+ public static final int STORE_FILE_USER_GENERAL = 2;
+ /**
+ * Config store file for network suggestions user store file.
+ * AOSP Path on Android 10: /data/misc_ce/<userId>/wifi/WifiConfigStoreNetworkSuggestions.xml
+ */
+ public static final int STORE_FILE_USER_NETWORK_SUGGESTIONS = 3;
+
+ /** @hide */
+ @IntDef(prefix = { "STORE_FILE_SHARED_" }, value = {
+ STORE_FILE_SHARED_GENERAL,
+ STORE_FILE_SHARED_SOFTAP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SharedStoreFileId { }
+
+ /** @hide */
+ @IntDef(prefix = { "STORE_FILE_USER_" }, value = {
+ STORE_FILE_USER_GENERAL,
+ STORE_FILE_USER_NETWORK_SUGGESTIONS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UserStoreFileId { }
+
+ /**
+ * Mapping of Store file Id to Store file names.
+ *
+ * NOTE: This is the default path for the files on AOSP devices. If the OEM has modified
+ * the path or renamed the files, please edit this appropriately.
+ */
+ private static final SparseArray<String> STORE_ID_TO_FILE_NAME =
+ new SparseArray<String>() {{
+ put(STORE_FILE_SHARED_GENERAL, "WifiConfigStore.xml");
+ put(STORE_FILE_SHARED_SOFTAP, "WifiConfigStoreSoftAp.xml");
+ put(STORE_FILE_USER_GENERAL, "WifiConfigStore.xml");
+ put(STORE_FILE_USER_NETWORK_SUGGESTIONS, "WifiConfigStoreNetworkSuggestions.xml");
+ }};
+
+ /**
+ * Pre-apex wifi shared folder.
+ */
+ private static File getLegacyWifiSharedDirectory() {
+ return new File(getDataMiscDirectory(), LEGACY_WIFI_STORE_DIRECTORY_NAME);
+ }
+
+ /**
+ * Pre-apex wifi user folder.
+ */
+ private static File getLegacyWifiUserDirectory(int userId) {
+ return new File(getDataMiscCeDirectory(userId), LEGACY_WIFI_STORE_DIRECTORY_NAME);
+ }
+
+ /**
+ * Legacy files were stored as AtomicFile. So, always use AtomicFile to operate on it to ensure
+ * data integrity.
+ */
+ private static AtomicFile getSharedAtomicFile(@SharedStoreFileId int storeFileId) {
+ return new AtomicFile(new File(
+ getLegacyWifiSharedDirectory(),
+ STORE_ID_TO_FILE_NAME.get(storeFileId)));
+ }
+
+ /**
+ * Legacy files were stored as AtomicFile. So, always use AtomicFile to operate on it to ensure
+ * data integrity.
+ */
+ private static AtomicFile getUserAtomicFile(@UserStoreFileId int storeFileId, int userId) {
+ return new AtomicFile(new File(
+ getLegacyWifiUserDirectory(userId),
+ STORE_ID_TO_FILE_NAME.get(storeFileId)));
+ }
+
+ private WifiMigration() { }
+
+ /**
+ * Load data from legacy shared wifi config store file.
+ * <p>
+ * Expected AOSP format is available in the sample files under {@code /frameworks/base/wifi/
+ * java/android/net/wifi/migration_samples}.
+ * </p>
+ * <p>
+ * Note:
+ * <li>OEMs need to change the implementation of
+ * {@link #convertAndRetrieveSharedConfigStoreFile(int)} only if their existing config store
+ * format or file locations differs from the vanilla AOSP implementation.</li>
+ * <li>The wifi apex will invoke
+ * {@link #convertAndRetrieveSharedConfigStoreFile(int)}
+ * method on every bootup, it is the responsibility of the OEM implementation to ensure that
+ * they perform the necessary in place conversion of their config store file to conform to the
+ * AOSP format. The OEM should ensure that the method should only return the
+ * {@link InputStream} stream for the data to be migrated only on the first bootup.</li>
+ * <li>Once the migration is done, the apex will invoke
+ * {@link #removeSharedConfigStoreFile(int)} to delete the store file.</li>
+ * <li>The only relevant invocation of {@link #convertAndRetrieveSharedConfigStoreFile(int)}
+ * occurs when a previously released device upgrades to the wifi apex from an OEM
+ * implementation of the wifi stack.
+ * <li>Ensure that the legacy file paths are accessible to the wifi module (sepolicy rules, file
+ * permissions, etc). Since the wifi service continues to run inside system_server process, this
+ * method will be called from the same context (so ideally the file should still be accessible).
+ * </li>
+ *
+ * @param storeFileId Identifier for the config store file. One of
+ * {@link #STORE_FILE_SHARED_GENERAL} or {@link #STORE_FILE_SHARED_GENERAL}
+ * @return Instance of {@link InputStream} for migrating data, null if no migration is
+ * necessary.
+ * @throws IllegalArgumentException on invalid storeFileId.
+ */
+ @Nullable
+ public static InputStream convertAndRetrieveSharedConfigStoreFile(
+ @SharedStoreFileId int storeFileId) {
+ if (storeFileId != STORE_FILE_SHARED_GENERAL && storeFileId != STORE_FILE_SHARED_SOFTAP) {
+ throw new IllegalArgumentException("Invalid shared store file id");
+ }
+ try {
+ // OEMs should do conversions necessary here before returning the stream.
+ return getSharedAtomicFile(storeFileId).openRead();
+ } catch (FileNotFoundException e) {
+ // Special handling for softap.conf.
+ // Note: OEM devices upgrading from Q -> R will only have the softap.conf file.
+ // Test devices running previous R builds however may have already migrated to the
+ // XML format. So, check for that above before falling back to check for legacy file.
+ if (storeFileId == STORE_FILE_SHARED_SOFTAP) {
+ return SoftApConfToXmlMigrationUtil.convert();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Remove the legacy shared wifi config store file.
+ *
+ * @param storeFileId Identifier for the config store file. One of
+ * {@link #STORE_FILE_SHARED_GENERAL} or {@link #STORE_FILE_SHARED_GENERAL}
+ * @throws IllegalArgumentException on invalid storeFileId.
+ */
+ public static void removeSharedConfigStoreFile(@SharedStoreFileId int storeFileId) {
+ if (storeFileId != STORE_FILE_SHARED_GENERAL && storeFileId != STORE_FILE_SHARED_SOFTAP) {
+ throw new IllegalArgumentException("Invalid shared store file id");
+ }
+ AtomicFile file = getSharedAtomicFile(storeFileId);
+ if (file.exists()) {
+ file.delete();
+ return;
+ }
+ // Special handling for softap.conf.
+ // Note: OEM devices upgrading from Q -> R will only have the softap.conf file.
+ // Test devices running previous R builds however may have already migrated to the
+ // XML format. So, check for that above before falling back to check for legacy file.
+ if (storeFileId == STORE_FILE_SHARED_SOFTAP) {
+ SoftApConfToXmlMigrationUtil.remove();
+ }
+ }
+
+ /**
+ * Load data from legacy user wifi config store file.
+ * <p>
+ * Expected AOSP format is available in the sample files under {@code /frameworks/base/wifi/
+ * java/android/net/wifi/migration_samples}.
+ * </p>
+ * <p>
+ * Note:
+ * <li>OEMs need to change the implementation of
+ * {@link #convertAndRetrieveUserConfigStoreFile(int, UserHandle)} only if their existing config
+ * store format or file locations differs from the vanilla AOSP implementation.</li>
+ * <li>The wifi apex will invoke
+ * {@link #convertAndRetrieveUserConfigStoreFile(int, UserHandle)}
+ * method on every bootup, it is the responsibility of the OEM implementation to ensure that
+ * they perform the necessary in place conversion of their config store file to conform to the
+ * AOSP format. The OEM should ensure that the method should only return the
+ * {@link InputStream} stream for the data to be migrated only on the first bootup.</li>
+ * <li>Once the migration is done, the apex will invoke
+ * {@link #removeUserConfigStoreFile(int, UserHandle)} to delete the store file.</li>
+ * <li>The only relevant invocation of
+ * {@link #convertAndRetrieveUserConfigStoreFile(int, UserHandle)} occurs when a previously
+ * released device upgrades to the wifi apex from an OEM implementation of the wifi
+ * stack.
+ * </li>
+ * <li>Ensure that the legacy file paths are accessible to the wifi module (sepolicy rules, file
+ * permissions, etc). Since the wifi service continues to run inside system_server process, this
+ * method will be called from the same context (so ideally the file should still be accessible).
+ * </li>
+ *
+ * @param storeFileId Identifier for the config store file. One of
+ * {@link #STORE_FILE_USER_GENERAL} or {@link #STORE_FILE_USER_NETWORK_SUGGESTIONS}
+ * @param userHandle User handle.
+ * @return Instance of {@link InputStream} for migrating data, null if no migration is
+ * necessary.
+ * @throws IllegalArgumentException on invalid storeFileId or userHandle.
+ */
+ @Nullable
+ public static InputStream convertAndRetrieveUserConfigStoreFile(
+ @UserStoreFileId int storeFileId, @NonNull UserHandle userHandle) {
+ if (storeFileId != STORE_FILE_USER_GENERAL
+ && storeFileId != STORE_FILE_USER_NETWORK_SUGGESTIONS) {
+ throw new IllegalArgumentException("Invalid user store file id");
+ }
+ Objects.requireNonNull(userHandle);
+ try {
+ // OEMs should do conversions necessary here before returning the stream.
+ return getUserAtomicFile(storeFileId, userHandle.getIdentifier()).openRead();
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Remove the legacy user wifi config store file.
+ *
+ * @param storeFileId Identifier for the config store file. One of
+ * {@link #STORE_FILE_USER_GENERAL} or {@link #STORE_FILE_USER_NETWORK_SUGGESTIONS}
+ * @param userHandle User handle.
+ * @throws IllegalArgumentException on invalid storeFileId or userHandle.
+ */
+ public static void removeUserConfigStoreFile(
+ @UserStoreFileId int storeFileId, @NonNull UserHandle userHandle) {
+ if (storeFileId != STORE_FILE_USER_GENERAL
+ && storeFileId != STORE_FILE_USER_NETWORK_SUGGESTIONS) {
+ throw new IllegalArgumentException("Invalid user store file id");
+ }
+ Objects.requireNonNull(userHandle);
+ AtomicFile file = getUserAtomicFile(storeFileId, userHandle.getIdentifier());
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+
+ /**
+ * Container for all the wifi settings data to migrate.
+ */
+ public static final class SettingsMigrationData implements Parcelable {
+ private final boolean mScanAlwaysAvailable;
+ private final boolean mP2pFactoryResetPending;
+ private final String mP2pDeviceName;
+ private final boolean mSoftApTimeoutEnabled;
+ private final boolean mWakeupEnabled;
+ private final boolean mScanThrottleEnabled;
+ private final boolean mVerboseLoggingEnabled;
+
+ private SettingsMigrationData(boolean scanAlwaysAvailable, boolean p2pFactoryResetPending,
+ @Nullable String p2pDeviceName, boolean softApTimeoutEnabled, boolean wakeupEnabled,
+ boolean scanThrottleEnabled, boolean verboseLoggingEnabled) {
+ mScanAlwaysAvailable = scanAlwaysAvailable;
+ mP2pFactoryResetPending = p2pFactoryResetPending;
+ mP2pDeviceName = p2pDeviceName;
+ mSoftApTimeoutEnabled = softApTimeoutEnabled;
+ mWakeupEnabled = wakeupEnabled;
+ mScanThrottleEnabled = scanThrottleEnabled;
+ mVerboseLoggingEnabled = verboseLoggingEnabled;
+ }
+
+ public static final @NonNull Parcelable.Creator<SettingsMigrationData> CREATOR =
+ new Parcelable.Creator<SettingsMigrationData>() {
+ @Override
+ public SettingsMigrationData createFromParcel(Parcel in) {
+ boolean scanAlwaysAvailable = in.readBoolean();
+ boolean p2pFactoryResetPending = in.readBoolean();
+ String p2pDeviceName = in.readString();
+ boolean softApTimeoutEnabled = in.readBoolean();
+ boolean wakeupEnabled = in.readBoolean();
+ boolean scanThrottleEnabled = in.readBoolean();
+ boolean verboseLoggingEnabled = in.readBoolean();
+ return new SettingsMigrationData(
+ scanAlwaysAvailable, p2pFactoryResetPending,
+ p2pDeviceName, softApTimeoutEnabled, wakeupEnabled,
+ scanThrottleEnabled, verboseLoggingEnabled);
+ }
+
+ @Override
+ public SettingsMigrationData[] newArray(int size) {
+ return new SettingsMigrationData[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeBoolean(mScanAlwaysAvailable);
+ dest.writeBoolean(mP2pFactoryResetPending);
+ dest.writeString(mP2pDeviceName);
+ dest.writeBoolean(mSoftApTimeoutEnabled);
+ dest.writeBoolean(mWakeupEnabled);
+ dest.writeBoolean(mScanThrottleEnabled);
+ dest.writeBoolean(mVerboseLoggingEnabled);
+ }
+
+ /**
+ * @return True if scans are allowed even when wifi is toggled off, false otherwise.
+ */
+ public boolean isScanAlwaysAvailable() {
+ return mScanAlwaysAvailable;
+ }
+
+ /**
+ * @return indicate whether factory reset request is pending.
+ */
+ public boolean isP2pFactoryResetPending() {
+ return mP2pFactoryResetPending;
+ }
+
+ /**
+ * @return the Wi-Fi peer-to-peer device name
+ */
+ public @Nullable String getP2pDeviceName() {
+ return mP2pDeviceName;
+ }
+
+ /**
+ * @return Whether soft AP will shut down after a timeout period when no devices are
+ * connected.
+ */
+ public boolean isSoftApTimeoutEnabled() {
+ return mSoftApTimeoutEnabled;
+ }
+
+ /**
+ * @return whether Wi-Fi Wakeup feature is enabled.
+ */
+ public boolean isWakeUpEnabled() {
+ return mWakeupEnabled;
+ }
+
+ /**
+ * @return Whether wifi scan throttle is enabled or not.
+ */
+ public boolean isScanThrottleEnabled() {
+ return mScanThrottleEnabled;
+ }
+
+ /**
+ * @return Whether to enable verbose logging in Wi-Fi.
+ */
+ public boolean isVerboseLoggingEnabled() {
+ return mVerboseLoggingEnabled;
+ }
+
+ /**
+ * Builder to create instance of {@link SettingsMigrationData}.
+ */
+ public static final class Builder {
+ private boolean mScanAlwaysAvailable;
+ private boolean mP2pFactoryResetPending;
+ private String mP2pDeviceName;
+ private boolean mSoftApTimeoutEnabled;
+ private boolean mWakeupEnabled;
+ private boolean mScanThrottleEnabled;
+ private boolean mVerboseLoggingEnabled;
+
+ public Builder() {
+ }
+
+ /**
+ * Setting to allow scans even when wifi is toggled off.
+ *
+ * @param available true if available, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setScanAlwaysAvailable(boolean available) {
+ mScanAlwaysAvailable = available;
+ return this;
+ }
+
+ /**
+ * Indicate whether factory reset request is pending.
+ *
+ * @param pending true if pending, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setP2pFactoryResetPending(boolean pending) {
+ mP2pFactoryResetPending = pending;
+ return this;
+ }
+
+ /**
+ * The Wi-Fi peer-to-peer device name
+ *
+ * @param name Name if set, null otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setP2pDeviceName(@Nullable String name) {
+ mP2pDeviceName = name;
+ return this;
+ }
+
+ /**
+ * Whether soft AP will shut down after a timeout period when no devices are connected.
+ *
+ * @param enabled true if enabled, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setSoftApTimeoutEnabled(boolean enabled) {
+ mSoftApTimeoutEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Value to specify if Wi-Fi Wakeup feature is enabled.
+ *
+ * @param enabled true if enabled, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setWakeUpEnabled(boolean enabled) {
+ mWakeupEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Whether wifi scan throttle is enabled or not.
+ *
+ * @param enabled true if enabled, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setScanThrottleEnabled(boolean enabled) {
+ mScanThrottleEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Setting to enable verbose logging in Wi-Fi.
+ *
+ * @param enabled true if enabled, false otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setVerboseLoggingEnabled(boolean enabled) {
+ mVerboseLoggingEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Build an instance of {@link SettingsMigrationData}.
+ *
+ * @return Instance of {@link SettingsMigrationData}.
+ */
+ public @NonNull SettingsMigrationData build() {
+ return new SettingsMigrationData(mScanAlwaysAvailable, mP2pFactoryResetPending,
+ mP2pDeviceName, mSoftApTimeoutEnabled, mWakeupEnabled, mScanThrottleEnabled,
+ mVerboseLoggingEnabled);
+ }
+ }
+ }
+
+ /**
+ * Load data from Settings.Global values.
+ *
+ * <p>
+ * Note:
+ * <li> This is method is invoked once on the first bootup. OEM can safely delete these settings
+ * once the migration is complete. The first & only relevant invocation of
+ * {@link #loadFromSettings(Context)} ()} occurs when a previously released
+ * device upgrades to the wifi apex from an OEM implementation of the wifi stack.
+ * </li>
+ *
+ * @param context Context to use for loading the settings provider.
+ * @return Instance of {@link SettingsMigrationData} for migrating data.
+ */
+ @NonNull
+ public static SettingsMigrationData loadFromSettings(@NonNull Context context) {
+ if (Settings.Global.getInt(
+ context.getContentResolver(), Settings.Global.WIFI_MIGRATION_COMPLETED, 0) == 1) {
+ // migration already complete, ignore.
+ return null;
+ }
+ SettingsMigrationData data = new SettingsMigrationData.Builder()
+ .setScanAlwaysAvailable(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1)
+ .setP2pFactoryResetPending(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET, 0) == 1)
+ .setP2pDeviceName(
+ Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.WIFI_P2P_DEVICE_NAME))
+ .setSoftApTimeoutEnabled(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1) == 1)
+ .setWakeUpEnabled(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1)
+ .setScanThrottleEnabled(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_SCAN_THROTTLE_ENABLED, 1) == 1)
+ .setVerboseLoggingEnabled(
+ Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0) == 1)
+ .build();
+ Settings.Global.putInt(
+ context.getContentResolver(), Settings.Global.WIFI_MIGRATION_COMPLETED, 1);
+ return data;
+
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
index d384298c60c4..0d13805a08d8 100644
--- a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
@@ -23,12 +23,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.MacAddress;
import android.net.MatchAllNetworkSpecifier;
-import android.net.NetworkAgent;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.TextUtils;
import java.util.Objects;
@@ -42,33 +40,10 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements
*/
private final WifiConfiguration mWifiConfiguration;
- /**
- * The UID of the app that requested a specific wifi network using {@link WifiNetworkSpecifier}.
- *
- * Will only be filled when the device connects to a wifi network as a result of a
- * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to -1 if the device
- * auto-connected to a wifi network.
- */
- private final int mOriginalRequestorUid;
-
- /**
- * The package name of the app that requested a specific wifi network using
- * {@link WifiNetworkSpecifier}.
- *
- * Will only be filled when the device connects to a wifi network as a result of a
- * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to null if the device
- * auto-connected to a wifi network.
- */
- private final String mOriginalRequestorPackageName;
-
- public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration,
- int originalRequestorUid,
- @Nullable String originalRequestorPackageName) {
+ public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration) {
checkNotNull(wifiConfiguration);
mWifiConfiguration = wifiConfiguration;
- mOriginalRequestorUid = originalRequestorUid;
- mOriginalRequestorPackageName = originalRequestorPackageName;
}
/**
@@ -79,10 +54,7 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements
@Override
public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) {
WifiConfiguration wifiConfiguration = in.readParcelable(null);
- int originalRequestorUid = in.readInt();
- String originalRequestorPackageName = in.readString();
- return new WifiNetworkAgentSpecifier(
- wifiConfiguration, originalRequestorUid, originalRequestorPackageName);
+ return new WifiNetworkAgentSpecifier(wifiConfiguration);
}
@Override
@@ -99,8 +71,6 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeParcelable(mWifiConfiguration, flags);
- dest.writeInt(mOriginalRequestorUid);
- dest.writeString(mOriginalRequestorPackageName);
}
@Override
@@ -120,7 +90,7 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements
/**
* Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the
- * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link NetworkAgent}.
+ * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link android.net.NetworkAgent}.
*/
public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) {
// None of these should be null by construction.
@@ -150,12 +120,6 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements
this.mWifiConfiguration.allowedKeyManagement)) {
return false;
}
- if (ns.requestorUid != this.mOriginalRequestorUid) {
- return false;
- }
- if (!TextUtils.equals(ns.requestorPackageName, this.mOriginalRequestorPackageName)) {
- return false;
- }
return true;
}
@@ -164,9 +128,7 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements
return Objects.hash(
mWifiConfiguration.SSID,
mWifiConfiguration.BSSID,
- mWifiConfiguration.allowedKeyManagement,
- mOriginalRequestorUid,
- mOriginalRequestorPackageName);
+ mWifiConfiguration.allowedKeyManagement);
}
@Override
@@ -181,10 +143,7 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements
return Objects.equals(this.mWifiConfiguration.SSID, lhs.mWifiConfiguration.SSID)
&& Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID)
&& Objects.equals(this.mWifiConfiguration.allowedKeyManagement,
- lhs.mWifiConfiguration.allowedKeyManagement)
- && mOriginalRequestorUid == lhs.mOriginalRequestorUid
- && TextUtils.equals(mOriginalRequestorPackageName,
- lhs.mOriginalRequestorPackageName);
+ lhs.mWifiConfiguration.allowedKeyManagement);
}
@Override
@@ -193,8 +152,6 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements
sb.append("WifiConfiguration=")
.append(", SSID=").append(mWifiConfiguration.SSID)
.append(", BSSID=").append(mWifiConfiguration.BSSID)
- .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid)
- .append(", mOriginalRequestorPackageName=").append(mOriginalRequestorPackageName)
.append("]");
return sb.toString();
}
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index 5a212a824452..378549d62edf 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.content.Context;
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
-import android.net.NetworkScoreManager;
import android.net.ScoredNetwork;
import android.os.Handler;
import android.os.Process;
@@ -30,19 +29,19 @@ import android.util.Log;
import android.util.LruCache;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
+import java.util.Objects;
/**
* {@link INetworkScoreCache} implementation for Wifi Networks.
*
+ * TODO: This should not be part of wifi mainline module.
* @hide
*/
-public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
- implements NetworkScoreManager.NetworkScoreCallback {
+public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
private static final String TAG = "WifiNetworkScoreCache";
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
@@ -248,17 +247,6 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
}
@Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- dumpWithLatestScanResults(fd, writer, args, wifiManager.getScanResults());
- }
-
- /**
- * This is directly invoked from within Wifi-Service (on it's instance of this class), hence
- * avoid making the WifiManager.getScanResults() call to avoid a deadlock.
- */
- public final void dumpWithLatestScanResults(
- FileDescriptor fd, PrintWriter writer, String[] args,
- List<ScanResult> latestScanResults) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
String header = String.format("WifiNetworkScoreCache (%s/%d)",
mContext.getPackageName(), Process.myUid());
@@ -269,7 +257,8 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
writer.println(" " + score);
}
writer.println(" Network scores for latest ScanResults:");
- for (ScanResult scanResult : latestScanResults) {
+ WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ for (ScanResult scanResult : wifiManager.getScanResults()) {
writer.println(
" " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult));
}
@@ -301,7 +290,7 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
* This cannot be null.
*/
public CacheListener(@NonNull Handler handler) {
- Preconditions.checkNotNull(handler);
+ Objects.requireNonNull(handler);
mHandler = handler;
}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index f08935af680d..b0213b0ef502 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -20,15 +20,12 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityThread;
import android.net.MacAddress;
-import android.net.MatchAllNetworkSpecifier;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PatternMatcher;
-import android.os.Process;
import android.text.TextUtils;
import android.util.Pair;
@@ -41,6 +38,7 @@ import java.util.Objects;
* {@link WifiNetworkSpecifier.Builder} class to create an instance.
*/
public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+ private static final String TAG = "WifiNetworkSpecifier";
/**
* Builder used to create {@link WifiNetworkSpecifier} objects.
@@ -49,11 +47,11 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
private static final String MATCH_ALL_SSID_PATTERN_PATH = ".*";
private static final String MATCH_EMPTY_SSID_PATTERN_PATH = "";
private static final Pair<MacAddress, MacAddress> MATCH_NO_BSSID_PATTERN1 =
- new Pair(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
+ new Pair<>(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
private static final Pair<MacAddress, MacAddress> MATCH_NO_BSSID_PATTERN2 =
- new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.BROADCAST_ADDRESS);
+ new Pair<>(WifiManager.ALL_ZEROS_MAC_ADDRESS, MacAddress.BROADCAST_ADDRESS);
private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN =
- new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ new Pair<>(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS);
private static final MacAddress MATCH_EXACT_BSSID_PATTERN_MASK =
MacAddress.BROADCAST_ADDRESS;
@@ -157,7 +155,8 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
*/
public @NonNull Builder setBssidPattern(
@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
- checkNotNull(baseAddress, mask);
+ checkNotNull(baseAddress);
+ checkNotNull(mask);
mBssidPatternMatcher = Pair.create(baseAddress, mask);
return this;
}
@@ -385,7 +384,8 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
*
* For example:
* To connect to an open network with a SSID prefix of "test" and a BSSID OUI of "10:03:23":
- * {@code
+ *
+ * <pre>{@code
* final NetworkSpecifier specifier =
* new Builder()
* .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
@@ -407,7 +407,7 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
* // etc.
* };
* connectivityManager.requestNetwork(request, networkCallback);
- * }
+ * }</pre>
*
* @return Instance of {@link NetworkSpecifier}.
* @throws IllegalStateException on invalid params set.
@@ -433,9 +433,7 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
return new WifiNetworkSpecifier(
mSsidPatternMatcher,
mBssidPatternMatcher,
- buildWifiConfiguration(),
- Process.myUid(),
- ActivityThread.currentApplication().getApplicationContext().getOpPackageName());
+ buildWifiConfiguration());
}
}
@@ -463,20 +461,6 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
*/
public final WifiConfiguration wifiConfiguration;
- /**
- * The UID of the process initializing this network specifier. Validated by receiver using
- * checkUidIfNecessary() and is used by satisfiedBy() to determine whether the specifier
- * matches the offered network.
- * @hide
- */
- public final int requestorUid;
-
- /**
- * The package name of the app initializing this network specifier.
- * @hide
- */
- public final String requestorPackageName;
-
/** @hide */
public WifiNetworkSpecifier() throws IllegalAccessException {
throw new IllegalAccessException("Use the builder to create an instance");
@@ -485,18 +469,14 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
/** @hide */
public WifiNetworkSpecifier(@NonNull PatternMatcher ssidPatternMatcher,
@NonNull Pair<MacAddress, MacAddress> bssidPatternMatcher,
- @NonNull WifiConfiguration wifiConfiguration,
- int requestorUid, @NonNull String requestorPackageName) {
+ @NonNull WifiConfiguration wifiConfiguration) {
checkNotNull(ssidPatternMatcher);
checkNotNull(bssidPatternMatcher);
checkNotNull(wifiConfiguration);
- checkNotNull(requestorPackageName);
this.ssidPatternMatcher = ssidPatternMatcher;
this.bssidPatternMatcher = bssidPatternMatcher;
this.wifiConfiguration = wifiConfiguration;
- this.requestorUid = requestorUid;
- this.requestorPackageName = requestorPackageName;
}
public static final @NonNull Creator<WifiNetworkSpecifier> CREATOR =
@@ -509,10 +489,8 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
Pair<MacAddress, MacAddress> bssidPatternMatcher =
Pair.create(baseAddress, mask);
WifiConfiguration wifiConfiguration = in.readParcelable(null);
- int requestorUid = in.readInt();
- String requestorPackageName = in.readString();
return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher,
- wifiConfiguration, requestorUid, requestorPackageName);
+ wifiConfiguration);
}
@Override
@@ -532,18 +510,13 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
dest.writeParcelable(bssidPatternMatcher.first, flags);
dest.writeParcelable(bssidPatternMatcher.second, flags);
dest.writeParcelable(wifiConfiguration, flags);
- dest.writeInt(requestorUid);
- dest.writeString(requestorPackageName);
}
@Override
public int hashCode() {
return Objects.hash(
- ssidPatternMatcher.getPath(),
- ssidPatternMatcher.getType(),
- bssidPatternMatcher,
- wifiConfiguration.allowedKeyManagement,
- requestorUid, requestorPackageName);
+ ssidPatternMatcher.getPath(), ssidPatternMatcher.getType(), bssidPatternMatcher,
+ wifiConfiguration.allowedKeyManagement);
}
@Override
@@ -562,9 +535,7 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
&& Objects.equals(this.bssidPatternMatcher,
lhs.bssidPatternMatcher)
&& Objects.equals(this.wifiConfiguration.allowedKeyManagement,
- lhs.wifiConfiguration.allowedKeyManagement)
- && requestorUid == lhs.requestorUid
- && TextUtils.equals(requestorPackageName, lhs.requestorPackageName);
+ lhs.wifiConfiguration.allowedKeyManagement);
}
@Override
@@ -575,8 +546,6 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
.append(", BSSID Match pattern=").append(bssidPatternMatcher)
.append(", SSID=").append(wifiConfiguration.SSID)
.append(", BSSID=").append(wifiConfiguration.BSSID)
- .append(", requestorUid=").append(requestorUid)
- .append(", requestorPackageName=").append(requestorPackageName)
.append("]")
.toString();
}
@@ -584,13 +553,6 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
/** @hide */
@Override
public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- if (this == other) {
- return true;
- }
- // Any generic requests should be satisifed by a specific wifi network.
- if (other == null || other instanceof MatchAllNetworkSpecifier) {
- return true;
- }
if (other instanceof WifiNetworkAgentSpecifier) {
return ((WifiNetworkAgentSpecifier) other).satisfiesNetworkSpecifier(this);
}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 426201732359..4d3a2c02c686 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -21,11 +21,13 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityThread;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.net.MacAddress;
+import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.Process;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import java.nio.charset.CharsetEncoder;
@@ -42,7 +44,6 @@ import java.util.Objects;
* {@link WifiManager#addNetworkSuggestions(List)}.
*/
public final class WifiNetworkSuggestion implements Parcelable {
-
/**
* Builder used to create {@link WifiNetworkSuggestion} objects.
*/
@@ -80,6 +81,10 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
private @Nullable WifiEnterpriseConfig mWpa3EnterpriseConfig;
/**
+ * The passpoint config for use with Hotspot 2.0 network
+ */
+ private @Nullable PasspointConfiguration mPasspointConfiguration;
+ /**
* This is a network that does not broadcast its SSID, so an
* SSID-specific probe request must be used for scans.
*/
@@ -95,13 +100,50 @@ public final class WifiNetworkSuggestion implements Parcelable {
/**
* Whether this network is metered or not.
*/
- private boolean mIsMetered;
+ private int mMeteredOverride;
/**
* Priority of this network among other network suggestions provided by the app.
* The lower the number, the higher the priority (i.e value of 0 = highest priority).
*/
private int mPriority;
+ /**
+ * The carrier ID identifies the operator who provides this network configuration.
+ * see {@link TelephonyManager#getSimCarrierId()}
+ */
+ private int mCarrierId;
+
+ /**
+ * Whether this network is shared credential with user to allow user manually connect.
+ */
+ private boolean mIsSharedWithUser;
+
+ /**
+ * Whether the setCredentialSharedWithUser have been called.
+ */
+ private boolean mIsSharedWithUserSet;
+
+ /**
+ * Whether this network is initialized with auto-join enabled (the default) or not.
+ */
+ private boolean mIsInitialAutojoinEnabled;
+
+ /**
+ * Pre-shared key for use with WAPI-PSK networks.
+ */
+ private @Nullable String mWapiPskPassphrase;
+
+ /**
+ * The enterprise configuration details specifying the EAP method,
+ * certificates and other settings associated with the WAPI networks.
+ */
+ private @Nullable WifiEnterpriseConfig mWapiEnterpriseConfig;
+
+ /**
+ * Whether this network will be brought up as untrusted (TRUSTED capability bit removed).
+ */
+ private boolean mIsNetworkUntrusted;
+
public Builder() {
mSsid = null;
mBssid = null;
@@ -110,11 +152,19 @@ public final class WifiNetworkSuggestion implements Parcelable {
mWpa3SaePassphrase = null;
mWpa2EnterpriseConfig = null;
mWpa3EnterpriseConfig = null;
+ mPasspointConfiguration = null;
mIsHiddenSSID = false;
mIsAppInteractionRequired = false;
mIsUserInteractionRequired = false;
- mIsMetered = false;
+ mMeteredOverride = WifiConfiguration.METERED_OVERRIDE_NONE;
+ mIsSharedWithUser = true;
+ mIsSharedWithUserSet = false;
+ mIsInitialAutojoinEnabled = true;
mPriority = UNASSIGNED_PRIORITY;
+ mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
+ mWapiPskPassphrase = null;
+ mWapiEnterpriseConfig = null;
+ mIsNetworkUntrusted = false;
}
/**
@@ -207,33 +257,111 @@ public final class WifiNetworkSuggestion implements Parcelable {
/**
* Set the associated enterprise configuration for this network. Needed for authenticating
- * to WPA2-EAP networks. See {@link WifiEnterpriseConfig} for description.
+ * to WPA2 enterprise networks. See {@link WifiEnterpriseConfig} for description.
*
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
* @return Instance of {@link Builder} to enable chaining of the builder method.
+ * @throws IllegalArgumentException if configuration CA certificate or
+ * AltSubjectMatch/DomainSuffixMatch is not set.
*/
public @NonNull Builder setWpa2EnterpriseConfig(
@NonNull WifiEnterpriseConfig enterpriseConfig) {
checkNotNull(enterpriseConfig);
+ if (enterpriseConfig.isInsecure()) {
+ throw new IllegalArgumentException("Enterprise configuration is insecure");
+ }
mWpa2EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
return this;
}
/**
* Set the associated enterprise configuration for this network. Needed for authenticating
- * to WPA3-SuiteB networks. See {@link WifiEnterpriseConfig} for description.
+ * to WPA3 enterprise networks. See {@link WifiEnterpriseConfig} for description.
*
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
* @return Instance of {@link Builder} to enable chaining of the builder method.
+ * @throws IllegalArgumentException if configuration CA certificate or
+ * AltSubjectMatch/DomainSuffixMatch is not set.
*/
public @NonNull Builder setWpa3EnterpriseConfig(
@NonNull WifiEnterpriseConfig enterpriseConfig) {
checkNotNull(enterpriseConfig);
+ if (enterpriseConfig.isInsecure()) {
+ throw new IllegalArgumentException("Enterprise configuration is insecure");
+ }
mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
return this;
}
/**
+ * Set the associated Passpoint configuration for this network. Needed for authenticating
+ * to Hotspot 2.0 networks. See {@link PasspointConfiguration} for description.
+ *
+ * @param passpointConfig Instance of {@link PasspointConfiguration}.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ * @throws IllegalArgumentException if passpoint configuration is invalid.
+ */
+ public @NonNull Builder setPasspointConfig(
+ @NonNull PasspointConfiguration passpointConfig) {
+ checkNotNull(passpointConfig);
+ if (!passpointConfig.validate()) {
+ throw new IllegalArgumentException("Passpoint configuration is invalid");
+ }
+ mPasspointConfiguration = passpointConfig;
+ return this;
+ }
+
+ /**
+ * Set the carrier ID of the network operator. The carrier ID associates a Suggested
+ * network with a specific carrier (and therefore SIM). The carrier ID must be provided
+ * for any network which uses the SIM-based authentication: e.g. EAP-SIM, EAP-AKA,
+ * EAP-AKA', and EAP-PEAP with SIM-based phase 2 authentication.
+ * @param carrierId see {@link TelephonyManager#getSimCarrierId()}.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
+ public @NonNull Builder setCarrierId(int carrierId) {
+ mCarrierId = carrierId;
+ return this;
+ }
+
+ /**
+ * Set the ASCII WAPI passphrase for this network. Needed for authenticating to
+ * WAPI-PSK networks.
+ *
+ * @param passphrase passphrase of the network.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ * @throws IllegalArgumentException if the passphrase is not ASCII encodable.
+ *
+ */
+ public @NonNull Builder setWapiPassphrase(@NonNull String passphrase) {
+ checkNotNull(passphrase);
+ final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+ if (!asciiEncoder.canEncode(passphrase)) {
+ throw new IllegalArgumentException("passphrase not ASCII encodable");
+ }
+ mWapiPskPassphrase = passphrase;
+ return this;
+ }
+
+ /**
+ * Set the associated enterprise configuration for this network. Needed for authenticating
+ * to WAPI-CERT networks. See {@link WifiEnterpriseConfig} for description.
+ *
+ * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setWapiEnterpriseConfig(
+ @NonNull WifiEnterpriseConfig enterpriseConfig) {
+ checkNotNull(enterpriseConfig);
+ mWapiEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+ return this;
+ }
+
+ /**
* Specifies whether this represents a hidden network.
* <p>
* <li>If not set, defaults to false (i.e not a hidden network).</li>
@@ -303,14 +431,81 @@ public final class WifiNetworkSuggestion implements Parcelable {
/**
* Specifies whether this network is metered.
* <p>
- * <li>If not set, defaults to false (i.e not metered).</li>
+ * <li>If not set, defaults to detect automatically.</li>
*
* @param isMetered {@code true} to indicate that the network is metered, {@code false}
- * otherwise.
+ * for not metered.
* @return Instance of {@link Builder} to enable chaining of the builder method.
*/
public @NonNull Builder setIsMetered(boolean isMetered) {
- mIsMetered = isMetered;
+ if (isMetered) {
+ mMeteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED;
+ } else {
+ mMeteredOverride = WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ }
+ return this;
+ }
+
+ /**
+ * Specifies whether the network credentials provided with this suggestion can be used by
+ * the user to explicitly (manually) connect to this network. If true this network will
+ * appear in the Wi-Fi Picker (in Settings) and the user will be able to select and connect
+ * to it with the provided credentials. If false, the user will need to enter network
+ * credentials and the resulting configuration will become a user saved network.
+ * <p>
+ * <li>Note: Only valid for secure (non-open) networks.
+ * <li>If not set, defaults to true (i.e. allow user to manually connect) for secure
+ * networks and false for open networks.</li>
+ *
+ * @param isShared {@code true} to indicate that the credentials may be used by the user to
+ * manually connect to the network, {@code false} otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setCredentialSharedWithUser(boolean isShared) {
+ mIsSharedWithUser = isShared;
+ mIsSharedWithUserSet = true;
+ return this;
+ }
+
+ /**
+ * Specifies whether the suggestion is created with auto-join enabled or disabled. The
+ * user may modify the auto-join configuration of a suggestion directly once the device
+ * associates to the network.
+ * <p>
+ * If auto-join is initialized as disabled the user may still be able to manually connect
+ * to the network. Therefore, disabling auto-join only makes sense if
+ * {@link #setCredentialSharedWithUser(boolean)} is set to true (the default) which
+ * itself implies a secure (non-open) network.
+ * <p>
+ * If not set, defaults to true (i.e. auto-join is initialized as enabled).
+ *
+ * @param enabled true for initializing with auto-join enabled (the default), false to
+ * initializing with auto-join disabled.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setIsInitialAutojoinEnabled(boolean enabled) {
+ mIsInitialAutojoinEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Specifies whether the system will bring up the network (if selected) as untrusted. An
+ * untrusted network has its {@link android.net.NetworkCapabilities#NET_CAPABILITY_TRUSTED}
+ * capability removed. The Wi-Fi network selection process may use this information to
+ * influence priority of the suggested network for Wi-Fi network selection (most likely to
+ * reduce it). The connectivity service may use this information to influence the overall
+ * network configuration of the device.
+ * <p>
+ * <li> An untrusted network's credentials may not be shared with the user using
+ * {@link #setCredentialSharedWithUser(boolean)}.</li>
+ * <li> If not set, defaults to false (i.e. network is trusted).</li>
+ *
+ * @param isUntrusted Boolean indicating whether the network should be brought up untrusted
+ * (if true) or trusted (if false).
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setUntrusted(boolean isUntrusted) {
+ mIsNetworkUntrusted = isUntrusted;
return this;
}
@@ -332,6 +527,13 @@ public final class WifiNetworkSuggestion implements Parcelable {
configuration.enterpriseConfig = mWpa3EnterpriseConfig;
} else if (mIsEnhancedOpen) { // OWE network
configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE);
+ } else if (!TextUtils.isEmpty(mWapiPskPassphrase)) { // WAPI-PSK network.
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WAPI_PSK);
+ // WifiConfiguration.preSharedKey needs quotes around ASCII password.
+ configuration.preSharedKey = "\"" + mWapiPskPassphrase + "\"";
+ } else if (mWapiEnterpriseConfig != null) { // WAPI-CERT network
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WAPI_CERT);
+ configuration.enterpriseConfig = mWapiEnterpriseConfig;
} else { // Open network
configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
}
@@ -353,9 +555,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
wifiConfiguration.hiddenSSID = mIsHiddenSSID;
wifiConfiguration.priority = mPriority;
- wifiConfiguration.meteredOverride =
- mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
- : WifiConfiguration.METERED_OVERRIDE_NONE;
+ wifiConfiguration.meteredOverride = mMeteredOverride;
+ wifiConfiguration.carrierId = mCarrierId;
+ wifiConfiguration.trusted = !mIsNetworkUntrusted;
return wifiConfiguration;
}
@@ -364,15 +566,31 @@ public final class WifiNetworkSuggestion implements Parcelable {
numSecurityTypes += mIsEnhancedOpen ? 1 : 0;
numSecurityTypes += !TextUtils.isEmpty(mWpa2PskPassphrase) ? 1 : 0;
numSecurityTypes += !TextUtils.isEmpty(mWpa3SaePassphrase) ? 1 : 0;
+ numSecurityTypes += !TextUtils.isEmpty(mWapiPskPassphrase) ? 1 : 0;
numSecurityTypes += mWpa2EnterpriseConfig != null ? 1 : 0;
numSecurityTypes += mWpa3EnterpriseConfig != null ? 1 : 0;
+ numSecurityTypes += mWapiEnterpriseConfig != null ? 1 : 0;
+ numSecurityTypes += mPasspointConfiguration != null ? 1 : 0;
if (numSecurityTypes > 1) {
throw new IllegalStateException("only one of setIsEnhancedOpen, setWpa2Passphrase,"
- + "setWpa3Passphrase, setWpa2EnterpriseConfig or setWpa3EnterpriseConfig"
- + " can be invoked for network specifier");
+ + " setWpa3Passphrase, setWpa2EnterpriseConfig, setWpa3EnterpriseConfig"
+ + " setWapiPassphrase, setWapiCertSuite, setIsWapiCertSuiteAuto"
+ + " or setPasspointConfig can be invoked for network suggestion");
}
}
+ private WifiConfiguration buildWifiConfigurationForPasspoint() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.FQDN = mPasspointConfiguration.getHomeSp().getFqdn();
+ wifiConfiguration.setPasspointUniqueId(mPasspointConfiguration.getUniqueId());
+ wifiConfiguration.priority = mPriority;
+ wifiConfiguration.meteredOverride = mMeteredOverride;
+ wifiConfiguration.trusted = !mIsNetworkUntrusted;
+ mPasspointConfiguration.setCarrierId(mCarrierId);
+ mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride);
+ return wifiConfiguration;
+ }
+
/**
* Create a network suggestion object for use in
* {@link WifiManager#addNetworkSuggestions(List)}.
@@ -384,29 +602,36 @@ public final class WifiNetworkSuggestion implements Parcelable {
* </p>
*
* For example:
- * To provide credentials for one open, one WPA2 and one WPA3 network with their
- * corresponding SSID's:
+ * To provide credentials for one open, one WPA2, one WPA3 network with their
+ * corresponding SSID's and one with Passpoint config:
*
* <pre>{@code
* final WifiNetworkSuggestion suggestion1 =
* new Builder()
* .setSsid("test111111")
- * .build()
+ * .build();
* final WifiNetworkSuggestion suggestion2 =
* new Builder()
* .setSsid("test222222")
* .setWpa2Passphrase("test123456")
- * .build()
+ * .build();
* final WifiNetworkSuggestion suggestion3 =
* new Builder()
* .setSsid("test333333")
* .setWpa3Passphrase("test6789")
- * .build()
+ * .build();
+ * final PasspointConfiguration passpointConfig= new PasspointConfiguration();
+ * // configure passpointConfig to include a valid Passpoint configuration
+ * final WifiNetworkSuggestion suggestion4 =
+ * new Builder()
+ * .setPasspointConfig(passpointConfig)
+ * .build();
* final List<WifiNetworkSuggestion> suggestionsList =
* new ArrayList<WifiNetworkSuggestion> { {
* add(suggestion1);
* add(suggestion2);
* add(suggestion3);
+ * add(suggestion4);
* } };
* final WifiManager wifiManager =
* context.getSystemService(Context.WIFI_SERVICE);
@@ -419,25 +644,59 @@ public final class WifiNetworkSuggestion implements Parcelable {
* @see WifiNetworkSuggestion
*/
public @NonNull WifiNetworkSuggestion build() {
- if (mSsid == null) {
- throw new IllegalStateException("setSsid should be invoked for suggestion");
+ validateSecurityParams();
+ WifiConfiguration wifiConfiguration;
+ if (mPasspointConfiguration != null) {
+ if (mSsid != null) {
+ throw new IllegalStateException("setSsid should not be invoked for suggestion "
+ + "with Passpoint configuration");
+ }
+ if (mIsHiddenSSID) {
+ throw new IllegalStateException("setIsHiddenSsid should not be invoked for "
+ + "suggestion with Passpoint configuration");
+ }
+ wifiConfiguration = buildWifiConfigurationForPasspoint();
+ } else {
+ if (mSsid == null) {
+ throw new IllegalStateException("setSsid should be invoked for suggestion");
+ }
+ if (TextUtils.isEmpty(mSsid)) {
+ throw new IllegalStateException("invalid ssid for suggestion");
+ }
+ if (mBssid != null
+ && (mBssid.equals(MacAddress.BROADCAST_ADDRESS)
+ || mBssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS))) {
+ throw new IllegalStateException("invalid bssid for suggestion");
+ }
+ wifiConfiguration = buildWifiConfiguration();
+ if (wifiConfiguration.isOpenNetwork()) {
+ if (mIsSharedWithUserSet && mIsSharedWithUser) {
+ throw new IllegalStateException("Open network should not be "
+ + "setCredentialSharedWithUser to true");
+ }
+ mIsSharedWithUser = false;
+ }
}
- if (TextUtils.isEmpty(mSsid)) {
- throw new IllegalStateException("invalid ssid for suggestion");
+ if (!mIsSharedWithUser && !mIsInitialAutojoinEnabled) {
+ throw new IllegalStateException("Should have not a network with both "
+ + "setCredentialSharedWithUser and "
+ + "setIsAutojoinEnabled set to false");
}
- if (mBssid != null
- && (mBssid.equals(MacAddress.BROADCAST_ADDRESS)
- || mBssid.equals(MacAddress.ALL_ZEROS_ADDRESS))) {
- throw new IllegalStateException("invalid bssid for suggestion");
+ if (mIsNetworkUntrusted) {
+ if (mIsSharedWithUserSet && mIsSharedWithUser) {
+ throw new IllegalStateException("Should not be both"
+ + "setCredentialSharedWithUser and +"
+ + "setIsNetworkAsUntrusted to true");
+ }
+ mIsSharedWithUser = false;
}
- validateSecurityParams();
-
return new WifiNetworkSuggestion(
- buildWifiConfiguration(),
+ wifiConfiguration,
+ mPasspointConfiguration,
mIsAppInteractionRequired,
mIsUserInteractionRequired,
- Process.myUid(),
- ActivityThread.currentApplication().getApplicationContext().getOpPackageName());
+ mIsSharedWithUser,
+ mIsInitialAutojoinEnabled);
}
}
@@ -445,9 +704,17 @@ public final class WifiNetworkSuggestion implements Parcelable {
* Network configuration for the provided network.
* @hide
*/
+ @NonNull
public final WifiConfiguration wifiConfiguration;
/**
+ * Passpoint configuration for the provided network.
+ * @hide
+ */
+ @Nullable
+ public final PasspointConfiguration passpointConfiguration;
+
+ /**
* Whether app needs to log in to captive portal to obtain Internet access.
* @hide
*/
@@ -460,39 +727,43 @@ public final class WifiNetworkSuggestion implements Parcelable {
public final boolean isUserInteractionRequired;
/**
- * The UID of the process initializing this network suggestion.
+ * Whether app share credential with the user, allow user use provided credential to
+ * connect network manually.
* @hide
*/
- public final int suggestorUid;
+ public final boolean isUserAllowedToManuallyConnect;
/**
- * The package name of the process initializing this network suggestion.
+ * Whether the suggestion will be initialized as auto-joined or not.
* @hide
*/
- public final String suggestorPackageName;
+ public final boolean isInitialAutoJoinEnabled;
/** @hide */
public WifiNetworkSuggestion() {
- this.wifiConfiguration = null;
+ this.wifiConfiguration = new WifiConfiguration();
+ this.passpointConfiguration = null;
this.isAppInteractionRequired = false;
this.isUserInteractionRequired = false;
- this.suggestorUid = -1;
- this.suggestorPackageName = null;
+ this.isUserAllowedToManuallyConnect = true;
+ this.isInitialAutoJoinEnabled = true;
}
/** @hide */
- public WifiNetworkSuggestion(@NonNull WifiConfiguration wifiConfiguration,
+ public WifiNetworkSuggestion(@NonNull WifiConfiguration networkConfiguration,
+ @Nullable PasspointConfiguration passpointConfiguration,
boolean isAppInteractionRequired,
boolean isUserInteractionRequired,
- int suggestorUid, @NonNull String suggestorPackageName) {
- checkNotNull(wifiConfiguration);
- checkNotNull(suggestorPackageName);
+ boolean isUserAllowedToManuallyConnect,
+ boolean isInitialAutoJoinEnabled) {
+ checkNotNull(networkConfiguration);
+ this.wifiConfiguration = networkConfiguration;
+ this.passpointConfiguration = passpointConfiguration;
- this.wifiConfiguration = wifiConfiguration;
this.isAppInteractionRequired = isAppInteractionRequired;
this.isUserInteractionRequired = isUserInteractionRequired;
- this.suggestorUid = suggestorUid;
- this.suggestorPackageName = suggestorPackageName;
+ this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
+ this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled;
}
public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
@@ -501,10 +772,11 @@ public final class WifiNetworkSuggestion implements Parcelable {
public WifiNetworkSuggestion createFromParcel(Parcel in) {
return new WifiNetworkSuggestion(
in.readParcelable(null), // wifiConfiguration
+ in.readParcelable(null), // PasspointConfiguration
in.readBoolean(), // isAppInteractionRequired
in.readBoolean(), // isUserInteractionRequired
- in.readInt(), // suggestorUid
- in.readString() // suggestorPackageName
+ in.readBoolean(), // isSharedCredentialWithUser
+ in.readBoolean() // isAutojoinEnabled
);
}
@@ -522,16 +794,17 @@ public final class WifiNetworkSuggestion implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(wifiConfiguration, flags);
+ dest.writeParcelable(passpointConfiguration, flags);
dest.writeBoolean(isAppInteractionRequired);
dest.writeBoolean(isUserInteractionRequired);
- dest.writeInt(suggestorUid);
- dest.writeString(suggestorPackageName);
+ dest.writeBoolean(isUserAllowedToManuallyConnect);
+ dest.writeBoolean(isInitialAutoJoinEnabled);
}
@Override
public int hashCode() {
return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID,
- wifiConfiguration.allowedKeyManagement, suggestorUid, suggestorPackageName);
+ wifiConfiguration.allowedKeyManagement, wifiConfiguration.getKey());
}
/**
@@ -546,24 +819,144 @@ public final class WifiNetworkSuggestion implements Parcelable {
return false;
}
WifiNetworkSuggestion lhs = (WifiNetworkSuggestion) obj;
- return Objects.equals(this.wifiConfiguration.SSID, lhs.wifiConfiguration.SSID)
- && Objects.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID)
+ if (this.passpointConfiguration == null ^ lhs.passpointConfiguration == null) {
+ return false;
+ }
+
+ return TextUtils.equals(this.wifiConfiguration.SSID, lhs.wifiConfiguration.SSID)
+ && TextUtils.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID)
&& Objects.equals(this.wifiConfiguration.allowedKeyManagement,
- lhs.wifiConfiguration.allowedKeyManagement)
- && suggestorUid == lhs.suggestorUid
- && TextUtils.equals(suggestorPackageName, lhs.suggestorPackageName);
+ lhs.wifiConfiguration.allowedKeyManagement)
+ && TextUtils.equals(this.wifiConfiguration.getKey(),
+ lhs.wifiConfiguration.getKey());
}
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [")
- .append(", SSID=").append(wifiConfiguration.SSID)
+ StringBuilder sb = new StringBuilder("WifiNetworkSuggestion[ ")
+ .append("SSID=").append(wifiConfiguration.SSID)
.append(", BSSID=").append(wifiConfiguration.BSSID)
+ .append(", FQDN=").append(wifiConfiguration.FQDN)
.append(", isAppInteractionRequired=").append(isAppInteractionRequired)
.append(", isUserInteractionRequired=").append(isUserInteractionRequired)
- .append(", suggestorUid=").append(suggestorUid)
- .append(", suggestorPackageName=").append(suggestorPackageName)
- .append("]");
+ .append(", isCredentialSharedWithUser=").append(isUserAllowedToManuallyConnect)
+ .append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
+ .append(", isUnTrusted=").append(!wifiConfiguration.trusted)
+ .append(" ]");
return sb.toString();
}
+
+ /**
+ * Get the {@link WifiConfiguration} associated with this Suggestion.
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public WifiConfiguration getWifiConfiguration() {
+ return wifiConfiguration;
+ }
+
+ /**
+ * Get the BSSID, or null if unset.
+ * @see Builder#setBssid(MacAddress)
+ */
+ @Nullable
+ public MacAddress getBssid() {
+ if (wifiConfiguration.BSSID == null) {
+ return null;
+ }
+ return MacAddress.fromString(wifiConfiguration.BSSID);
+ }
+
+ /** @see Builder#setCredentialSharedWithUser(boolean) */
+ public boolean isCredentialSharedWithUser() {
+ return isUserAllowedToManuallyConnect;
+ }
+
+ /** @see Builder#setIsAppInteractionRequired(boolean) */
+ public boolean isAppInteractionRequired() {
+ return isAppInteractionRequired;
+ }
+
+ /** @see Builder#setIsEnhancedOpen(boolean) */
+ public boolean isEnhancedOpen() {
+ return wifiConfiguration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE);
+ }
+
+ /** @see Builder#setIsHiddenSsid(boolean) */
+ public boolean isHiddenSsid() {
+ return wifiConfiguration.hiddenSSID;
+ }
+
+ /** @see Builder#setIsInitialAutojoinEnabled(boolean) */
+ public boolean isInitialAutojoinEnabled() {
+ return isInitialAutoJoinEnabled;
+ }
+
+ /** @see Builder#setIsMetered(boolean) */
+ public boolean isMetered() {
+ return wifiConfiguration.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED;
+ }
+
+ /** @see Builder#setIsUserInteractionRequired(boolean) */
+ public boolean isUserInteractionRequired() {
+ return isUserInteractionRequired;
+ }
+
+ /**
+ * Get the {@link PasspointConfiguration} associated with this Suggestion, or null if this
+ * Suggestion is not for a Passpoint network.
+ */
+ @Nullable
+ public PasspointConfiguration getPasspointConfig() {
+ return passpointConfiguration;
+ }
+
+ /** @see Builder#setPriority(int) */
+ @IntRange(from = 0)
+ public int getPriority() {
+ return wifiConfiguration.priority;
+ }
+
+ /**
+ * Return the SSID of the network, or null if this is a Passpoint network.
+ * @see Builder#setSsid(String)
+ */
+ @Nullable
+ public String getSsid() {
+ if (wifiConfiguration.SSID == null) {
+ return null;
+ }
+ return WifiInfo.sanitizeSsid(wifiConfiguration.SSID);
+ }
+
+ /** @see Builder#setUntrusted(boolean) */
+ public boolean isUntrusted() {
+ return !wifiConfiguration.trusted;
+ }
+
+ /**
+ * Get the WifiEnterpriseConfig, or null if unset.
+ * @see Builder#setWapiEnterpriseConfig(WifiEnterpriseConfig)
+ * @see Builder#setWpa2EnterpriseConfig(WifiEnterpriseConfig)
+ * @see Builder#setWpa3EnterpriseConfig(WifiEnterpriseConfig)
+ */
+ @Nullable
+ public WifiEnterpriseConfig getEnterpriseConfig() {
+ return wifiConfiguration.enterpriseConfig;
+ }
+
+ /**
+ * Get the passphrase, or null if unset.
+ * @see Builder#setWapiPassphrase(String)
+ * @see Builder#setWpa2Passphrase(String)
+ * @see Builder#setWpa3Passphrase(String)
+ */
+ @Nullable
+ public String getPassphrase() {
+ if (wifiConfiguration.preSharedKey == null) {
+ return null;
+ }
+ return WifiInfo.removeDoubleQuotes(wifiConfiguration.preSharedKey);
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 66dc992d6dc7..94771ac4ad78 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -17,11 +17,16 @@
package android.net.wifi;
import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -31,16 +36,20 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.WorkSource;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* This class provides a way to scan the Wifi universe around the device
@@ -50,26 +59,87 @@ import java.util.List;
@SystemService(Context.WIFI_SCANNING_SERVICE)
public class WifiScanner {
- /** no band specified; use channel list instead */
- public static final int WIFI_BAND_UNSPECIFIED = 0; /* not specified */
+ /** @hide */
+ public static final int WIFI_BAND_INDEX_24_GHZ = 0;
+ /** @hide */
+ public static final int WIFI_BAND_INDEX_5_GHZ = 1;
+ /** @hide */
+ public static final int WIFI_BAND_INDEX_5_GHZ_DFS_ONLY = 2;
+ /** @hide */
+ public static final int WIFI_BAND_INDEX_6_GHZ = 3;
+ /** @hide */
+ public static final int WIFI_BAND_COUNT = 4;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"WIFI_BAND_INDEX_"}, value = {
+ WIFI_BAND_INDEX_24_GHZ,
+ WIFI_BAND_INDEX_5_GHZ,
+ WIFI_BAND_INDEX_5_GHZ_DFS_ONLY,
+ WIFI_BAND_INDEX_6_GHZ})
+ public @interface WifiBandIndex {}
+ /** no band specified; use channel list instead */
+ public static final int WIFI_BAND_UNSPECIFIED = 0;
/** 2.4 GHz band */
- public static final int WIFI_BAND_24_GHZ = 1; /* 2.4 GHz band */
+ public static final int WIFI_BAND_24_GHZ = 1 << WIFI_BAND_INDEX_24_GHZ;
/** 5 GHz band excluding DFS channels */
- public static final int WIFI_BAND_5_GHZ = 2; /* 5 GHz band without DFS channels */
+ public static final int WIFI_BAND_5_GHZ = 1 << WIFI_BAND_INDEX_5_GHZ;
/** DFS channels from 5 GHz band only */
- public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; /* 5 GHz band with DFS channels */
- /** 5 GHz band including DFS channels */
- public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; /* 5 GHz band with DFS channels */
+ public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 1 << WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;
+ /** 6 GHz band */
+ public static final int WIFI_BAND_6_GHZ = 1 << WIFI_BAND_INDEX_6_GHZ;
+
+ /**
+ * Combination of bands
+ * Note that those are only the common band combinations,
+ * other combinations can be created by combining any of the basic bands above
+ */
/** Both 2.4 GHz band and 5 GHz band; no DFS channels */
- public static final int WIFI_BAND_BOTH = 3; /* both bands without DFS channels */
+ public static final int WIFI_BAND_BOTH = WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ;
+ /**
+ * 2.4Ghz band + DFS channels from 5 GHz band only
+ * @hide
+ */
+ public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS =
+ WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+ /** 5 GHz band including DFS channels */
+ public static final int WIFI_BAND_5_GHZ_WITH_DFS = WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
/** Both 2.4 GHz band and 5 GHz band; with DFS channels */
- public static final int WIFI_BAND_BOTH_WITH_DFS = 7; /* both bands with DFS channels */
+ public static final int WIFI_BAND_BOTH_WITH_DFS =
+ WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+ /** 2.4 GHz band and 5 GHz band (no DFS channels) and 6 GHz */
+ public static final int WIFI_BAND_24_5_6_GHZ = WIFI_BAND_BOTH | WIFI_BAND_6_GHZ;
+ /** 2.4 GHz band and 5 GHz band; with DFS channels and 6 GHz */
+ public static final int WIFI_BAND_24_5_WITH_DFS_6_GHZ =
+ WIFI_BAND_BOTH_WITH_DFS | WIFI_BAND_6_GHZ;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"WIFI_BAND_"}, value = {
+ WIFI_BAND_UNSPECIFIED,
+ WIFI_BAND_24_GHZ,
+ WIFI_BAND_5_GHZ,
+ WIFI_BAND_BOTH,
+ WIFI_BAND_5_GHZ_DFS_ONLY,
+ WIFI_BAND_24_GHZ_WITH_5GHZ_DFS,
+ WIFI_BAND_5_GHZ_WITH_DFS,
+ WIFI_BAND_BOTH_WITH_DFS,
+ WIFI_BAND_6_GHZ,
+ WIFI_BAND_24_5_6_GHZ,
+ WIFI_BAND_24_5_WITH_DFS_6_GHZ})
+ public @interface WifiBand {}
+
+ /**
+ * All bands
+ * @hide
+ */
+ public static final int WIFI_BAND_ALL = (1 << WIFI_BAND_COUNT) - 1;
/** Minimum supported scanning period */
- public static final int MIN_SCAN_PERIOD_MS = 1000; /* minimum supported period */
+ public static final int MIN_SCAN_PERIOD_MS = 1000;
/** Maximum supported scanning period */
- public static final int MAX_SCAN_PERIOD_MS = 1024000; /* maximum supported period */
+ public static final int MAX_SCAN_PERIOD_MS = 1024000;
/** No Error */
public static final int REASON_SUCCEEDED = 0;
@@ -98,16 +168,41 @@ public class WifiScanner {
}
/**
- * gives you all the possible channels; channel is specified as an
- * integer with frequency in MHz i.e. channel 1 is 2412
+ * Test if scan is a full scan. i.e. scanning all available bands.
+ * For backward compatibility, since some apps don't include 6GHz in their requests yet,
+ * lacking 6GHz band does not cause the result to be false.
+ *
+ * @param bandScanned bands that are fully scanned
+ * @param excludeDfs when true, DFS band is excluded from the check
+ * @return true if all bands are scanned, false otherwise
+ *
* @hide
*/
+ public static boolean isFullBandScan(@WifiBand int bandScanned, boolean excludeDfs) {
+ return (bandScanned | WIFI_BAND_6_GHZ | (excludeDfs ? WIFI_BAND_5_GHZ_DFS_ONLY : 0))
+ == WIFI_BAND_ALL;
+ }
+
+ /**
+ * Returns a list of all the possible channels for the given band(s).
+ *
+ * @param band one of the WifiScanner#WIFI_BAND_* constants, e.g. {@link #WIFI_BAND_24_GHZ}
+ * @return a list of all the frequencies, in MHz, for the given band(s) e.g. channel 1 is
+ * 2412, or null if an error occurred.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public List<Integer> getAvailableChannels(int band) {
try {
- Bundle bundle = mService.getAvailableChannels(band);
- return bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA);
+ Bundle bundle = mService.getAvailableChannels(band, mContext.getOpPackageName(),
+ mContext.getAttributionTag());
+ List<Integer> channels = bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA);
+ return channels == null ? new ArrayList<>() : channels;
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -162,23 +257,20 @@ public class WifiScanner {
public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
/**
- * This is used to indicate the purpose of the scan to the wifi chip in
- * {@link ScanSettings#type}.
- * On devices with multiple hardware radio chains (and hence different modes of scan),
- * this type serves as an indication to the hardware on what mode of scan to perform.
- * Only apps holding android.Manifest.permission.NETWORK_STACK permission can set this value.
- *
- * Note: This serves as an intent and not as a stipulation, the wifi chip
- * might honor or ignore the indication based on the current radio conditions. Always
- * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration used
- * to receive the corresponding scan result.
+ * Optimize the scan for lower latency.
+ * @see ScanSettings#type
*/
- /** {@hide} */
- public static final int TYPE_LOW_LATENCY = 0;
- /** {@hide} */
- public static final int TYPE_LOW_POWER = 1;
- /** {@hide} */
- public static final int TYPE_HIGH_ACCURACY = 2;
+ public static final int SCAN_TYPE_LOW_LATENCY = 0;
+ /**
+ * Optimize the scan for lower power usage.
+ * @see ScanSettings#type
+ */
+ public static final int SCAN_TYPE_LOW_POWER = 1;
+ /**
+ * Optimize the scan for higher accuracy.
+ * @see ScanSettings#type
+ */
+ public static final int SCAN_TYPE_HIGH_ACCURACY = 2;
/** {@hide} */
public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
@@ -186,23 +278,21 @@ public class WifiScanner {
public static final String SCAN_PARAMS_WORK_SOURCE_KEY = "WorkSource";
/** {@hide} */
public static final String REQUEST_PACKAGE_NAME_KEY = "PackageName";
+ /** {@hide} */
+ public static final String REQUEST_FEATURE_ID_KEY = "FeatureId";
/**
* scan configuration parameters to be sent to {@link #startBackgroundScan}
*/
public static class ScanSettings implements Parcelable {
- /**
- * Hidden network to be scanned for.
- * {@hide}
- */
+ /** Hidden network to be scanned for. */
public static class HiddenNetwork {
/** SSID of the network */
- public String ssid;
+ @NonNull
+ public final String ssid;
- /**
- * Default constructor for HiddenNetwork.
- */
- public HiddenNetwork(String ssid) {
+ /** Default constructor for HiddenNetwork. */
+ public HiddenNetwork(@NonNull String ssid) {
this.ssid = ssid;
}
}
@@ -212,34 +302,64 @@ public class WifiScanner {
/** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
public ChannelSpec[] channels;
/**
- * list of hidden networks to scan for. Explicit probe requests are sent out for such
+ * List of hidden networks to scan for. Explicit probe requests are sent out for such
* networks during scan. Only valid for single scan requests.
- * {@hide}
*/
+ @NonNull
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public HiddenNetwork[] hiddenNetworks;
- /** period of background scan; in millisecond, 0 => single shot scan */
+ public final List<HiddenNetwork> hiddenNetworks = new ArrayList<>();
+ /**
+ * period of background scan; in millisecond, 0 => single shot scan
+ * @deprecated Background scan support has always been hardware vendor dependent. This
+ * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
+ * ScanListener)} instead for single scans.
+ */
+ @Deprecated
public int periodInMs;
- /** must have a valid REPORT_EVENT value */
+ /**
+ * must have a valid REPORT_EVENT value
+ * @deprecated Background scan support has always been hardware vendor dependent. This
+ * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
+ * ScanListener)} instead for single scans.
+ */
+ @Deprecated
public int reportEvents;
- /** defines number of bssids to cache from each scan */
+ /**
+ * defines number of bssids to cache from each scan
+ * @deprecated Background scan support has always been hardware vendor dependent. This
+ * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
+ * ScanListener)} instead for single scans.
+ */
+ @Deprecated
public int numBssidsPerScan;
/**
* defines number of scans to cache; use it with REPORT_EVENT_AFTER_BUFFER_FULL
* to wake up at fixed interval
+ * @deprecated Background scan support has always been hardware vendor dependent. This
+ * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
+ * ScanListener)} instead for single scans.
*/
+ @Deprecated
public int maxScansToCache;
/**
* if maxPeriodInMs is non zero or different than period, then this bucket is
* a truncated binary exponential backoff bucket and the scan period will grow
* exponentially as per formula: actual_period(N) = period * (2 ^ (N/stepCount))
* to maxPeriodInMs
+ * @deprecated Background scan support has always been hardware vendor dependent. This
+ * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
+ * ScanListener)} instead for single scans.
*/
+ @Deprecated
public int maxPeriodInMs;
/**
* for truncated binary exponential back off bucket, number of scans to perform
* for a given period
+ * @deprecated Background scan support has always been hardware vendor dependent. This
+ * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
+ * ScanListener)} instead for single scans.
*/
+ @Deprecated
public int stepCount;
/**
* Flag to indicate if the scan settings are targeted for PNO scan.
@@ -248,11 +368,24 @@ public class WifiScanner {
public boolean isPnoScan;
/**
* Indicate the type of scan to be performed by the wifi chip.
- * Default value: {@link #TYPE_LOW_LATENCY}.
- * {@hide}
+ *
+ * On devices with multiple hardware radio chains (and hence different modes of scan),
+ * this type serves as an indication to the hardware on what mode of scan to perform.
+ * Only apps holding {@link android.Manifest.permission.NETWORK_STACK} permission can set
+ * this value.
+ *
+ * Note: This serves as an intent and not as a stipulation, the wifi chip
+ * might honor or ignore the indication based on the current radio conditions. Always
+ * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration
+ * used to receive the corresponding scan result.
+ *
+ * One of {@link #SCAN_TYPE_LOW_LATENCY}, {@link #SCAN_TYPE_LOW_POWER},
+ * {@link #SCAN_TYPE_HIGH_ACCURACY}.
+ * Default value: {@link #SCAN_TYPE_LOW_LATENCY}.
*/
+ @WifiAnnotations.ScanType
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public int type = TYPE_LOW_LATENCY;
+ public int type = SCAN_TYPE_LOW_LATENCY;
/**
* This scan request may ignore location settings while receiving scans. This should only
* be used in emergency situations.
@@ -299,18 +432,14 @@ public class WifiScanner {
} else {
dest.writeInt(0);
}
- if (hiddenNetworks != null) {
- dest.writeInt(hiddenNetworks.length);
- for (int i = 0; i < hiddenNetworks.length; i++) {
- dest.writeString(hiddenNetworks[i].ssid);
- }
- } else {
- dest.writeInt(0);
+ dest.writeInt(hiddenNetworks.size());
+ for (HiddenNetwork hiddenNetwork : hiddenNetworks) {
+ dest.writeString(hiddenNetwork.ssid);
}
}
/** Implement the Parcelable interface {@hide} */
- public static final @android.annotation.NonNull Creator<ScanSettings> CREATOR =
+ public static final @NonNull Creator<ScanSettings> CREATOR =
new Creator<ScanSettings>() {
public ScanSettings createFromParcel(Parcel in) {
ScanSettings settings = new ScanSettings();
@@ -335,10 +464,10 @@ public class WifiScanner {
settings.channels[i] = spec;
}
int numNetworks = in.readInt();
- settings.hiddenNetworks = new HiddenNetwork[numNetworks];
+ settings.hiddenNetworks.clear();
for (int i = 0; i < numNetworks; i++) {
String ssid = in.readString();
- settings.hiddenNetworks[i] = new HiddenNetwork(ssid);;
+ settings.hiddenNetworks.add(new HiddenNetwork(ssid));
}
return settings;
}
@@ -347,7 +476,6 @@ public class WifiScanner {
return new ScanSettings[size];
}
};
-
}
/**
@@ -375,19 +503,27 @@ public class WifiScanner {
*/
private int mBandScanned;
/** all scan results discovered in this scan, sorted by timestamp in ascending order */
- private ScanResult mResults[];
+ private final List<ScanResult> mResults;
- ScanData() {}
+ ScanData() {
+ mResults = new ArrayList<>();
+ }
public ScanData(int id, int flags, ScanResult[] results) {
mId = id;
mFlags = flags;
- mResults = results;
+ mResults = new ArrayList<>(Arrays.asList(results));
}
/** {@hide} */
public ScanData(int id, int flags, int bucketsScanned, int bandScanned,
ScanResult[] results) {
+ this(id, flags, bucketsScanned, bandScanned, new ArrayList<>(Arrays.asList(results)));
+ }
+
+ /** {@hide} */
+ public ScanData(int id, int flags, int bucketsScanned, int bandScanned,
+ List<ScanResult> results) {
mId = id;
mFlags = flags;
mBucketsScanned = bucketsScanned;
@@ -400,11 +536,9 @@ public class WifiScanner {
mFlags = s.mFlags;
mBucketsScanned = s.mBucketsScanned;
mBandScanned = s.mBandScanned;
- mResults = new ScanResult[s.mResults.length];
- for (int i = 0; i < s.mResults.length; i++) {
- ScanResult result = s.mResults[i];
- ScanResult newResult = new ScanResult(result);
- mResults[i] = newResult;
+ mResults = new ArrayList<>();
+ for (ScanResult scanResult : s.mResults) {
+ mResults.add(new ScanResult(scanResult));
}
}
@@ -427,7 +561,14 @@ public class WifiScanner {
}
public ScanResult[] getResults() {
- return mResults;
+ return mResults.toArray(new ScanResult[0]);
+ }
+
+ /** {@hide} */
+ public void addResults(@NonNull ScanResult[] newResults) {
+ for (ScanResult result : newResults) {
+ mResults.add(new ScanResult(result));
+ }
}
/** Implement the Parcelable interface {@hide} */
@@ -437,34 +578,23 @@ public class WifiScanner {
/** Implement the Parcelable interface {@hide} */
public void writeToParcel(Parcel dest, int flags) {
- if (mResults != null) {
- dest.writeInt(mId);
- dest.writeInt(mFlags);
- dest.writeInt(mBucketsScanned);
- dest.writeInt(mBandScanned);
- dest.writeInt(mResults.length);
- for (int i = 0; i < mResults.length; i++) {
- ScanResult result = mResults[i];
- result.writeToParcel(dest, flags);
- }
- } else {
- dest.writeInt(0);
- }
+ dest.writeInt(mId);
+ dest.writeInt(mFlags);
+ dest.writeInt(mBucketsScanned);
+ dest.writeInt(mBandScanned);
+ dest.writeParcelableList(mResults, 0);
}
/** Implement the Parcelable interface {@hide} */
- public static final @android.annotation.NonNull Creator<ScanData> CREATOR =
+ public static final @NonNull Creator<ScanData> CREATOR =
new Creator<ScanData>() {
public ScanData createFromParcel(Parcel in) {
int id = in.readInt();
int flags = in.readInt();
int bucketsScanned = in.readInt();
int bandScanned = in.readInt();
- int n = in.readInt();
- ScanResult results[] = new ScanResult[n];
- for (int i = 0; i < n; i++) {
- results[i] = ScanResult.CREATOR.createFromParcel(in);
- }
+ List<ScanResult> results = new ArrayList<>();
+ in.readParcelableList(results, ScanResult.class.getClassLoader());
return new ScanData(id, flags, bucketsScanned, bandScanned, results);
}
@@ -505,7 +635,7 @@ public class WifiScanner {
}
/** Implement the Parcelable interface {@hide} */
- public static final @android.annotation.NonNull Creator<ParcelableScanData> CREATOR =
+ public static final @NonNull Creator<ParcelableScanData> CREATOR =
new Creator<ParcelableScanData>() {
public ParcelableScanData createFromParcel(Parcel in) {
int n = in.readInt();
@@ -553,7 +683,7 @@ public class WifiScanner {
}
/** Implement the Parcelable interface {@hide} */
- public static final @android.annotation.NonNull Creator<ParcelableScanResults> CREATOR =
+ public static final @NonNull Creator<ParcelableScanResults> CREATOR =
new Creator<ParcelableScanResults>() {
public ParcelableScanResults createFromParcel(Parcel in) {
int n = in.readInt();
@@ -631,6 +761,25 @@ public class WifiScanner {
public PnoNetwork(String ssid) {
this.ssid = ssid;
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ssid, flags, authBitField);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof PnoNetwork)) {
+ return false;
+ }
+ PnoNetwork lhs = (PnoNetwork) obj;
+ return TextUtils.equals(this.ssid, lhs.ssid)
+ && this.flags == lhs.flags
+ && this.authBitField == lhs.authBitField;
+ }
}
/** Connected vs Disconnected PNO flag {@hide} */
@@ -639,19 +788,8 @@ public class WifiScanner {
public int min5GHzRssi;
/** Minimum 2.4GHz RSSI for a BSSID to be considered */
public int min24GHzRssi;
- /** Maximum score that a network can have before bonuses */
- public int initialScoreMax;
- /**
- * Only report when there is a network's score this much higher
- * than the current connection.
- */
- public int currentConnectionBonus;
- /** score bonus for all networks with the same network flag */
- public int sameNetworkBonus;
- /** score bonus for networks that are not open */
- public int secureBonus;
- /** 5GHz RSSI score bonus (applied to all 5GHz networks) */
- public int band5GHzBonus;
+ /** Minimum 6GHz RSSI for a BSSID to be considered */
+ public int min6GHzRssi;
/** Pno Network filter list */
public PnoNetwork[] networkList;
@@ -665,11 +803,7 @@ public class WifiScanner {
dest.writeInt(isConnected ? 1 : 0);
dest.writeInt(min5GHzRssi);
dest.writeInt(min24GHzRssi);
- dest.writeInt(initialScoreMax);
- dest.writeInt(currentConnectionBonus);
- dest.writeInt(sameNetworkBonus);
- dest.writeInt(secureBonus);
- dest.writeInt(band5GHzBonus);
+ dest.writeInt(min6GHzRssi);
if (networkList != null) {
dest.writeInt(networkList.length);
for (int i = 0; i < networkList.length; i++) {
@@ -684,18 +818,14 @@ public class WifiScanner {
}
/** Implement the Parcelable interface {@hide} */
- public static final @android.annotation.NonNull Creator<PnoSettings> CREATOR =
+ public static final @NonNull Creator<PnoSettings> CREATOR =
new Creator<PnoSettings>() {
public PnoSettings createFromParcel(Parcel in) {
PnoSettings settings = new PnoSettings();
settings.isConnected = in.readInt() == 1;
settings.min5GHzRssi = in.readInt();
settings.min24GHzRssi = in.readInt();
- settings.initialScoreMax = in.readInt();
- settings.currentConnectionBonus = in.readInt();
- settings.sameNetworkBonus = in.readInt();
- settings.secureBonus = in.readInt();
- settings.band5GHzBonus = in.readInt();
+ settings.min6GHzRssi = in.readInt();
int numNetworks = in.readInt();
settings.networkList = new PnoNetwork[numNetworks];
for (int i = 0; i < numNetworks; i++) {
@@ -724,7 +854,11 @@ public class WifiScanner {
/**
* Framework co-ordinates scans across multiple apps; so it may not give exactly the
* same period requested. If period of a scan is changed; it is reported by this event.
+ * @deprecated Background scan support has always been hardware vendor dependent. This
+ * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
+ * ScanListener)} instead for single scans.
*/
+ @Deprecated
public void onPeriodChanged(int periodInMs);
/**
* reports results retrieved from background scan and single shot scans
@@ -751,8 +885,12 @@ public class WifiScanner {
/**
* Enable/Disable wifi scanning.
*
+ * @param enable set to true to enable scanning, set to false to disable all types of scanning.
+ *
+ * @see WifiManager#ACTION_WIFI_SCAN_AVAILABILITY_CHANGED
* {@hide}
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.NETWORK_STACK)
public void setScanningEnabled(boolean enable) {
validateChannel();
@@ -760,34 +898,46 @@ public class WifiScanner {
}
/**
- * Register a listener that will receive results from all single scans
- * Either the onSuccess/onFailure will be called once when the listener is registered. After
- * (assuming onSuccess was called) all subsequent single scan results will be delivered to the
- * listener. It is possible that onFullResult will not be called for all results of the first
- * scan if the listener was registered during the scan.
+ * Register a listener that will receive results from all single scans.
+ * Either the {@link ScanListener#onSuccess()} or {@link ScanListener#onFailure(int, String)}
+ * method will be called once when the listener is registered.
+ * Afterwards (assuming onSuccess was called), all subsequent single scan results will be
+ * delivered to the listener. It is possible that onFullResult will not be called for all
+ * results of the first scan if the listener was registered during the scan.
*
+ * @param executor the Executor on which to run the callback.
* @param listener specifies the object to report events to. This object is also treated as a
* key for this request, and must also be specified to cancel the request.
* Multiple requests should also not share this object.
- * {@hide}
*/
@RequiresPermission(Manifest.permission.NETWORK_STACK)
- public void registerScanListener(ScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
- int key = addListener(listener);
+ public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull ScanListener listener) {
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
+ int key = addListener(listener, executor);
if (key == INVALID_KEY) return;
validateChannel();
mAsyncChannel.sendMessage(CMD_REGISTER_SCAN_LISTENER, 0, key);
}
/**
+ * Overload of {@link #registerScanListener(Executor, ScanListener)} that executes the callback
+ * synchronously.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.NETWORK_STACK)
+ public void registerScanListener(@NonNull ScanListener listener) {
+ registerScanListener(new SynchronousExecutor(), listener);
+ }
+
+ /**
* Deregister a listener for ongoing single scans
* @param listener specifies which scan to cancel; must be same object as passed in {@link
* #registerScanListener}
- * {@hide}
*/
- public void deregisterScanListener(ScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ public void unregisterScanListener(@NonNull ScanListener listener) {
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -813,11 +963,15 @@ public class WifiScanner {
* @param listener specifies the object to report events to. This object is also treated as a
* key for this scan, and must also be specified to cancel the scan. Multiple
* scans should also not share this object.
+ * @deprecated Background scan support has always been hardware vendor dependent. This support
+ * may not be present on newer devices. Use {@link #startScan(ScanSettings, ScanListener)}
+ * instead for single scans.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startBackgroundScan(ScanSettings settings, ScanListener listener,
WorkSource workSource) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = addListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -825,6 +979,7 @@ public class WifiScanner {
scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
}
@@ -832,27 +987,37 @@ public class WifiScanner {
* stop an ongoing wifi scan
* @param listener specifies which scan to cancel; must be same object as passed in {@link
* #startBackgroundScan}
+ * @deprecated Background scan support has always been hardware vendor dependent. This support
+ * may not be present on newer devices. Use {@link #startScan(ScanSettings, ScanListener)}
+ * instead for single scans.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void stopBackgroundScan(ScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
Bundle scanParams = new Bundle();
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key, scanParams);
}
/**
* reports currently available scan results on appropriate listeners
* @return true if all scan results were reported correctly
+ * @deprecated Background scan support has always been hardware vendor dependent. This support
+ * may not be present on newer devices. Use {@link #startScan(ScanSettings, ScanListener)}
+ * instead for single scans.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean getScanResults() {
validateChannel();
Bundle scanParams = new Bundle();
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
Message reply =
mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0, 0, scanParams);
return reply.what == CMD_OP_SUCCEEDED;
@@ -875,21 +1040,39 @@ public class WifiScanner {
* starts a single scan and reports results asynchronously
* @param settings specifies various parameters for the scan; for more information look at
* {@link ScanSettings}
- * @param workSource WorkSource to blame for power usage
* @param listener specifies the object to report events to. This object is also treated as a
* key for this scan, and must also be specified to cancel the scan. Multiple
* scans should also not share this object.
+ * @param workSource WorkSource to blame for power usage
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
- int key = addListener(listener);
+ startScan(settings, null, listener, workSource);
+ }
+
+ /**
+ * starts a single scan and reports results asynchronously
+ * @param settings specifies various parameters for the scan; for more information look at
+ * {@link ScanSettings}
+ * @param executor the Executor on which to run the callback.
+ * @param listener specifies the object to report events to. This object is also treated as a
+ * key for this scan, and must also be specified to cancel the scan. Multiple
+ * scans should also not share this object.
+ * @param workSource WorkSource to blame for power usage
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+ public void startScan(ScanSettings settings, @Nullable @CallbackExecutor Executor executor,
+ ScanListener listener, WorkSource workSource) {
+ Objects.requireNonNull(listener, "listener cannot be null");
+ int key = addListener(listener, executor);
if (key == INVALID_KEY) return;
validateChannel();
Bundle scanParams = new Bundle();
scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
}
@@ -900,23 +1083,26 @@ public class WifiScanner {
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void stopScan(ScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
Bundle scanParams = new Bundle();
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key, scanParams);
}
/**
* Retrieve the most recent scan results from a single scan request.
- * {@hide}
*/
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public List<ScanResult> getSingleScanResults() {
validateChannel();
Bundle scanParams = new Bundle();
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0, 0,
scanParams);
if (reply.what == WifiScanner.CMD_OP_SUCCEEDED) {
@@ -925,7 +1111,7 @@ public class WifiScanner {
OperationResult result = (OperationResult) reply.obj;
Log.e(TAG, "Error retrieving SingleScan results reason: " + result.reason
+ " description: " + result.description);
- return new ArrayList<ScanResult>();
+ return new ArrayList<>();
}
private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
@@ -943,16 +1129,17 @@ public class WifiScanner {
* {@link ScanSettings}
* @param pnoSettings specifies various parameters for PNO; for more information look at
* {@link PnoSettings}
+ * @param executor the Executor on which to run the callback.
* @param listener specifies the object to report events to. This object is also treated as a
* key for this scan, and must also be specified to cancel the scan. Multiple
* scans should also not share this object.
* {@hide}
*/
public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
- PnoScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
- Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
- int key = addListener(listener);
+ @NonNull @CallbackExecutor Executor executor, PnoScanListener listener) {
+ Objects.requireNonNull(listener, "listener cannot be null");
+ Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null");
+ int key = addListener(listener, executor);
if (key == INVALID_KEY) return;
validateChannel();
pnoSettings.isConnected = true;
@@ -971,10 +1158,10 @@ public class WifiScanner {
*/
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
- PnoScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
- Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
- int key = addListener(listener);
+ @NonNull @CallbackExecutor Executor executor, PnoScanListener listener) {
+ Objects.requireNonNull(listener, "listener cannot be null");
+ Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null");
+ int key = addListener(listener, executor);
if (key == INVALID_KEY) return;
validateChannel();
pnoSettings.isConnected = false;
@@ -988,7 +1175,7 @@ public class WifiScanner {
*/
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
public void stopPnoScan(ScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -1029,7 +1216,7 @@ public class WifiScanner {
}
/** Implement the Parcelable interface {@hide} */
- public static final @android.annotation.NonNull Creator<WifiChangeSettings> CREATOR =
+ public static final @NonNull Creator<WifiChangeSettings> CREATOR =
new Creator<WifiChangeSettings>() {
public WifiChangeSettings createFromParcel(Parcel in) {
return new WifiChangeSettings();
@@ -1140,7 +1327,7 @@ public class WifiScanner {
}
/** Implement the Parcelable interface {@hide} */
- public static final @android.annotation.NonNull Creator<HotlistSettings> CREATOR =
+ public static final @NonNull Creator<HotlistSettings> CREATOR =
new Creator<HotlistSettings>() {
public HotlistSettings createFromParcel(Parcel in) {
HotlistSettings settings = new HotlistSettings();
@@ -1230,6 +1417,7 @@ public class WifiScanner {
private int mListenerKey = 1;
private final SparseArray mListenerMap = new SparseArray();
+ private final SparseArray<Executor> mExecutorMap = new SparseArray<>();
private final Object mListenerMapLock = new Object();
private AsyncChannel mAsyncChannel;
@@ -1240,12 +1428,15 @@ public class WifiScanner {
* Applications will almost always want to use
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
* the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
+ *
* @param context the application context
- * @param service the Binder interface
+ * @param service the Binder interface for {@link Context#WIFI_SCANNING_SERVICE}
* @param looper the Looper used to deliver callbacks
+ *
* @hide
*/
- public WifiScanner(Context context, IWifiScanner service, Looper looper) {
+ public WifiScanner(@NonNull Context context, @NonNull IWifiScanner service,
+ @NonNull Looper looper) {
mContext = context;
mService = service;
@@ -1274,10 +1465,14 @@ public class WifiScanner {
"No permission to access and change wifi or a bad initialization");
}
+ private int addListener(ActionListener listener) {
+ return addListener(listener, null);
+ }
+
// Add a listener into listener map. If the listener already exists, return INVALID_KEY and
// send an error message to internal handler; Otherwise add the listener to the listener map and
// return the key of the listener.
- private int addListener(ActionListener listener) {
+ private int addListener(ActionListener listener, Executor executor) {
synchronized (mListenerMapLock) {
boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
// Note we need to put the listener into listener map even if it's a duplicate as the
@@ -1293,6 +1488,7 @@ public class WifiScanner {
message.sendToTarget();
return INVALID_KEY;
} else {
+ mExecutorMap.put(key, executor);
return key;
}
}
@@ -1310,11 +1506,22 @@ public class WifiScanner {
return key;
}
- private Object getListener(int key) {
- if (key == INVALID_KEY) return null;
+ private static class ListenerWithExecutor {
+ @Nullable final Object mListener;
+ @Nullable final Executor mExecutor;
+
+ ListenerWithExecutor(@Nullable Object listener, @Nullable Executor executor) {
+ mListener = listener;
+ mExecutor = executor;
+ }
+ }
+
+ private ListenerWithExecutor getListenerWithExecutor(int key) {
+ if (key == INVALID_KEY) return new ListenerWithExecutor(null, null);
synchronized (mListenerMapLock) {
Object listener = mListenerMap.get(key);
- return listener;
+ Executor executor = mExecutorMap.get(key);
+ return new ListenerWithExecutor(listener, executor);
}
}
@@ -1335,6 +1542,7 @@ public class WifiScanner {
synchronized (mListenerMapLock) {
Object listener = mListenerMap.get(key);
mListenerMap.remove(key);
+ mExecutorMap.remove(key);
return listener;
}
}
@@ -1347,6 +1555,7 @@ public class WifiScanner {
}
synchronized (mListenerMapLock) {
mListenerMap.remove(key);
+ mExecutorMap.remove(key);
return key;
}
}
@@ -1373,7 +1582,7 @@ public class WifiScanner {
}
/** Implement the Parcelable interface {@hide} */
- public static final @android.annotation.NonNull Creator<OperationResult> CREATOR =
+ public static final @NonNull Creator<OperationResult> CREATOR =
new Creator<OperationResult>() {
public OperationResult createFromParcel(Parcel in) {
int reason = in.readInt();
@@ -1405,7 +1614,8 @@ public class WifiScanner {
return;
}
- Object listener = getListener(msg.arg2);
+ ListenerWithExecutor listenerWithExecutor = getListenerWithExecutor(msg.arg2);
+ Object listener = listenerWithExecutor.mListener;
if (listener == null) {
if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
@@ -1414,36 +1624,52 @@ public class WifiScanner {
if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
}
+ Executor executor = listenerWithExecutor.mExecutor;
+ if (executor == null) {
+ executor = new SynchronousExecutor();
+ }
+
switch (msg.what) {
- /* ActionListeners grouped together */
- case CMD_OP_SUCCEEDED :
- ((ActionListener) listener).onSuccess();
- break;
- case CMD_OP_FAILED : {
- OperationResult result = (OperationResult)msg.obj;
- ((ActionListener) listener).onFailure(result.reason, result.description);
- removeListener(msg.arg2);
- }
- break;
- case CMD_SCAN_RESULT :
- ((ScanListener) listener).onResults(
- ((ParcelableScanData) msg.obj).getResults());
- return;
- case CMD_FULL_SCAN_RESULT :
+ /* ActionListeners grouped together */
+ case CMD_OP_SUCCEEDED: {
+ ActionListener actionListener = (ActionListener) listener;
+ Binder.clearCallingIdentity();
+ executor.execute(actionListener::onSuccess);
+ } break;
+ case CMD_OP_FAILED: {
+ OperationResult result = (OperationResult) msg.obj;
+ ActionListener actionListener = (ActionListener) listener;
+ removeListener(msg.arg2);
+ Binder.clearCallingIdentity();
+ executor.execute(() ->
+ actionListener.onFailure(result.reason, result.description));
+ } break;
+ case CMD_SCAN_RESULT: {
+ ScanListener scanListener = (ScanListener) listener;
+ ParcelableScanData parcelableScanData = (ParcelableScanData) msg.obj;
+ Binder.clearCallingIdentity();
+ executor.execute(() -> scanListener.onResults(parcelableScanData.getResults()));
+ } break;
+ case CMD_FULL_SCAN_RESULT: {
ScanResult result = (ScanResult) msg.obj;
- ((ScanListener) listener).onFullResult(result);
- return;
- case CMD_SINGLE_SCAN_COMPLETED:
+ ScanListener scanListener = ((ScanListener) listener);
+ Binder.clearCallingIdentity();
+ executor.execute(() -> scanListener.onFullResult(result));
+ } break;
+ case CMD_SINGLE_SCAN_COMPLETED: {
if (DBG) Log.d(TAG, "removing listener for single scan");
removeListener(msg.arg2);
- break;
- case CMD_PNO_NETWORK_FOUND:
- ((PnoScanListener) listener).onPnoNetworkFound(
- ((ParcelableScanResults) msg.obj).getResults());
- return;
- default:
+ } break;
+ case CMD_PNO_NETWORK_FOUND: {
+ PnoScanListener pnoScanListener = (PnoScanListener) listener;
+ ParcelableScanResults parcelableScanResults = (ParcelableScanResults) msg.obj;
+ Binder.clearCallingIdentity();
+ executor.execute(() ->
+ pnoScanListener.onPnoNetworkFound(parcelableScanResults.getResults()));
+ } break;
+ default: {
if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
- return;
+ } break;
}
}
}
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index a591f312028e..704ae81f71aa 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -16,6 +16,8 @@
package android.net.wifi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -40,23 +42,29 @@ import java.util.Locale;
*
* @hide
*/
-public class WifiSsid implements Parcelable {
+public final class WifiSsid implements Parcelable {
private static final String TAG = "WifiSsid";
@UnsupportedAppUsage
public final ByteArrayOutputStream octets = new ByteArrayOutputStream(32);
private static final int HEX_RADIX = 16;
+
@UnsupportedAppUsage
public static final String NONE = WifiManager.UNKNOWN_SSID;
private WifiSsid() {
}
- public static WifiSsid createFromByteArray(byte ssid[]) {
+ /**
+ * Create a WifiSsid from a raw byte array. If the byte array is null, return an empty WifiSsid
+ * object.
+ */
+ @NonNull
+ public static WifiSsid createFromByteArray(@Nullable byte[] ssid) {
WifiSsid wifiSsid = new WifiSsid();
if (ssid != null) {
- wifiSsid.octets.write(ssid, 0/* the start offset */, ssid.length);;
+ wifiSsid.octets.write(ssid, 0 /* the start offset */, ssid.length);
}
return wifiSsid;
}
@@ -174,6 +182,10 @@ public class WifiSsid implements Parcelable {
}
}
+ /**
+ * Converts this SSID to an unquoted UTF-8 String representation.
+ * @return the SSID string, or {@link WifiManager#UNKNOWN_SSID} if there was an error.
+ */
@Override
public String toString() {
byte[] ssidBytes = octets.toByteArray();
@@ -191,7 +203,7 @@ public class WifiSsid implements Parcelable {
CoderResult result = decoder.decode(ByteBuffer.wrap(ssidBytes), out, true);
out.flip();
if (result.isError()) {
- return NONE;
+ return WifiManager.UNKNOWN_SSID;
}
return out.toString();
}
@@ -241,32 +253,36 @@ public class WifiSsid implements Parcelable {
return (octets.size() > 0) ? out : null;
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
+ @Override
public int describeContents() {
return 0;
}
- /** Implement the Parcelable interface {@hide} */
- public void writeToParcel(Parcel dest, int flags) {
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(octets.size());
dest.writeByteArray(octets.toByteArray());
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
@UnsupportedAppUsage
- public static final @android.annotation.NonNull Creator<WifiSsid> CREATOR =
- new Creator<WifiSsid>() {
- public WifiSsid createFromParcel(Parcel in) {
- WifiSsid ssid = new WifiSsid();
- int length = in.readInt();
- byte b[] = new byte[length];
- in.readByteArray(b);
- ssid.octets.write(b, 0, length);
- return ssid;
- }
+ public static final @NonNull Creator<WifiSsid> CREATOR =
+ new Creator<WifiSsid>() {
+ @Override
+ public WifiSsid createFromParcel(Parcel in) {
+ WifiSsid ssid = new WifiSsid();
+ int length = in.readInt();
+ byte[] b = new byte[length];
+ in.readByteArray(b);
+ ssid.octets.write(b, 0, length);
+ return ssid;
+ }
- public WifiSsid[] newArray(int size) {
- return new WifiSsid[size];
- }
- };
+ @Override
+ public WifiSsid[] newArray(int size) {
+ return new WifiSsid[size];
+ }
+ };
}
diff --git a/wifi/java/android/net/wifi/WpsResult.java b/wifi/java/android/net/wifi/WpsResult.java
deleted file mode 100644
index f2ffb6f52520..000000000000
--- a/wifi/java/android/net/wifi/WpsResult.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A class representing the result of a WPS request
- * @hide
- */
-public class WpsResult implements Parcelable {
-
- public enum Status {
- SUCCESS,
- FAILURE,
- IN_PROGRESS,
- }
-
- public Status status;
-
- public String pin;
-
- public WpsResult() {
- status = Status.FAILURE;
- pin = null;
- }
-
- public WpsResult(Status s) {
- status = s;
- pin = null;
- }
-
- public String toString() {
- StringBuffer sbuf = new StringBuffer();
- sbuf.append(" status: ").append(status.toString());
- sbuf.append('\n');
- sbuf.append(" pin: ").append(pin);
- sbuf.append("\n");
- return sbuf.toString();
- }
-
- /** Implement the Parcelable interface {@hide} */
- public int describeContents() {
- return 0;
- }
-
- /** copy constructor {@hide} */
- public WpsResult(WpsResult source) {
- if (source != null) {
- status = source.status;
- pin = source.pin;
- }
- }
-
- /** Implement the Parcelable interface {@hide} */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(status.name());
- dest.writeString(pin);
- }
-
- /** Implement the Parcelable interface {@hide} */
- public static final @android.annotation.NonNull Creator<WpsResult> CREATOR =
- new Creator<WpsResult>() {
- public WpsResult createFromParcel(Parcel in) {
- WpsResult result = new WpsResult();
- result.status = Status.valueOf(in.readString());
- result.pin = in.readString();
- return result;
- }
-
- public WpsResult[] newArray(int size) {
- return new WpsResult[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/aware/Characteristics.java b/wifi/java/android/net/wifi/aware/Characteristics.java
index e2cf4dc02659..d5fd48e9e7b3 100644
--- a/wifi/java/android/net/wifi/aware/Characteristics.java
+++ b/wifi/java/android/net/wifi/aware/Characteristics.java
@@ -16,10 +16,14 @@
package android.net.wifi.aware;
+import android.annotation.IntDef;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* The characteristics of the Wi-Fi Aware implementation.
*/
@@ -31,6 +35,8 @@ public final class Characteristics implements Parcelable {
"key_max_service_specific_info_length";
/** @hide */
public static final String KEY_MAX_MATCH_FILTER_LENGTH = "key_max_match_filter_length";
+ /** @hide */
+ public static final String KEY_SUPPORTED_CIPHER_SUITES = "key_supported_cipher_suites";
private Bundle mCharacteristics = new Bundle();
@@ -71,12 +77,41 @@ public final class Characteristics implements Parcelable {
* {@link PublishConfig.Builder#setMatchFilter(java.util.List)} and
* {@link SubscribeConfig.Builder#setMatchFilter(java.util.List)}.
*
- * @return A positive integer, maximum legngth of byte array for Aware discovery match filter.
+ * @return A positive integer, maximum length of byte array for Aware discovery match filter.
*/
public int getMaxMatchFilterLength() {
return mCharacteristics.getInt(KEY_MAX_MATCH_FILTER_LENGTH);
}
+ /** @hide */
+ @IntDef(flag = true, prefix = { "WIFI_AWARE_CIPHER_SUITE_" }, value = {
+ WIFI_AWARE_CIPHER_SUITE_NCS_SK_128,
+ WIFI_AWARE_CIPHER_SUITE_NCS_SK_256,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WifiAwareCipherSuites {}
+
+ /**
+ * Wi-Fi Aware supported ciphier suite representing NCS SK 128: 128 bit shared-key.
+ */
+ public static final int WIFI_AWARE_CIPHER_SUITE_NCS_SK_128 = 1 << 0;
+
+ /**
+ * Wi-Fi Aware supported ciphier suite representing NCS SK 256: 256 bit shared-key.
+ */
+ public static final int WIFI_AWARE_CIPHER_SUITE_NCS_SK_256 = 1 << 1;
+
+ /**
+ * Returns the set of cipher suites supported by the device for use in Wi-Fi Aware data-paths.
+ * The device automatically picks the strongest cipher suite when initiating a data-path setup.
+ *
+ * @return A set of flags from {@link #WIFI_AWARE_CIPHER_SUITE_NCS_SK_128}, or
+ * {@link #WIFI_AWARE_CIPHER_SUITE_NCS_SK_256}.
+ */
+ public @WifiAwareCipherSuites int getSupportedCipherSuites() {
+ return mCharacteristics.getInt(KEY_SUPPORTED_CIPHER_SUITES);
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeBundle(mCharacteristics);
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index b07d8edde3d4..61ab92c9416f 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -47,6 +47,7 @@ public final class ConfigRequest implements Parcelable {
*/
public static final int NAN_BAND_24GHZ = 0;
public static final int NAN_BAND_5GHZ = 1;
+ public static final int NAN_BAND_6GHZ = 2;
/**
* Magic values for Discovery Window (DW) interval configuration
@@ -60,6 +61,11 @@ public final class ConfigRequest implements Parcelable {
public final boolean mSupport5gBand;
/**
+ * Indicates whether 6G band support is requested.
+ */
+ public final boolean mSupport6gBand;
+
+ /**
* Specifies the desired master preference.
*/
public final int mMasterPreference;
@@ -81,9 +87,10 @@ public final class ConfigRequest implements Parcelable {
*/
public final int mDiscoveryWindowInterval[];
- private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow,
- int clusterHigh, int discoveryWindowInterval[]) {
+ private ConfigRequest(boolean support5gBand, boolean support6gBand, int masterPreference,
+ int clusterLow, int clusterHigh, int[] discoveryWindowInterval) {
mSupport5gBand = support5gBand;
+ mSupport6gBand = support6gBand;
mMasterPreference = masterPreference;
mClusterLow = clusterLow;
mClusterHigh = clusterHigh;
@@ -92,10 +99,12 @@ public final class ConfigRequest implements Parcelable {
@Override
public String toString() {
- return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference="
- + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh="
- + mClusterHigh + ", mDiscoveryWindowInterval="
- + Arrays.toString(mDiscoveryWindowInterval) + "]";
+ return "ConfigRequest [mSupport5gBand=" + mSupport5gBand
+ + ", mSupport6gBand=" + mSupport6gBand
+ + ", mMasterPreference=" + mMasterPreference
+ + ", mClusterLow=" + mClusterLow
+ + ", mClusterHigh=" + mClusterHigh
+ + ", mDiscoveryWindowInterval=" + Arrays.toString(mDiscoveryWindowInterval) + "]";
}
@Override
@@ -106,6 +115,7 @@ public final class ConfigRequest implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mSupport5gBand ? 1 : 0);
+ dest.writeInt(mSupport6gBand ? 1 : 0);
dest.writeInt(mMasterPreference);
dest.writeInt(mClusterLow);
dest.writeInt(mClusterHigh);
@@ -121,13 +131,14 @@ public final class ConfigRequest implements Parcelable {
@Override
public ConfigRequest createFromParcel(Parcel in) {
boolean support5gBand = in.readInt() != 0;
+ boolean support6gBand = in.readInt() != 0;
int masterPreference = in.readInt();
int clusterLow = in.readInt();
int clusterHigh = in.readInt();
int discoveryWindowInterval[] = in.createIntArray();
- return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh,
- discoveryWindowInterval);
+ return new ConfigRequest(support5gBand, support6gBand, masterPreference, clusterLow,
+ clusterHigh, discoveryWindowInterval);
}
};
@@ -143,7 +154,9 @@ public final class ConfigRequest implements Parcelable {
ConfigRequest lhs = (ConfigRequest) o;
- return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
+ return mSupport5gBand == lhs.mSupport5gBand
+ && mSupport6gBand == lhs.mSupport6gBand
+ && mMasterPreference == lhs.mMasterPreference
&& mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh
&& Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval);
}
@@ -153,6 +166,7 @@ public final class ConfigRequest implements Parcelable {
int result = 17;
result = 31 * result + (mSupport5gBand ? 1 : 0);
+ result = 31 * result + (mSupport6gBand ? 1 : 0);
result = 31 * result + mMasterPreference;
result = 31 * result + mClusterLow;
result = 31 * result + mClusterHigh;
@@ -190,9 +204,9 @@ public final class ConfigRequest implements Parcelable {
throw new IllegalArgumentException(
"Invalid argument combination - must have Cluster Low <= Cluster High");
}
- if (mDiscoveryWindowInterval.length != 2) {
+ if (mDiscoveryWindowInterval.length != 3) {
throw new IllegalArgumentException(
- "Invalid discovery window interval: must have 2 elements (2.4 & 5");
+ "Invalid discovery window interval: must have 3 elements (2.4 & 5 & 6");
}
if (mDiscoveryWindowInterval[NAN_BAND_24GHZ] != DW_INTERVAL_NOT_INIT &&
(mDiscoveryWindowInterval[NAN_BAND_24GHZ] < 1 // valid for 2.4GHz: [1-5]
@@ -206,7 +220,12 @@ public final class ConfigRequest implements Parcelable {
throw new IllegalArgumentException(
"Invalid discovery window interval for 5GHz: valid is UNSET or [0,5]");
}
-
+ if (mDiscoveryWindowInterval[NAN_BAND_6GHZ] != DW_INTERVAL_NOT_INIT
+ && (mDiscoveryWindowInterval[NAN_BAND_6GHZ] < 0 // valid for 6GHz: [0-5]
+ || mDiscoveryWindowInterval[NAN_BAND_6GHZ] > 5)) {
+ throw new IllegalArgumentException(
+ "Invalid discovery window interval for 6GHz: valid is UNSET or [0,5]");
+ }
}
/**
@@ -214,10 +233,12 @@ public final class ConfigRequest implements Parcelable {
*/
public static final class Builder {
private boolean mSupport5gBand = true;
+ private boolean mSupport6gBand = false;
private int mMasterPreference = 0;
private int mClusterLow = CLUSTER_ID_MIN;
private int mClusterHigh = CLUSTER_ID_MAX;
- private int mDiscoveryWindowInterval[] = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT};
+ private int[] mDiscoveryWindowInterval = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT,
+ DW_INTERVAL_NOT_INIT};
/**
* Specify whether 5G band support is required in this request. Disabled by default.
@@ -233,6 +254,19 @@ public final class ConfigRequest implements Parcelable {
}
/**
+ * Specify whether 6G band support is required in this request. Disabled by default.
+ *
+ * @param support6gBand Support for 6G band is required.
+ *
+ * @return The builder to facilitate chaining
+ * {@code builder.setXXX(..).setXXX(..)}.
+ */
+ public Builder setSupport6gBand(boolean support6gBand) {
+ mSupport6gBand = support6gBand;
+ return this;
+ }
+
+ /**
* Specify the Master Preference requested. The permitted range is 0 (the default) to
* 255 with 1 and 255 excluded (reserved).
*
@@ -310,7 +344,8 @@ public final class ConfigRequest implements Parcelable {
* awake. The configuration enables trading off latency vs. power (higher interval means
* higher discovery latency but lower power).
*
- * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ}.
+ * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ} or
+ * {@link #NAN_BAND_6GHZ}.
* @param interval A value of 1, 2, 3, 4, or 5 indicating an interval of 2^(interval-1). For
* the 5GHz band a value of 0 indicates that the device will not be awake
* for any discovery windows.
@@ -319,13 +354,14 @@ public final class ConfigRequest implements Parcelable {
* {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}.
*/
public Builder setDiscoveryWindowInterval(int band, int interval) {
- if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ) {
+ if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ && band != NAN_BAND_6GHZ) {
throw new IllegalArgumentException("Invalid band value");
}
if ((band == NAN_BAND_24GHZ && (interval < 1 || interval > 5))
- || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))) {
+ || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))
+ || (band == NAN_BAND_6GHZ && (interval < 0 || interval > 5))) {
throw new IllegalArgumentException(
- "Invalid interval value: 2.4 GHz [1,5] or 5GHz [0,5]");
+ "Invalid interval value: 2.4 GHz [1,5] or 5GHz/6GHz [0,5]");
}
mDiscoveryWindowInterval[band] = interval;
@@ -342,8 +378,8 @@ public final class ConfigRequest implements Parcelable {
"Invalid argument combination - must have Cluster Low <= Cluster High");
}
- return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh,
- mDiscoveryWindowInterval);
+ return new ConfigRequest(mSupport5gBand, mSupport6gBand, mMasterPreference, mClusterLow,
+ mClusterHigh, mDiscoveryWindowInterval);
}
}
}
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index d97f6fb02ac6..4d92ae174e6d 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -20,12 +20,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.NetworkSpecifier;
+import android.util.CloseGuard;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import dalvik.system.CloseGuard;
-
+import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
/**
@@ -58,7 +58,7 @@ public class DiscoverySession implements AutoCloseable {
/** @hide */
protected boolean mTerminated = false;
- private final CloseGuard mCloseGuard = CloseGuard.get();
+ private final CloseGuard mCloseGuard = new CloseGuard();
/**
* Return the maximum permitted retry count when sending messages using
@@ -108,6 +108,7 @@ public class DiscoverySession implements AutoCloseable {
mTerminated = true;
mMgr.clear();
mCloseGuard.close();
+ Reference.reachabilityFence(this);
}
/**
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index c4b24cfa2394..88f95ad4d495 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -38,14 +38,15 @@ interface IWifiAwareManager
Characteristics getCharacteristics();
// client API
- void connect(in IBinder binder, in String callingPackage, in IWifiAwareEventCallback callback,
- in ConfigRequest configRequest, boolean notifyOnIdentityChanged);
+ void connect(in IBinder binder, in String callingPackage, in String callingFeatureId,
+ in IWifiAwareEventCallback callback, in ConfigRequest configRequest,
+ boolean notifyOnIdentityChanged);
void disconnect(int clientId, in IBinder binder);
- void publish(in String callingPackage, int clientId, in PublishConfig publishConfig,
- in IWifiAwareDiscoverySessionCallback callback);
- void subscribe(in String callingPackage, int clientId, in SubscribeConfig subscribeConfig,
- in IWifiAwareDiscoverySessionCallback callback);
+ void publish(in String callingPackage, in String callingFeatureId, int clientId,
+ in PublishConfig publishConfig, in IWifiAwareDiscoverySessionCallback callback);
+ void subscribe(in String callingPackage, in String callingFeatureId, int clientId,
+ in SubscribeConfig subscribeConfig, in IWifiAwareDiscoverySessionCallback callback);
// session API
void updatePublish(int clientId, int discoverySessionId, in PublishConfig publishConfig);
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index 1886b7ef4c8d..a8844c1d3812 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -19,11 +19,10 @@ package android.net.wifi.aware;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.wifi.util.HexEncoding;
import android.os.Parcel;
import android.os.Parcelable;
-import libcore.util.HexEncoding;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index f0f758170bf2..76780f421af2 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -19,11 +19,10 @@ package android.net.wifi.aware;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.wifi.util.HexEncoding;
import android.os.Parcel;
import android.os.Parcelable;
-import libcore.util.HexEncoding;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index b3b5b2903471..2d3cc1eda643 100644
--- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -18,8 +18,6 @@ package android.net.wifi.aware;
import android.annotation.Nullable;
-import libcore.io.Memory;
-
import java.nio.BufferOverflowException;
import java.nio.ByteOrder;
import java.util.ArrayList;
@@ -266,7 +264,7 @@ public class TlvBufferUtils {
public TlvConstructor putShort(int type, short data) {
checkLength(2);
addHeader(type, 2);
- Memory.pokeShort(mArray, mPosition, data, mByteOrder);
+ pokeShort(mArray, mPosition, data, mByteOrder);
mPosition += 2;
return this;
}
@@ -284,7 +282,7 @@ public class TlvBufferUtils {
public TlvConstructor putInt(int type, int data) {
checkLength(4);
addHeader(type, 4);
- Memory.pokeInt(mArray, mPosition, data, mByteOrder);
+ pokeInt(mArray, mPosition, data, mByteOrder);
mPosition += 4;
return this;
}
@@ -349,14 +347,14 @@ public class TlvBufferUtils {
if (mTypeSize == 1) {
mArray[mPosition] = (byte) type;
} else if (mTypeSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) type, mByteOrder);
+ pokeShort(mArray, mPosition, (short) type, mByteOrder);
}
mPosition += mTypeSize;
if (mLengthSize == 1) {
mArray[mPosition] = (byte) length;
} else if (mLengthSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) length, mByteOrder);
+ pokeShort(mArray, mPosition, (short) length, mByteOrder);
}
mPosition += mLengthSize;
}
@@ -445,7 +443,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing a short from a TLV element of length " + length);
}
- return Memory.peekShort(mRefArray, offset, byteOrder);
+ return peekShort(mRefArray, offset, byteOrder);
}
/**
@@ -460,7 +458,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing an int from a TLV element of length " + length);
}
- return Memory.peekInt(mRefArray, offset, byteOrder);
+ return peekInt(mRefArray, offset, byteOrder);
}
/**
@@ -590,7 +588,7 @@ public class TlvBufferUtils {
if (mTypeSize == 1) {
type = mArray[mOffset];
} else if (mTypeSize == 2) {
- type = Memory.peekShort(mArray, mOffset, mByteOrder);
+ type = peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mTypeSize;
@@ -598,7 +596,7 @@ public class TlvBufferUtils {
if (mLengthSize == 1) {
length = mArray[mOffset];
} else if (mLengthSize == 2) {
- length = Memory.peekShort(mArray, mOffset, mByteOrder);
+ length = peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mLengthSize;
@@ -661,10 +659,56 @@ public class TlvBufferUtils {
if (lengthSize == 1) {
nextTlvIndex += lengthSize + array[nextTlvIndex];
} else {
- nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, byteOrder);
+ nextTlvIndex += lengthSize + peekShort(array, nextTlvIndex, byteOrder);
}
}
return nextTlvIndex == array.length;
}
+
+ private static void pokeShort(byte[] dst, int offset, short value, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ dst[offset++] = (byte) ((value >> 8) & 0xff);
+ dst[offset ] = (byte) ((value >> 0) & 0xff);
+ } else {
+ dst[offset++] = (byte) ((value >> 0) & 0xff);
+ dst[offset ] = (byte) ((value >> 8) & 0xff);
+ }
+ }
+
+ private static void pokeInt(byte[] dst, int offset, int value, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ dst[offset++] = (byte) ((value >> 24) & 0xff);
+ dst[offset++] = (byte) ((value >> 16) & 0xff);
+ dst[offset++] = (byte) ((value >> 8) & 0xff);
+ dst[offset ] = (byte) ((value >> 0) & 0xff);
+ } else {
+ dst[offset++] = (byte) ((value >> 0) & 0xff);
+ dst[offset++] = (byte) ((value >> 8) & 0xff);
+ dst[offset++] = (byte) ((value >> 16) & 0xff);
+ dst[offset ] = (byte) ((value >> 24) & 0xff);
+ }
+ }
+
+ private static short peekShort(byte[] src, int offset, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ return (short) ((src[offset] << 8) | (src[offset + 1] & 0xff));
+ } else {
+ return (short) ((src[offset + 1] << 8) | (src[offset] & 0xff));
+ }
+ }
+
+ private static int peekInt(byte[] src, int offset, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ return ((src[offset++] & 0xff) << 24)
+ | ((src[offset++] & 0xff) << 16)
+ | ((src[offset++] & 0xff) << 8)
+ | ((src[offset ] & 0xff) << 0);
+ } else {
+ return ((src[offset++] & 0xff) << 0)
+ | ((src[offset++] & 0xff) << 8)
+ | ((src[offset++] & 0xff) << 16)
+ | ((src[offset ] & 0xff) << 24);
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
index 3b26c6e558b3..9ae3bd0c93c0 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
@@ -17,12 +17,11 @@
package android.net.wifi.aware;
import android.net.NetworkSpecifier;
+import android.net.wifi.util.HexEncoding;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
-import libcore.util.HexEncoding;
-
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@@ -201,14 +200,14 @@ public class WifiAwareAgentNetworkSpecifier extends NetworkSpecifier implements
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeBlob(mData);
+ dest.writeByteArray(mData);
}
public static final @android.annotation.NonNull Creator<ByteArrayWrapper> CREATOR =
new Creator<ByteArrayWrapper>() {
@Override
public ByteArrayWrapper createFromParcel(Parcel in) {
- return new ByteArrayWrapper(in.readBlob());
+ return new ByteArrayWrapper(in.createByteArray());
}
@Override
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 41a412b1d134..c2ae17c4bdeb 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -19,6 +19,7 @@ package android.net.wifi.aware;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
@@ -26,18 +27,16 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
+import android.net.wifi.util.HexEncoding;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
-import libcore.util.HexEncoding;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -158,7 +157,7 @@ public class WifiAwareManager {
private final Object mLock = new Object(); // lock access to the following vars
/** @hide */
- public WifiAwareManager(Context context, IWifiAwareManager service) {
+ public WifiAwareManager(@NonNull Context context, @NonNull IWifiAwareManager service) {
mContext = context;
mService = service;
}
@@ -268,7 +267,7 @@ public class WifiAwareManager {
try {
Binder binder = new Binder();
- mService.connect(binder, mContext.getOpPackageName(),
+ mService.connect(binder, mContext.getOpPackageName(), mContext.getAttributionTag(),
new WifiAwareEventCallbackProxy(this, looper, binder, attachCallback,
identityChangedListener), configRequest,
identityChangedListener != null);
@@ -299,7 +298,8 @@ public class WifiAwareManager {
}
try {
- mService.publish(mContext.getOpPackageName(), clientId, publishConfig,
+ mService.publish(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId,
+ publishConfig,
new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback,
clientId));
} catch (RemoteException e) {
@@ -336,7 +336,8 @@ public class WifiAwareManager {
}
try {
- mService.subscribe(mContext.getOpPackageName(), clientId, subscribeConfig,
+ mService.subscribe(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId,
+ subscribeConfig,
new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback,
clientId));
} catch (RemoteException e) {
@@ -395,6 +396,17 @@ public class WifiAwareManager {
}
/** @hide */
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+ public void requestMacAddresses(int uid, List<Integer> peerIds,
+ IWifiAwareMacAddressProvider callback) {
+ try {
+ mService.requestMacAddresses(uid, peerIds, callback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId,
@NonNull PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) {
if (VDBG) {
@@ -434,8 +446,7 @@ public class WifiAwareManager {
pmk,
passphrase,
0, // no port info for deprecated IB APIs
- -1, // no transport info for deprecated IB APIs
- Process.myUid());
+ -1); // no transport info for deprecated IB APIs
}
/** @hide */
@@ -475,8 +486,7 @@ public class WifiAwareManager {
pmk,
passphrase,
0, // no port info for OOB APIs
- -1, // no transport protocol info for OOB APIs
- Process.myUid());
+ -1); // no transport protocol info for OOB APIs
}
private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
index e9fb37ea0c29..60fe60438ce7 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
@@ -137,7 +137,7 @@ public final class WifiAwareNetworkInfo implements TransportInfo, Parcelable {
ipv6Addr = Inet6Address.getByAddress(null, addr, ni);
} catch (UnknownHostException e) {
e.printStackTrace();
- return null;
+ return new WifiAwareNetworkInfo(null);
}
return new WifiAwareNetworkInfo(ipv6Addr, port, transportProtocol);
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index 487f3d8746cb..3547750896b3 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -20,11 +20,9 @@ import static android.net.wifi.aware.WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.Process;
import android.text.TextUtils;
import java.util.Arrays;
@@ -145,19 +143,9 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
*/
public final int transportProtocol;
- /**
- * The UID of the process initializing this network specifier. Validated by receiver using
- * checkUidIfNecessary() and is used by satisfiedBy() to determine whether matches the
- * offered network.
- *
- * @hide
- */
- public final int requestorUid;
-
/** @hide */
public WifiAwareNetworkSpecifier(int type, int role, int clientId, int sessionId, int peerId,
- byte[] peerMac, byte[] pmk, String passphrase, int port, int transportProtocol,
- int requestorUid) {
+ byte[] peerMac, byte[] pmk, String passphrase, int port, int transportProtocol) {
this.type = type;
this.role = role;
this.clientId = clientId;
@@ -168,7 +156,6 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
this.passphrase = passphrase;
this.port = port;
this.transportProtocol = transportProtocol;
- this.requestorUid = requestorUid;
}
public static final @android.annotation.NonNull Creator<WifiAwareNetworkSpecifier> CREATOR =
@@ -185,8 +172,7 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
in.createByteArray(), // pmk
in.readString(), // passphrase
in.readInt(), // port
- in.readInt(), // transportProtocol
- in.readInt()); // requestorUid
+ in.readInt()); // transportProtocol
}
@Override
@@ -222,7 +208,6 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
dest.writeString(passphrase);
dest.writeInt(port);
dest.writeInt(transportProtocol);
- dest.writeInt(requestorUid);
}
/** @hide */
@@ -239,7 +224,7 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
@Override
public int hashCode() {
return Objects.hash(type, role, clientId, sessionId, peerId, Arrays.hashCode(peerMac),
- Arrays.hashCode(pmk), passphrase, port, transportProtocol, requestorUid);
+ Arrays.hashCode(pmk), passphrase, port, transportProtocol);
}
/** @hide */
@@ -264,8 +249,7 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
&& Arrays.equals(pmk, lhs.pmk)
&& Objects.equals(passphrase, lhs.passphrase)
&& port == lhs.port
- && transportProtocol == lhs.transportProtocol
- && requestorUid == lhs.requestorUid;
+ && transportProtocol == lhs.transportProtocol;
}
/** @hide */
@@ -284,7 +268,7 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
// masking PII
.append(", passphrase=").append((passphrase == null) ? "<null>" : "<non-null>")
.append(", port=").append(port).append(", transportProtocol=")
- .append(transportProtocol).append(", requestorUid=").append(requestorUid)
+ .append(transportProtocol)
.append("]");
return sb.toString();
}
@@ -329,7 +313,8 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
* Configure the PSK Passphrase for the Wi-Fi Aware connection being requested. This method
* is optional - if not called, then an Open (unencrypted) connection will be created.
*
- * @param pskPassphrase The (optional) passphrase to be used to encrypt the link.
+ * @param pskPassphrase The (optional) passphrase to be used to encrypt the link. Use the
+ * {@link #setPmk(byte[])} to specify a PMK.
* @return the current {@link Builder} builder, enabling chaining of builder
* methods.
*/
@@ -350,9 +335,7 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
* specify a Passphrase.
* @return the current {@link Builder} builder, enabling chaining of builder
* methods.
- * @hide
*/
- @SystemApi
public @NonNull Builder setPmk(@NonNull byte[] pmk) {
if (!WifiAwareUtils.validatePmk(pmk)) {
throw new IllegalArgumentException("PMK must 32 bytes");
@@ -369,7 +352,7 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
* <ul>
* <li>The server device must be the Publisher device!
* <li>The port information can only be specified on secure links, specified using
- * {@link #setPskPassphrase(String)}.
+ * {@link #setPskPassphrase(String)} or {@link #setPmk(byte[])}.
* </ul>
*
* @param port A positive integer indicating the port to be used for communication.
@@ -392,7 +375,7 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
* <ul>
* <li>The server device must be the Publisher device!
* <li>The transport protocol information can only be specified on secure links,
- * specified using {@link #setPskPassphrase(String)}.
+ * specified using {@link #setPskPassphrase(String)} or {@link #setPmk(byte[])}.
* </ul>
* The transport protocol number is assigned by the Internet Assigned Numbers Authority
* (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
@@ -418,7 +401,7 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p> The default builder constructor will initialize a NetworkSpecifier which requests an
* open (non-encrypted) link. To request an encrypted link use the
- * {@link #setPskPassphrase(String)} builder method.
+ * {@link #setPskPassphrase(String)} or {@link #setPmk(byte[])} builder methods.
*
* @return A {@link NetworkSpecifier} to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass
@@ -457,7 +440,7 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
return new WifiAwareNetworkSpecifier(
WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, role,
mDiscoverySession.mClientId, mDiscoverySession.mSessionId, mPeerHandle.peerId,
- null, mPmk, mPskPassphrase, mPort, mTransportProtocol, Process.myUid());
+ null, mPmk, mPskPassphrase, mPort, mTransportProtocol);
}
}
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 3c9781323c07..fe0872caf5f8 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -23,12 +23,12 @@ import android.net.NetworkSpecifier;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
+import android.util.CloseGuard;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import dalvik.system.CloseGuard;
-
+import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
/**
@@ -45,7 +45,7 @@ public class WifiAwareSession implements AutoCloseable {
private final int mClientId;
private boolean mTerminated = true;
- private final CloseGuard mCloseGuard = CloseGuard.get();
+ private final CloseGuard mCloseGuard = new CloseGuard();
/** @hide */
public WifiAwareSession(WifiAwareManager manager, Binder binder, int clientId) {
@@ -80,6 +80,7 @@ public class WifiAwareSession implements AutoCloseable {
mTerminated = true;
mMgr.clear();
mCloseGuard.close();
+ Reference.reachabilityFence(this);
}
/** @hide */
diff --git a/wifi/java/android/net/wifi/hotspot2/ConfigParser.java b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
index e8e873199e17..bb01365d6722 100644
--- a/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
+++ b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
@@ -182,6 +182,12 @@ public final class ConfigParser {
throw new IOException("Passpoint profile missing credential");
}
+ // Don't allow the installer to make changes to the update identifier. This is an
+ // indicator of an R2 (or newer) network.
+ if (config.getUpdateIdentifier() != Integer.MIN_VALUE) {
+ config.setUpdateIdentifier(Integer.MIN_VALUE);
+ }
+
// Parse CA (Certificate Authority) certificate.
byte[] caCertData = mimeParts.get(TYPE_CA_CERT);
if (caCertData != null) {
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index a32bd547e1e2..f0a06076961c 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -19,7 +19,6 @@ package android.net.wifi.hotspot2;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.wifi.WifiSsid;
import android.os.Bundle;
@@ -27,6 +26,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -85,15 +85,16 @@ public final class OsuProvider implements Parcelable {
*/
private final List<Integer> mMethodList;
- /**
- * Icon data for the OSU (Online Sign-Up) provider.
- */
- private final Icon mIcon;
+ /** @hide */
+ public OsuProvider(String osuSsid, Map<String, String> friendlyNames,
+ String serviceDescription, Uri serverUri, String nai, List<Integer> methodList) {
+ this(WifiSsid.createFromByteArray(osuSsid.getBytes(StandardCharsets.UTF_8)),
+ friendlyNames, serviceDescription, serverUri, nai, methodList);
+ }
/** @hide */
public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames,
- String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
- Icon icon) {
+ String serviceDescription, Uri serverUri, String nai, List<Integer> methodList) {
mOsuSsid = osuSsid;
mFriendlyNames = friendlyNames;
mServiceDescription = serviceDescription;
@@ -104,7 +105,6 @@ public final class OsuProvider implements Parcelable {
} else {
mMethodList = new ArrayList<>(methodList);
}
- mIcon = icon;
}
/**
@@ -121,7 +121,6 @@ public final class OsuProvider implements Parcelable {
mServerUri = null;
mNetworkAccessIdentifier = null;
mMethodList = new ArrayList<>();
- mIcon = null;
return;
}
@@ -135,7 +134,6 @@ public final class OsuProvider implements Parcelable {
} else {
mMethodList = new ArrayList<>(source.mMethodList);
}
- mIcon = source.mIcon;
}
/** @hide */
@@ -196,11 +194,6 @@ public final class OsuProvider implements Parcelable {
return mMethodList;
}
- /** @hide */
- public Icon getIcon() {
- return mIcon;
- }
-
@Override
public int describeContents() {
return 0;
@@ -213,7 +206,6 @@ public final class OsuProvider implements Parcelable {
dest.writeParcelable(mServerUri, flags);
dest.writeString(mNetworkAccessIdentifier);
dest.writeList(mMethodList);
- dest.writeParcelable(mIcon, flags);
Bundle bundle = new Bundle();
bundle.putSerializable("friendlyNameMap", (HashMap<String, String>) mFriendlyNames);
dest.writeBundle(bundle);
@@ -228,21 +220,16 @@ public final class OsuProvider implements Parcelable {
return false;
}
OsuProvider that = (OsuProvider) thatObject;
- return (mOsuSsid == null ? that.mOsuSsid == null : mOsuSsid.equals(that.mOsuSsid))
- && (mFriendlyNames == null) ? that.mFriendlyNames == null
- : mFriendlyNames.equals(that.mFriendlyNames)
+ return Objects.equals(mOsuSsid, that.mOsuSsid)
+ && Objects.equals(mFriendlyNames, that.mFriendlyNames)
&& TextUtils.equals(mServiceDescription, that.mServiceDescription)
- && (mServerUri == null ? that.mServerUri == null
- : mServerUri.equals(that.mServerUri))
+ && Objects.equals(mServerUri, that.mServerUri)
&& TextUtils.equals(mNetworkAccessIdentifier, that.mNetworkAccessIdentifier)
- && (mMethodList == null ? that.mMethodList == null
- : mMethodList.equals(that.mMethodList))
- && (mIcon == null ? that.mIcon == null : mIcon.sameAs(that.mIcon));
+ && Objects.equals(mMethodList, that.mMethodList);
}
@Override
public int hashCode() {
- // mIcon is not hashable, skip the variable.
return Objects.hash(mOsuSsid, mServiceDescription, mFriendlyNames,
mServerUri, mNetworkAccessIdentifier, mMethodList);
}
@@ -255,8 +242,7 @@ public final class OsuProvider implements Parcelable {
+ " mServiceDescription=" + mServiceDescription
+ " mServerUri=" + mServerUri
+ " mNetworkAccessIdentifier=" + mNetworkAccessIdentifier
- + " mMethodList=" + mMethodList
- + " mIcon=" + mIcon;
+ + " mMethodList=" + mMethodList;
}
public static final @android.annotation.NonNull Creator<OsuProvider> CREATOR =
@@ -269,12 +255,11 @@ public final class OsuProvider implements Parcelable {
String nai = in.readString();
List<Integer> methodList = new ArrayList<>();
in.readList(methodList, null);
- Icon icon = in.readParcelable(null);
Bundle bundle = in.readBundle();
Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable(
"friendlyNameMap");
return new OsuProvider(osuSsid, friendlyNamesMap, serviceDescription,
- serverUri, nai, methodList, icon);
+ serverUri, nai, methodList);
}
@Override
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 9095b5d927a2..d1d1780a25fd 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -16,6 +16,13 @@
package android.net.wifi.hotspot2;
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
+import static android.net.wifi.WifiConfiguration.MeteredOverride;
+
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.wifi.hotspot2.pps.Credential;
import android.net.wifi.hotspot2.pps.HomeSp;
import android.net.wifi.hotspot2.pps.Policy;
@@ -23,6 +30,7 @@ import android.net.wifi.hotspot2.pps.UpdateParameter;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -64,6 +72,7 @@ public final class PasspointConfiguration implements Parcelable {
* Configurations under HomeSp subtree.
*/
private HomeSp mHomeSp = null;
+
/**
* Set the Home SP (Service Provider) information.
*
@@ -78,6 +87,29 @@ public final class PasspointConfiguration implements Parcelable {
public HomeSp getHomeSp() { return mHomeSp; }
/**
+ * Configurations under AAAServerTrustedNames subtree.
+ */
+ private String[] mAaaServerTrustedNames = null;
+ /**
+ * Set the AAA server trusted names information.
+ *
+ * @param aaaServerTrustedNames The AAA server trusted names information to set to
+ * @hide
+ */
+ public void setAaaServerTrustedNames(@Nullable String[] aaaServerTrustedNames) {
+ mAaaServerTrustedNames = aaaServerTrustedNames;
+ }
+ /**
+ * Get the AAA server trusted names information.
+ *
+ * @return AAA server trusted names information
+ * @hide
+ */
+ public @Nullable String[] getAaaServerTrustedNames() {
+ return mAaaServerTrustedNames;
+ }
+
+ /**
* Configurations under Credential subtree.
*/
private Credential mCredential = null;
@@ -216,18 +248,22 @@ public final class PasspointConfiguration implements Parcelable {
*
* Use Long.MIN_VALUE to indicate unset value.
*/
- private long mSubscriptionExpirationTimeInMillis = Long.MIN_VALUE;
+ private long mSubscriptionExpirationTimeMillis = Long.MIN_VALUE;
/**
* @hide
*/
public void setSubscriptionExpirationTimeInMillis(long subscriptionExpirationTimeInMillis) {
- mSubscriptionExpirationTimeInMillis = subscriptionExpirationTimeInMillis;
+ mSubscriptionExpirationTimeMillis = subscriptionExpirationTimeInMillis;
}
/**
- * @hide
+ * Utility method to get the time this subscription will expire. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * @return The time this subscription will expire, or Long.MIN_VALUE to indicate unset value
*/
- public long getSubscriptionExpirationTimeInMillis() {
- return mSubscriptionExpirationTimeInMillis;
+ @CurrentTimeMillisLong
+ public long getSubscriptionExpirationTimeMillis() {
+ return mSubscriptionExpirationTimeMillis;
}
/**
@@ -370,6 +406,131 @@ public final class PasspointConfiguration implements Parcelable {
}
/**
+ * The carrier ID identifies the operator who provides this network configuration.
+ * see {@link TelephonyManager#getSimCarrierId()}
+ */
+ private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
+
+ /**
+ * Set the carrier ID associated with current configuration.
+ * @param carrierId {@code mCarrierId}
+ * @hide
+ */
+ public void setCarrierId(int carrierId) {
+ this.mCarrierId = carrierId;
+ }
+
+ /**
+ * Get the carrier ID associated with current configuration.
+ * @return {@code mCarrierId}
+ * @hide
+ */
+ public int getCarrierId() {
+ return mCarrierId;
+ }
+
+ /**
+ * The auto-join configuration specifies whether or not the Passpoint Configuration is
+ * considered for auto-connection. If true then yes, if false then it isn't considered as part
+ * of auto-connection - but can still be manually connected to.
+ */
+ private boolean mIsAutojoinEnabled = true;
+
+ /**
+ * The mac randomization setting specifies whether a randomized or device MAC address will
+ * be used to connect to the passpoint network. If true, a randomized MAC will be used.
+ * Otherwise, the device MAC address will be used.
+ */
+ private boolean mIsMacRandomizationEnabled = true;
+
+ /**
+ * Indicates if the end user has expressed an explicit opinion about the
+ * meteredness of this network, such as through the Settings app.
+ * This value is one of {@link #METERED_OVERRIDE_NONE}, {@link #METERED_OVERRIDE_METERED},
+ * or {@link #METERED_OVERRIDE_NOT_METERED}.
+ * <p>
+ * This should always override any values from {@link WifiInfo#getMeteredHint()}.
+ *
+ * By default this field is set to {@link #METERED_OVERRIDE_NONE}.
+ */
+ private int mMeteredOverride = METERED_OVERRIDE_NONE;
+
+ /**
+ * Configures the auto-association status of this Passpoint configuration. A value of true
+ * indicates that the configuration will be considered for auto-connection, a value of false
+ * indicates that only manual connection will work - the framework will not auto-associate to
+ * this Passpoint network.
+ *
+ * @param autojoinEnabled true to be considered for framework auto-connection, false otherwise.
+ * @hide
+ */
+ public void setAutojoinEnabled(boolean autojoinEnabled) {
+ mIsAutojoinEnabled = autojoinEnabled;
+ }
+
+ /**
+ * Configures the MAC randomization setting for this Passpoint configuration.
+ * If set to true, the framework will use a randomized MAC address to connect to this Passpoint
+ * network. Otherwise, the framework will use the device MAC address.
+ *
+ * @param enabled true to use randomized MAC address, false to use device MAC address.
+ * @hide
+ */
+ public void setMacRandomizationEnabled(boolean enabled) {
+ mIsMacRandomizationEnabled = enabled;
+ }
+
+ /**
+ * Sets the metered override setting for this Passpoint configuration.
+ *
+ * @param meteredOverride One of the values in {@link MeteredOverride}
+ * @hide
+ */
+ public void setMeteredOverride(@MeteredOverride int meteredOverride) {
+ mMeteredOverride = meteredOverride;
+ }
+
+ /**
+ * Indicates whether the Passpoint configuration may be auto-connected to by the framework. A
+ * value of true indicates that auto-connection can happen, a value of false indicates that it
+ * cannot. However, even when auto-connection is not possible manual connection by the user is
+ * possible.
+ *
+ * @return the auto-join configuration: true for auto-connection (or join) enabled, false
+ * otherwise.
+ * @hide
+ */
+ @SystemApi
+ public boolean isAutojoinEnabled() {
+ return mIsAutojoinEnabled;
+ }
+
+ /**
+ * Indicates whether the user chose this configuration to be treated as metered or not.
+ *
+ * @return One of the values in {@link MeteredOverride}
+ * @hide
+ */
+ @SystemApi
+ @MeteredOverride
+ public int getMeteredOverride() {
+ return mMeteredOverride;
+ }
+
+ /**
+ * Indicates whether a randomized MAC address or device MAC address will be used for
+ * connections to this Passpoint network. If true, a randomized MAC address will be used.
+ * Otherwise, the device MAC address will be used.
+ *
+ * @return true for MAC randomization enabled. False for disabled.
+ * @hide
+ */
+ @SystemApi
+ public boolean isMacRandomizationEnabled() {
+ return mIsMacRandomizationEnabled;
+ }
+
+ /**
* Constructor for creating PasspointConfiguration with default values.
*/
public PasspointConfiguration() {}
@@ -402,13 +563,18 @@ public final class PasspointConfiguration implements Parcelable {
mUpdateIdentifier = source.mUpdateIdentifier;
mCredentialPriority = source.mCredentialPriority;
mSubscriptionCreationTimeInMillis = source.mSubscriptionCreationTimeInMillis;
- mSubscriptionExpirationTimeInMillis = source.mSubscriptionExpirationTimeInMillis;
+ mSubscriptionExpirationTimeMillis = source.mSubscriptionExpirationTimeMillis;
mSubscriptionType = source.mSubscriptionType;
mUsageLimitDataLimit = source.mUsageLimitDataLimit;
mUsageLimitStartTimeInMillis = source.mUsageLimitStartTimeInMillis;
mUsageLimitTimeLimitInMinutes = source.mUsageLimitTimeLimitInMinutes;
mUsageLimitUsageTimePeriodInMinutes = source.mUsageLimitUsageTimePeriodInMinutes;
mServiceFriendlyNames = source.mServiceFriendlyNames;
+ mAaaServerTrustedNames = source.mAaaServerTrustedNames;
+ mCarrierId = source.mCarrierId;
+ mIsAutojoinEnabled = source.mIsAutojoinEnabled;
+ mIsMacRandomizationEnabled = source.mIsMacRandomizationEnabled;
+ mMeteredOverride = source.mMeteredOverride;
}
@Override
@@ -426,16 +592,21 @@ public final class PasspointConfiguration implements Parcelable {
dest.writeInt(mUpdateIdentifier);
dest.writeInt(mCredentialPriority);
dest.writeLong(mSubscriptionCreationTimeInMillis);
- dest.writeLong(mSubscriptionExpirationTimeInMillis);
+ dest.writeLong(mSubscriptionExpirationTimeMillis);
dest.writeString(mSubscriptionType);
dest.writeLong(mUsageLimitUsageTimePeriodInMinutes);
dest.writeLong(mUsageLimitStartTimeInMillis);
dest.writeLong(mUsageLimitDataLimit);
dest.writeLong(mUsageLimitTimeLimitInMinutes);
+ dest.writeStringArray(mAaaServerTrustedNames);
Bundle bundle = new Bundle();
bundle.putSerializable("serviceFriendlyNames",
(HashMap<String, String>) mServiceFriendlyNames);
dest.writeBundle(bundle);
+ dest.writeInt(mCarrierId);
+ dest.writeBoolean(mIsAutojoinEnabled);
+ dest.writeBoolean(mIsMacRandomizationEnabled);
+ dest.writeInt(mMeteredOverride);
}
@Override
@@ -448,6 +619,8 @@ public final class PasspointConfiguration implements Parcelable {
}
PasspointConfiguration that = (PasspointConfiguration) thatObject;
return (mHomeSp == null ? that.mHomeSp == null : mHomeSp.equals(that.mHomeSp))
+ && (mAaaServerTrustedNames == null ? that.mAaaServerTrustedNames == null
+ : Arrays.equals(mAaaServerTrustedNames, that.mAaaServerTrustedNames))
&& (mCredential == null ? that.mCredential == null
: mCredential.equals(that.mCredential))
&& (mPolicy == null ? that.mPolicy == null : mPolicy.equals(that.mPolicy))
@@ -457,12 +630,16 @@ public final class PasspointConfiguration implements Parcelable {
&& mUpdateIdentifier == that.mUpdateIdentifier
&& mCredentialPriority == that.mCredentialPriority
&& mSubscriptionCreationTimeInMillis == that.mSubscriptionCreationTimeInMillis
- && mSubscriptionExpirationTimeInMillis == that.mSubscriptionExpirationTimeInMillis
+ && mSubscriptionExpirationTimeMillis == that.mSubscriptionExpirationTimeMillis
&& TextUtils.equals(mSubscriptionType, that.mSubscriptionType)
&& mUsageLimitUsageTimePeriodInMinutes == that.mUsageLimitUsageTimePeriodInMinutes
&& mUsageLimitStartTimeInMillis == that.mUsageLimitStartTimeInMillis
&& mUsageLimitDataLimit == that.mUsageLimitDataLimit
&& mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
+ && mCarrierId == that.mCarrierId
+ && mIsAutojoinEnabled == that.mIsAutojoinEnabled
+ && mIsMacRandomizationEnabled == that.mIsMacRandomizationEnabled
+ && mMeteredOverride == that.mMeteredOverride
&& (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
: mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
}
@@ -471,9 +648,10 @@ public final class PasspointConfiguration implements Parcelable {
public int hashCode() {
return Objects.hash(mHomeSp, mCredential, mPolicy, mSubscriptionUpdate, mTrustRootCertList,
mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis,
- mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes,
+ mSubscriptionExpirationTimeMillis, mUsageLimitUsageTimePeriodInMinutes,
mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
- mServiceFriendlyNames);
+ mServiceFriendlyNames, mCarrierId, mIsAutojoinEnabled, mIsMacRandomizationEnabled,
+ mMeteredOverride);
}
@Override
@@ -485,14 +663,16 @@ public final class PasspointConfiguration implements Parcelable {
mSubscriptionCreationTimeInMillis != Long.MIN_VALUE
? new Date(mSubscriptionCreationTimeInMillis) : "Not specified").append("\n");
builder.append("SubscriptionExpirationTime: ").append(
- mSubscriptionExpirationTimeInMillis != Long.MIN_VALUE
- ? new Date(mSubscriptionExpirationTimeInMillis) : "Not specified").append("\n");
+ mSubscriptionExpirationTimeMillis != Long.MIN_VALUE
+ ? new Date(mSubscriptionExpirationTimeMillis) : "Not specified").append("\n");
builder.append("UsageLimitStartTime: ").append(mUsageLimitStartTimeInMillis != Long.MIN_VALUE
? new Date(mUsageLimitStartTimeInMillis) : "Not specified").append("\n");
builder.append("UsageTimePeriod: ").append(mUsageLimitUsageTimePeriodInMinutes)
.append("\n");
builder.append("UsageLimitDataLimit: ").append(mUsageLimitDataLimit).append("\n");
builder.append("UsageLimitTimeLimit: ").append(mUsageLimitTimeLimitInMinutes).append("\n");
+ builder.append("Provisioned by a subscription server: ")
+ .append(isOsuProvisioned() ? "Yes" : "No").append("\n");
if (mHomeSp != null) {
builder.append("HomeSP Begin ---\n");
builder.append(mHomeSp);
@@ -517,9 +697,17 @@ public final class PasspointConfiguration implements Parcelable {
builder.append("TrustRootCertServers: ").append(mTrustRootCertList.keySet())
.append("\n");
}
+ if (mAaaServerTrustedNames != null) {
+ builder.append("AAAServerTrustedNames: ")
+ .append(String.join(";", mAaaServerTrustedNames)).append("\n");
+ }
if (mServiceFriendlyNames != null) {
builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames);
}
+ builder.append("CarrierId:" + mCarrierId);
+ builder.append("IsAutojoinEnabled:" + mIsAutojoinEnabled);
+ builder.append("mIsMacRandomizationEnabled:" + mIsMacRandomizationEnabled);
+ builder.append("mMeteredOverride:" + mMeteredOverride);
return builder.toString();
}
@@ -534,7 +722,7 @@ public final class PasspointConfiguration implements Parcelable {
if (mSubscriptionUpdate != null && !mSubscriptionUpdate.validate()) {
return false;
}
- return validateForCommonR1andR2(true);
+ return validateForCommonR1andR2();
}
/**
@@ -553,17 +741,17 @@ public final class PasspointConfiguration implements Parcelable {
if (mSubscriptionUpdate == null || !mSubscriptionUpdate.validate()) {
return false;
}
- return validateForCommonR1andR2(false);
+ return validateForCommonR1andR2();
}
- private boolean validateForCommonR1andR2(boolean isR1) {
+ private boolean validateForCommonR1andR2() {
// Required: PerProviderSubscription/<X+>/HomeSP
if (mHomeSp == null || !mHomeSp.validate()) {
return false;
}
// Required: PerProviderSubscription/<X+>/Credential
- if (mCredential == null || !mCredential.validate(isR1)) {
+ if (mCredential == null || !mCredential.validate()) {
return false;
}
@@ -619,10 +807,15 @@ public final class PasspointConfiguration implements Parcelable {
config.setUsageLimitStartTimeInMillis(in.readLong());
config.setUsageLimitDataLimit(in.readLong());
config.setUsageLimitTimeLimitInMinutes(in.readLong());
+ config.setAaaServerTrustedNames(in.createStringArray());
Bundle bundle = in.readBundle();
Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable(
"serviceFriendlyNames");
config.setServiceFriendlyNames(friendlyNamesMap);
+ config.mCarrierId = in.readInt();
+ config.mIsAutojoinEnabled = in.readBoolean();
+ config.mIsMacRandomizationEnabled = in.readBoolean();
+ config.mMeteredOverride = in.readInt();
return config;
}
@@ -695,4 +888,34 @@ public final class PasspointConfiguration implements Parcelable {
}
return true;
}
+
+ /**
+ * Indicates if the Passpoint Configuration was provisioned by a subscription (OSU) server,
+ * which means that it's an R2 (or R3) profile.
+ *
+ * @return true if the Passpoint Configuration was provisioned by a subscription server.
+ */
+ public boolean isOsuProvisioned() {
+ return getUpdateIdentifier() != Integer.MIN_VALUE;
+ }
+
+ /**
+ * Get a unique identifier for a PasspointConfiguration object. The identifier depends on the
+ * configuration that identify the service provider under the HomeSp subtree, and on the
+ * credential configuration under the Credential subtree.
+ * The method throws an {@link IllegalStateException} if the configuration under HomeSp subtree
+ * or the configuration under Credential subtree are not initialized.
+ *
+ * @return A unique identifier
+ */
+ public @NonNull String getUniqueId() {
+ if (mCredential == null || mHomeSp == null || TextUtils.isEmpty(mHomeSp.getFqdn())) {
+ throw new IllegalStateException("Credential or HomeSP are not initialized");
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format("%s_%x%x", mHomeSp.getFqdn(), mHomeSp.getUniqueId(),
+ mCredential.getUniqueId()));
+ return sb.toString();
+ }
}
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
index 984cf7d62aa5..ae60ed47fd6a 100644
--- a/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
@@ -25,6 +25,8 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+import org.xml.sax.SAXException;
+
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
@@ -36,8 +38,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.xml.sax.SAXException;
-
/**
* Utility class for converting OMA-DM (Open Mobile Alliance's Device Management)
* PPS-MO (PerProviderSubscription Management Object) XML tree to a
@@ -147,6 +147,47 @@ public final class PpsMoParser {
private static final String NODE_EXTENSION = "Extension";
/**
+ * Fields under Extension/Android subtree.
+ */
+ /*
+ * This node is used to put Android specific extension nodes and must be put
+ * under "Extension" node. Nodes with unknown names are allowed under this subtree.
+ * If there is any new node added in later release, it won't break older release parsing.
+ * <p>
+ * Ex:
+ * <Node>
+ * <NodeName>Extension</NodeName>
+ * <Node>
+ * <NodeName>Android</NodeName>
+ * <Node>
+ * <NodeName>AndroidSpecificAttribute</NodeName>
+ * <Value>AndroidSpecificValue</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>AndroidSpecificAttribute2</NodeName>
+ * <Value>AndroidSpecificValue2</Value>
+ * </Node>
+ * </Node>
+ * </Node>
+ */
+ private static final String NODE_VENDOR_ANDROID = "Android";
+ /*
+ * This node describes AAA server trusted names. The trusted name must be put in
+ * a leaf named "FQDN". More than one trusted names can be provided by using
+ * semicolons to separate the strings (e.g., example.org;example.com).
+ * <p>
+ * Ex:
+ * <Node>
+ * <NodeName>AAAServerTrustedNames</NodeName>
+ * <Node>
+ * <NodeName>FQDN</NodeName>
+ * <Value>trusted.com;auth.net</Value>
+ * </Node>
+ * <Node>
+ */
+ private static final String NODE_AAA_SERVER_TRUSTED_NAMES = "AAAServerTrustedNames";
+
+ /**
* Fields under HomeSP subtree.
*/
private static final String NODE_HOMESP = "HomeSP";
@@ -633,7 +674,7 @@ public final class PpsMoParser {
break;
case NODE_EXTENSION:
// All vendor specific information will be under this node.
- Log.d(TAG, "Ignore Extension node for vendor specific information");
+ parseExtension(child, config);
break;
default:
throw new ParsingException("Unknown node: " + child.getName());
@@ -896,7 +937,7 @@ public final class PpsMoParser {
*/
private static Credential parseCredential(PPSNode node) throws ParsingException {
if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for HomeSP");
+ throw new ParsingException("Leaf node not expected for Credential");
}
Credential credential = new Credential();
@@ -968,8 +1009,8 @@ public final class PpsMoParser {
parseEAPMethod(child, userCred);
break;
default:
- throw new ParsingException("Unknown node under UsernamPassword: " +
- child.getName());
+ throw new ParsingException("Unknown node under UsernamePassword: "
+ + child.getName());
}
}
return userCred;
@@ -1024,7 +1065,7 @@ public final class PpsMoParser {
private static Credential.CertificateCredential parseCertificateCredential(PPSNode node)
throws ParsingException {
if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for DigitalCertificate");
+ throw new ParsingException("Leaf node not expected for CertificateCredential");
}
Credential.CertificateCredential certCred = new Credential.CertificateCredential();
@@ -1037,8 +1078,8 @@ public final class PpsMoParser {
certCred.setCertSha256Fingerprint(parseHexString(getPpsNodeValue(child)));
break;
default:
- throw new ParsingException("Unknown node under DigitalCertificate: " +
- child.getName());
+ throw new ParsingException("Unknown node under CertificateCredential: "
+ + child.getName());
}
}
return certCred;
@@ -1055,7 +1096,7 @@ public final class PpsMoParser {
private static Credential.SimCredential parseSimCredential(PPSNode node)
throws ParsingException {
if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for SIM");
+ throw new ParsingException("Leaf node not expected for SimCredential");
}
Credential.SimCredential simCred = new Credential.SimCredential();
@@ -1068,7 +1109,8 @@ public final class PpsMoParser {
simCred.setEapType(parseInteger(getPpsNodeValue(child)));
break;
default:
- throw new ParsingException("Unknown node under SIM: " + child.getName());
+ throw new ParsingException("Unknown node under SimCredential: "
+ + child.getName());
}
}
return simCred;
@@ -1572,6 +1614,92 @@ public final class PpsMoParser {
}
/**
+ * Parse configurations under PerProviderSubscription/Extension/Android/AAAServerTrustedNames
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Extension/Android/AAAServerTrustedNames subtree
+ * @return String[] list of trusted name
+ * @throws ParsingException
+ */
+ private static String[] parseAaaServerTrustedNames(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for AAAServerTrustedNames instance");
+ }
+ String fqdnListStr = null;
+ String[] fqdnListArray = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_FQDN:
+ fqdnListStr = getPpsNodeValue(child);
+ fqdnListArray = fqdnListStr.split(";");
+ break;
+ default:
+ throw new ParsingException(
+ "Unknown node under AAAServerTrustedNames instance: "
+ + child.getName());
+ }
+ }
+ if (fqdnListArray == null) {
+ throw new ParsingException("AAAServerTrustedNames instance missing FQDN field");
+ }
+
+ return fqdnListArray;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Extension/Android subtree.
+ *
+ * @param node PPSNode representing the root of PerProviderSubscription/Extension
+ * subtree
+ * @param config Instance of {@link PasspointConfiguration}
+ * @throws ParsingException
+ */
+ private static void parseVendorAndroidExtension(PPSNode node, PasspointConfiguration config)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for AndroidExtension");
+ }
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_AAA_SERVER_TRUSTED_NAMES:
+ config.setAaaServerTrustedNames(parseAaaServerTrustedNames(child));
+ break;
+ default:
+ // Don't raise an exception for unknown nodes to avoid breaking old release
+ Log.w(TAG, "Unknown node under Android Extension: " + child.getName());
+ }
+ }
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Extension subtree.
+ *
+ * @param node PPSNode representing the root of PerProviderSubscription/Extension
+ * subtree
+ * @param config Instance of {@link PasspointConfiguration}
+ * @throws ParsingException
+ */
+ private static void parseExtension(PPSNode node, PasspointConfiguration config)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for Extension");
+ }
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_VENDOR_ANDROID:
+ parseVendorAndroidExtension(child, config);
+ break;
+ default:
+ // Unknown nodes under Extension won't raise exception.
+ // This allows adding new nodes in the future and
+ // won't break older release.
+ Log.w(TAG, "Unknown node under Extension: " + child.getName());
+ }
+ }
+ }
+
+ /**
* Convert a hex string to a byte array.
*
* @param str String containing hex values
@@ -1580,7 +1708,8 @@ public final class PpsMoParser {
*/
private static byte[] parseHexString(String str) throws ParsingException {
if ((str.length() & 1) == 1) {
- throw new ParsingException("Odd length hex string: " + str.length());
+ throw new ParsingException("Odd length hex string: " + str + ", length: "
+ + str.length());
}
byte[] result = new byte[str.length() / 2];
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 9409c03c614d..fa806e7797cd 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -738,7 +738,16 @@ public final class Credential implements Parcelable {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
- builder.append("IMSI: ").append(mImsi).append("\n");
+ String imsi;
+ if (mImsi != null) {
+ if (mImsi.length() > 6 && mImsi.charAt(6) != '*') {
+ // Truncate the full IMSI from the log
+ imsi = mImsi.substring(0, 6) + "****";
+ } else {
+ imsi = mImsi;
+ }
+ builder.append("IMSI: ").append(imsi).append("\n");
+ }
builder.append("EAPType: ").append(mEapType).append("\n");
return builder.toString();
}
@@ -1020,6 +1029,17 @@ public final class Credential implements Parcelable {
Arrays.hashCode(mClientCertificateChain));
}
+ /**
+ * Get a unique identifier for Credential. This identifier depends only on items that remain
+ * constant throughout the lifetime of a subscription's credentials.
+ *
+ * @hide
+ * @return a Unique identifier for a Credential object
+ */
+ public int getUniqueId() {
+ return Objects.hash(mUserCredential, mCertCredential, mSimCredential, mRealm);
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
@@ -1050,11 +1070,10 @@ public final class Credential implements Parcelable {
/**
* Validate the configuration data.
*
- * @param isR1 {@code true} if the configuration is for R1
* @return true on success or false on failure
* @hide
*/
- public boolean validate(boolean isR1) {
+ public boolean validate() {
if (TextUtils.isEmpty(mRealm)) {
Log.d(TAG, "Missing realm");
return false;
@@ -1067,11 +1086,11 @@ public final class Credential implements Parcelable {
// Verify the credential.
if (mUserCredential != null) {
- if (!verifyUserCredential(isR1)) {
+ if (!verifyUserCredential()) {
return false;
}
} else if (mCertCredential != null) {
- if (!verifyCertCredential(isR1)) {
+ if (!verifyCertCredential()) {
return false;
}
} else if (mSimCredential != null) {
@@ -1112,11 +1131,11 @@ public final class Credential implements Parcelable {
/**
* Verify user credential.
+ * If no CA certificate is provided, then the system uses the CAs in the trust store.
*
- * @param isR1 {@code true} if credential is for R1
* @return true if user credential is valid, false otherwise.
*/
- private boolean verifyUserCredential(boolean isR1) {
+ private boolean verifyUserCredential() {
if (mUserCredential == null) {
Log.d(TAG, "Missing user credential");
return false;
@@ -1129,23 +1148,17 @@ public final class Credential implements Parcelable {
return false;
}
- // CA certificate is required for R1 Passpoint profile.
- // For R2, it is downloaded using cert URL provided in PPS MO after validation completes.
- if (isR1 && mCaCertificates == null) {
- Log.d(TAG, "Missing CA Certificate for user credential");
- return false;
- }
return true;
}
/**
* Verify certificate credential, which is used for EAP-TLS. This will verify
* that the necessary client key and certificates are provided.
+ * If no CA certificate is provided, then the system uses the CAs in the trust store.
*
- * @param isR1 {@code true} if credential is for R1
* @return true if certificate credential is valid, false otherwise.
*/
- private boolean verifyCertCredential(boolean isR1) {
+ private boolean verifyCertCredential() {
if (mCertCredential == null) {
Log.d(TAG, "Missing certificate credential");
return false;
@@ -1159,13 +1172,6 @@ public final class Credential implements Parcelable {
return false;
}
- // Verify required key and certificates for certificate credential.
- // CA certificate is required for R1 Passpoint profile.
- // For R2, it is downloaded using cert URL provided in PPS MO after validation completes.
- if (isR1 && mCaCertificates == null) {
- Log.d(TAG, "Missing CA Certificate for certificate credential");
- return false;
- }
if (mClientPrivateKey == null) {
Log.d(TAG, "Missing client private key for certificate credential");
return false;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 49a76c33d209..224c4bed9d5b 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -16,8 +16,8 @@
package android.net.wifi.hotspot2.pps;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
@@ -299,10 +299,26 @@ public final class HomeSp implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mFqdn, mFriendlyName, mIconUrl, mHomeNetworkIds, mMatchAllOis,
- mMatchAnyOis, mOtherHomePartners, mRoamingConsortiumOis);
+ return Objects.hash(mFqdn, mFriendlyName, mIconUrl,
+ mHomeNetworkIds, Arrays.hashCode(mMatchAllOis),
+ Arrays.hashCode(mMatchAnyOis), Arrays.hashCode(mOtherHomePartners),
+ Arrays.hashCode(mRoamingConsortiumOis));
}
+ /**
+ * Get a unique identifier for HomeSp. This identifier depends only on items that remain
+ * constant throughout the lifetime of a subscription.
+ *
+ * @hide
+ * @return a Unique identifier for a HomeSp object
+ */
+ public int getUniqueId() {
+ return Objects.hash(mFqdn, mFriendlyName, mHomeNetworkIds, Arrays.hashCode(mMatchAllOis),
+ Arrays.hashCode(mMatchAnyOis), Arrays.hashCode(mOtherHomePartners),
+ Arrays.hashCode(mRoamingConsortiumOis));
+ }
+
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
deleted file mode 100644
index 701db479076a..000000000000
--- a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.hotspot2.pps;
-
-parcelable UpdateParameter;
diff --git a/wifi/java/android/net/wifi/migration_samples/README.txt b/wifi/java/android/net/wifi/migration_samples/README.txt
new file mode 100644
index 000000000000..264debaa51f9
--- /dev/null
+++ b/wifi/java/android/net/wifi/migration_samples/README.txt
@@ -0,0 +1,35 @@
+This folder contains sample files for each of the 4 XML Wi-Fi config store files in Android 11 AOSP.
+OEMs can use these files as reference for converting their previous customized
+formats into the AOSP format. The conversion logic needs to be written in
+WifiMigration.java class, i.e each OEM needs to modify
+WifiMigration.convertAndRetrieveSharedConfigStoreFile() and the
+WifiMigration.convertAndRetrieveUserConfigStoreFile() methods.
+
+The 4 files are:
+
+Shared files
+============
+1) WifiConfigStore.xml - General storage for shared configurations. Includes
+user's saved Wi-Fi networks.
+AOSP Path in Android 10: /data/misc/wifi/WifiConfigStore.xml
+AOSP Path in Android 11: /data/misc/apexdata/com.android/wifi/WifiConfigStore.xml
+Sample File (in this folder): Shared_WifiConfigStore.xml
+
+2) WifiConfigStoreSoftAp.xml - Storage for user's softap/tethering configuration.
+AOSP Path in Android 10: /data/misc/wifi/softap.conf.
+Note: Was key/value format in Android 10. Conversion to XML done in SoftApConfToXmlMigrationUtil.java.
+AOSP Path in Android 11: /data/misc/apexdata/com.android/wifi/WifiConfigStore.xml
+Sample File (in this folder): Shared_WifiConfigStoreSoftAp.xml
+
+User specific files
+==================
+3) WifiConfigStore.xml - General storage for user specific configurations. Includes
+user's saved passpoint networks, Wi-Fi network request approvals, etc.
+AOSP Path in Android 10: /data/misc_ce/<userId>/wifi/WifiConfigStore.xml
+AOSP Path in Android 11: /data/misc_ce/<userId>/apexdata/com.android/wifi/WifiConfigStore.xml
+Sample File (in this folder): User_WifiConfigStore.xml
+
+4) WifiConfigStoreNetworkSuggestions.xml - Storage for app installed network suggestions.
+AOSP Path in Android 10: /data/misc_ce/<userId>/wifi/WifiConfigStoreNetworkSuggestions.xml
+AOSP Path in Android 11: /data/misc_ce/<userId>/apexdata/com.android/wifi/WifiConfigStoreNetworkSuggestions.xml
+Sample File (in this folder): User_WifiConfigStoreNetworkSuggestions.xml
diff --git a/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStore.xml b/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStore.xml
new file mode 100644
index 000000000000..3063276fae6a
--- /dev/null
+++ b/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStore.xml
@@ -0,0 +1,200 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<WifiConfigStoreData>
+<int name="Version" value="3" />
+<NetworkList>
+<Network>
+<WifiConfiguration>
+<string name="ConfigKey">&quot;OPEN_SSID&quot;NONE</string>
+<string name="SSID">&quot;OPEN_SSID&quot;</string>
+<null name="PreSharedKey" />
+<null name="WEPKeys" />
+<int name="WEPTxKeyIndex" value="0" />
+<boolean name="HiddenSSID" value="false" />
+<boolean name="RequirePMF" value="false" />
+<byte-array name="AllowedKeyMgmt" num="1">01</byte-array>
+<byte-array name="AllowedProtocols" num="1">03</byte-array>
+<byte-array name="AllowedAuthAlgos" num="0"></byte-array>
+<byte-array name="AllowedGroupCiphers" num="1">2f</byte-array>
+<byte-array name="AllowedPairwiseCiphers" num="1">0e</byte-array>
+<byte-array name="AllowedGroupMgmtCiphers" num="1">04</byte-array>
+<byte-array name="AllowedSuiteBCiphers" num="0"></byte-array>
+<boolean name="Shared" value="true" />
+<boolean name="AutoJoinEnabled" value="true" />
+<boolean name="Trusted" value="true" />
+<null name="BSSID" />
+<int name="Status" value="2" />
+<null name="FQDN" />
+<null name="ProviderFriendlyName" />
+<null name="LinkedNetworksList" />
+<null name="DefaultGwMacAddress" />
+<boolean name="ValidatedInternetAccess" value="true" />
+<boolean name="NoInternetAccessExpected" value="false" />
+<boolean name="MeteredHint" value="false" />
+<int name="MeteredOverride" value="0" />
+<boolean name="UseExternalScores" value="false" />
+<int name="NumAssociation" value="3" />
+<int name="CreatorUid" value="1000" />
+<string name="CreatorName">android.uid.system:1000</string>
+<int name="LastUpdateUid" value="1000" />
+<string name="LastUpdateName">android.uid.system:1000</string>
+<int name="LastConnectUid" value="1000" />
+<boolean name="IsLegacyPasspointConfig" value="false" />
+<long-array name="RoamingConsortiumOIs" num="0" />
+<string name="RandomizedMacAddress">ce:b1:36:bb:71:ac</string>
+<int name="MacRandomizationSetting" value="1" />
+<int name="CarrierId" value="-1" />
+</WifiConfiguration>
+<NetworkStatus>
+<string name="SelectionStatus">NETWORK_SELECTION_ENABLED</string>
+<string name="DisableReason">NETWORK_SELECTION_ENABLE</string>
+<string name="ConnectChoice">&quot;ENTERPRISE_SSID&quot;WPA_EAP</string>
+<boolean name="HasEverConnected" value="true" />
+</NetworkStatus>
+<IpConfiguration>
+<string name="IpAssignment">DHCP</string>
+<string name="ProxySettings">NONE</string>
+</IpConfiguration>
+</Network>
+<Network>
+<WifiConfiguration>
+<string name="ConfigKey">&quot;ENTERPRISE_SSID&quot;WPA_EAP</string>
+<string name="SSID">&quot;ENTERPRISE_SSID&quot;</string>
+<null name="PreSharedKey" />
+<null name="WEPKeys" />
+<int name="WEPTxKeyIndex" value="0" />
+<boolean name="HiddenSSID" value="false" />
+<boolean name="RequirePMF" value="false" />
+<byte-array name="AllowedKeyMgmt" num="1">0c</byte-array>
+<byte-array name="AllowedProtocols" num="1">03</byte-array>
+<byte-array name="AllowedAuthAlgos" num="0"></byte-array>
+<byte-array name="AllowedGroupCiphers" num="1">2f</byte-array>
+<byte-array name="AllowedPairwiseCiphers" num="1">0e</byte-array>
+<byte-array name="AllowedGroupMgmtCiphers" num="1">04</byte-array>
+<byte-array name="AllowedSuiteBCiphers" num="0"></byte-array>
+<boolean name="Shared" value="true" />
+<boolean name="AutoJoinEnabled" value="true" />
+<boolean name="Trusted" value="true" />
+<null name="BSSID" />
+<int name="Status" value="2" />
+<null name="FQDN" />
+<null name="ProviderFriendlyName" />
+<null name="LinkedNetworksList" />
+<null name="DefaultGwMacAddress" />
+<boolean name="ValidatedInternetAccess" value="false" />
+<boolean name="NoInternetAccessExpected" value="false" />
+<boolean name="MeteredHint" value="false" />
+<int name="MeteredOverride" value="0" />
+<boolean name="UseExternalScores" value="false" />
+<int name="NumAssociation" value="0" />
+<int name="CreatorUid" value="1000" />
+<string name="CreatorName">android.uid.system:1000</string>
+<int name="LastUpdateUid" value="1000" />
+<string name="LastUpdateName">android.uid.system:1000</string>
+<int name="LastConnectUid" value="1000" />
+<boolean name="IsLegacyPasspointConfig" value="false" />
+<long-array name="RoamingConsortiumOIs" num="0" />
+<string name="RandomizedMacAddress">f6:b3:94:44:40:87</string>
+<int name="MacRandomizationSetting" value="1" />
+<int name="CarrierId" value="-1" />
+</WifiConfiguration>
+<NetworkStatus>
+<string name="SelectionStatus">NETWORK_SELECTION_TEMPORARY_DISABLED</string>
+<string name="DisableReason">NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE</string>
+<null name="ConnectChoice" />
+<boolean name="HasEverConnected" value="false" />
+</NetworkStatus>
+<IpConfiguration>
+<string name="IpAssignment">DHCP</string>
+<string name="ProxySettings">NONE</string>
+</IpConfiguration>
+<WifiEnterpriseConfiguration>
+<string name="Identity">adadadasdaddsa</string>
+<string name="AnonIdentity">asdadaddadasd</string>
+<string name="Password">adasdadadad</string>
+<string name="ClientCert"></string>
+<string name="CaCert"></string>
+<string name="SubjectMatch"></string>
+<string name="Engine">0</string>
+<string name="EngineId"></string>
+<string name="PrivateKeyId"></string>
+<string name="AltSubjectMatch"></string>
+<string name="DomSuffixMatch">adsad</string>
+<string name="CaPath">/system/etc/security/cacerts</string>
+<int name="EapMethod" value="0" />
+<int name="Phase2Method" value="3" />
+<string name="PLMN"></string>
+<string name="Realm"></string>
+<int name="Ocsp" value="0" />
+<string name="WapiCertSuite"></string>
+</WifiEnterpriseConfiguration>
+</Network>
+<Network>
+<WifiConfiguration>
+<string name="ConfigKey">&quot;WPA3_SSID&quot;SAE</string>
+<string name="SSID">&quot;WPA3_SSID&quot;</string>
+<string name="PreSharedKey">&quot;sfsdfsfdsfsdf&quot;</string>
+<null name="WEPKeys" />
+<int name="WEPTxKeyIndex" value="0" />
+<boolean name="HiddenSSID" value="false" />
+<boolean name="RequirePMF" value="true" />
+<byte-array name="AllowedKeyMgmt" num="2">0001</byte-array>
+<byte-array name="AllowedProtocols" num="1">02</byte-array>
+<byte-array name="AllowedAuthAlgos" num="0"></byte-array>
+<byte-array name="AllowedGroupCiphers" num="1">28</byte-array>
+<byte-array name="AllowedPairwiseCiphers" num="1">0c</byte-array>
+<byte-array name="AllowedGroupMgmtCiphers" num="1">04</byte-array>
+<byte-array name="AllowedSuiteBCiphers" num="0"></byte-array>
+<boolean name="Shared" value="true" />
+<boolean name="AutoJoinEnabled" value="true" />
+<boolean name="Trusted" value="true" />
+<null name="BSSID" />
+<int name="Status" value="1" />
+<null name="FQDN" />
+<null name="ProviderFriendlyName" />
+<null name="LinkedNetworksList" />
+<null name="DefaultGwMacAddress" />
+<boolean name="ValidatedInternetAccess" value="false" />
+<boolean name="NoInternetAccessExpected" value="false" />
+<boolean name="MeteredHint" value="false" />
+<int name="MeteredOverride" value="0" />
+<boolean name="UseExternalScores" value="false" />
+<int name="NumAssociation" value="0" />
+<int name="CreatorUid" value="1000" />
+<string name="CreatorName">android.uid.system:1000</string>
+<int name="LastUpdateUid" value="1000" />
+<string name="LastUpdateName">android.uid.system:1000</string>
+<int name="LastConnectUid" value="1000" />
+<boolean name="IsLegacyPasspointConfig" value="false" />
+<long-array name="RoamingConsortiumOIs" num="0" />
+<string name="RandomizedMacAddress">a6:3d:b0:13:ed:41</string>
+<int name="MacRandomizationSetting" value="1" />
+<int name="CarrierId" value="-1" />
+</WifiConfiguration>
+<NetworkStatus>
+<string name="SelectionStatus">NETWORK_SELECTION_PERMANENTLY_DISABLED</string>
+<string name="DisableReason">NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD</string>
+<null name="ConnectChoice" />
+<boolean name="HasEverConnected" value="false" />
+</NetworkStatus>
+<IpConfiguration>
+<string name="IpAssignment">DHCP</string>
+<string name="ProxySettings">NONE</string>
+</IpConfiguration>
+</Network>
+</NetworkList>
+<MacAddressMap>
+<map name="MacMapEntry" />
+</MacAddressMap>
+<Settings>
+<map name="Values">
+<boolean name="wifi_p2p_pending_factory_reset" value="false" />
+<boolean name="wifi_scan_throttle_enabled" value="true" />
+<null name="wifi_p2p_device_name" />
+<boolean name="wifi_scan_always_enabled" value="false" />
+<boolean name="wifi_verbose_logging_enabled" value="true" />
+</map>
+</Settings>
+<PasspointConfigData>
+<long name="ProviderIndex" value="0" />
+</PasspointConfigData>
+</WifiConfigStoreData>
diff --git a/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStoreSoftAp.xml b/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStoreSoftAp.xml
new file mode 100644
index 000000000000..fd99dd3df8b2
--- /dev/null
+++ b/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStoreSoftAp.xml
@@ -0,0 +1,22 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<WifiConfigStoreData>
+<int name="Version" value="3" />
+<SoftAp>
+<string name="SSID">HOTSPOT_SSID</string>
+<int name="ApBand" value="1" />
+<int name="Channel" value="0" />
+<boolean name="HiddenSSID" value="false" />
+<int name="SecurityType" value="1" />
+<string name="Passphrase">blahblahblah</string>
+<int name="MaxNumberOfClients" value="0" />
+<boolean name="ClientControlByUser" value="false" />
+<boolean name="AutoShutdownEnabled" value="true" />
+<long name="ShutdownTimeoutMillis" value="0" />
+<BlockedClientList>
+<string name="ClientMacAddress">00:11:22:33:44:55</string>
+</BlockedClientList>
+<AllowedClientList>
+<string name="ClientMacAddress">aa:bb:cc:dd:ee:ff</string>
+</AllowedClientList>
+</SoftAp>
+</WifiConfigStoreData>
diff --git a/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStore.xml b/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStore.xml
new file mode 100644
index 000000000000..67d5aab215f2
--- /dev/null
+++ b/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStore.xml
@@ -0,0 +1,81 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<WifiConfigStoreData>
+<int name="Version" value="3" />
+<NetworkList />
+<PasspointConfigData>
+<ProviderList>
+<Provider>
+<long name="ProviderID" value="0" />
+<int name="CreatorUID" value="10085" />
+<string name="PackageName">com.android.certinstaller</string>
+<list name="CaCertificateAliases">
+<string>HS2_0_0</string>
+</list>
+<null name="ClientPrivateKeyAlias" />
+<boolean name="HasEverConnected" value="false" />
+<boolean name="IsFromSuggestion" value="false" />
+<boolean name="IsTrusted" value="true" />
+<Configuration>
+<int name="UpdateIdentifier" value="-2147483648" />
+<int name="CredentialPriority" value="-2147483648" />
+<null name="TrustRootCertList" />
+<long name="SubscriptionCreationTime" value="-9223372036854775808" />
+<long name="SubscriptionExpirationTime" value="-9223372036854775808" />
+<null name="SubscriptionType" />
+<long name="UsageLimitTimePeriod" value="-9223372036854775808" />
+<long name="UsageLimitStartTime" value="-9223372036854775808" />
+<long name="UsageLimitDataLimit" value="-9223372036854775808" />
+<long name="UsageLimitTimeLimit" value="-9223372036854775808" />
+<HomeSP>
+<string name="FQDN">Passpoint.net</string>
+<string name="FriendlyName">Passpoint Friendly Name</string>
+<null name="IconURL" />
+<null name="HomeNetworkIDs" />
+<null name="MatchAllOIs" />
+<null name="MatchAnyOIs" />
+<null name="OtherHomePartners" />
+<null name="RoamingConsortiumOIs" />
+</HomeSP>
+<Credential>
+<long name="CreationTime" value="-9223372036854775808" />
+<long name="ExpirationTime" value="-9223372036854775808" />
+<string name="Realm">passpoint.com</string>
+<boolean name="CheckAAAServerCertStatus" value="false" />
+<UserCredential>
+<string name="Username">blahblahblah</string>
+<string name="Password">doubleblahlah</string>
+<boolean name="MachineManaged" value="true" />
+<null name="SoftTokenApp" />
+<boolean name="AbleToShare" value="false" />
+<int name="EAPType" value="21" />
+<string name="NonEAPInnerMethod">PAP</string>
+</UserCredential>
+</Credential>
+<int name="CarrierId" value="-1" />
+<boolean name="AutoJoinEnabled" value="true" />
+<boolean name="IsMacRandomizationEnabled" value="true" />
+<int name="MeteredOverride" value="0" />
+</Configuration>
+<null name="RemediationCaCertificateAlias" />
+</Provider>
+</ProviderList>
+</PasspointConfigData>
+<OpenNetworkNotifierBlacklistConfigData />
+<NetworkRequestMap>
+<ApprovedAccessPointsPerApp>
+<string name="RequestorPackageName">com.android.cts.verifier</string>
+<AccessPoint>
+<string name="SSID">OPEN_SSID</string>
+<string name="BSSID">00:11:22:33:44:55</string>
+<int name="NetworkType" value="0" />
+</AccessPoint>
+</ApprovedAccessPointsPerApp>
+</NetworkRequestMap>
+<WakeupConfigStoreData>
+<FeatureState>
+<boolean name="IsActive" value="false" />
+<boolean name="IsOnboarded" value="false" />
+<int name="NotificationsShown" value="1" />
+</FeatureState>
+</WakeupConfigStoreData>
+</WifiConfigStoreData>
diff --git a/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml b/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml
new file mode 100644
index 000000000000..4ecdd29709b4
--- /dev/null
+++ b/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml
@@ -0,0 +1,155 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<WifiConfigStoreData>
+<int name="Version" value="3" />
+<NetworkSuggestionMap>
+<NetworkSuggestionPerApp>
+<string name="SuggestorPackageName">com.android.cts.verifier</string>
+<null name="SuggestorFeatureId" />
+<boolean name="SuggestorHasUserApproved" value="true" />
+<int name="SuggestorMaxSize" value="1" />
+<int name="SuggestorUid" value="10228" />
+<int name="SuggestorCarrierId" value="-1" />
+<NetworkSuggestion>
+<WifiConfiguration>
+<string name="ConfigKey">&quot;OPEN_SSID&quot;NONE</string>
+<string name="SSID">&quot;OPEN_SSID&quot;</string>
+<null name="PreSharedKey" />
+<null name="WEPKeys" />
+<int name="WEPTxKeyIndex" value="0" />
+<boolean name="HiddenSSID" value="false" />
+<boolean name="RequirePMF" value="false" />
+<byte-array name="AllowedKeyMgmt" num="1">01</byte-array>
+<byte-array name="AllowedProtocols" num="0"></byte-array>
+<byte-array name="AllowedAuthAlgos" num="0"></byte-array>
+<byte-array name="AllowedGroupCiphers" num="0"></byte-array>
+<byte-array name="AllowedPairwiseCiphers" num="0"></byte-array>
+<byte-array name="AllowedGroupMgmtCiphers" num="0"></byte-array>
+<byte-array name="AllowedSuiteBCiphers" num="0"></byte-array>
+<boolean name="Shared" value="true" />
+<boolean name="AutoJoinEnabled" value="true" />
+<boolean name="Trusted" value="true" />
+<null name="BSSID" />
+<int name="Status" value="0" />
+<null name="FQDN" />
+<null name="ProviderFriendlyName" />
+<null name="LinkedNetworksList" />
+<null name="DefaultGwMacAddress" />
+<boolean name="ValidatedInternetAccess" value="false" />
+<boolean name="NoInternetAccessExpected" value="false" />
+<boolean name="MeteredHint" value="false" />
+<int name="MeteredOverride" value="1" />
+<boolean name="UseExternalScores" value="false" />
+<int name="NumAssociation" value="0" />
+<int name="CreatorUid" value="10228" />
+<string name="CreatorName">com.android.cts.verifier</string>
+<int name="LastUpdateUid" value="-1" />
+<null name="LastUpdateName" />
+<int name="LastConnectUid" value="0" />
+<boolean name="IsLegacyPasspointConfig" value="false" />
+<long-array name="RoamingConsortiumOIs" num="0" />
+<string name="RandomizedMacAddress">02:00:00:00:00:00</string>
+<int name="MacRandomizationSetting" value="1" />
+<int name="CarrierId" value="-1" />
+</WifiConfiguration>
+<boolean name="IsAppInteractionRequired" value="false" />
+<boolean name="IsUserInteractionRequired" value="false" />
+<boolean name="IsUserAllowedToManuallyConnect" value="false" />
+<boolean name="InitializedAutoJoinEnabled" value="true" />
+<boolean name="AutoJoinEnabled" value="true" />
+</NetworkSuggestion>
+<NetworkSuggestion>
+<WifiConfiguration>
+<string name="ConfigKey">passpoint.net</string>
+<null name="SSID" />
+<null name="PreSharedKey" />
+<null name="WEPKeys" />
+<int name="WEPTxKeyIndex" value="0" />
+<boolean name="HiddenSSID" value="false" />
+<boolean name="RequirePMF" value="false" />
+<byte-array name="AllowedKeyMgmt" num="0"></byte-array>
+<byte-array name="AllowedProtocols" num="0"></byte-array>
+<byte-array name="AllowedAuthAlgos" num="0"></byte-array>
+<byte-array name="AllowedGroupCiphers" num="0"></byte-array>
+<byte-array name="AllowedPairwiseCiphers" num="0"></byte-array>
+<byte-array name="AllowedGroupMgmtCiphers" num="0"></byte-array>
+<byte-array name="AllowedSuiteBCiphers" num="0"></byte-array>
+<boolean name="Shared" value="true" />
+<boolean name="AutoJoinEnabled" value="true" />
+<boolean name="Trusted" value="true" />
+<null name="BSSID" />
+<int name="Status" value="0" />
+<string name="FQDN">passpoint.net</string>
+<null name="ProviderFriendlyName" />
+<null name="LinkedNetworksList" />
+<null name="DefaultGwMacAddress" />
+<boolean name="ValidatedInternetAccess" value="false" />
+<boolean name="NoInternetAccessExpected" value="false" />
+<boolean name="MeteredHint" value="false" />
+<int name="MeteredOverride" value="0" />
+<boolean name="UseExternalScores" value="false" />
+<int name="NumAssociation" value="0" />
+<int name="CreatorUid" value="1000" />
+<string name="CreatorName">com.android.cts.verifier</string>
+<int name="LastUpdateUid" value="-1" />
+<null name="LastUpdateName" />
+<int name="LastConnectUid" value="0" />
+<boolean name="IsLegacyPasspointConfig" value="false" />
+<long-array name="RoamingConsortiumOIs" num="0" />
+<string name="RandomizedMacAddress">02:00:00:00:00:00</string>
+<int name="MacRandomizationSetting" value="1" />
+<int name="CarrierId" value="-1" />
+<boolean name="IsMostRecentlyConnected" value="false" />
+</WifiConfiguration>
+<PasspointConfiguration>
+<int name="UpdateIdentifier" value="-2147483648" />
+<int name="CredentialPriority" value="-2147483648" />
+<null name="TrustRootCertList" />
+<long name="SubscriptionCreationTime" value="-9223372036854775808" />
+<long name="SubscriptionExpirationTime" value="-9223372036854775808" />
+<null name="SubscriptionType" />
+<long name="UsageLimitTimePeriod" value="-9223372036854775808" />
+<long name="UsageLimitStartTime" value="-9223372036854775808" />
+<long name="UsageLimitDataLimit" value="-9223372036854775808" />
+<long name="UsageLimitTimeLimit" value="-9223372036854775808" />
+<HomeSP>
+<string name="FQDN">passpoint.net</string>
+<string name="FriendlyName">Passpoint Friendly Name</string>
+<null name="IconURL" />
+<null name="HomeNetworkIDs" />
+<null name="MatchAllOIs" />
+<null name="MatchAnyOIs" />
+<null name="OtherHomePartners" />
+<null name="RoamingConsortiumOIs" />
+</HomeSP>
+<Credential>
+<long name="CreationTime" value="-9223372036854775808" />
+<long name="ExpirationTime" value="-9223372036854775808" />
+<string name="Realm">passpoint.com</string>
+<boolean name="CheckAAAServerCertStatus" value="false" />
+<UserCredential>
+<string name="Username">blahblahblah</string>
+<string name="Password">doubleblahblah</string>
+<boolean name="MachineManaged" value="false" />
+<null name="SoftTokenApp" />
+<boolean name="AbleToShare" value="false" />
+<int name="EAPType" value="21" />
+<string name="NonEAPInnerMethod">PAP</string>
+</UserCredential>
+</Credential>
+<int name="CarrierId" value="-1" />
+<boolean name="AutoJoinEnabled" value="true" />
+<boolean name="IsMacRandomizationEnabled" value="true" />
+<int name="MeteredOverride" value="0" />
+</PasspointConfiguration>
+<boolean name="IsAppInteractionRequired" value="false" />
+<boolean name="IsUserInteractionRequired" value="false" />
+<boolean name="IsUserAllowedToManuallyConnect" value="true" />
+<boolean name="InitializedAutoJoinEnabled" value="true" />
+<boolean name="AutoJoinEnabled" value="true" />
+</NetworkSuggestion>
+</NetworkSuggestionPerApp>
+</NetworkSuggestionMap>
+<ImsiPrivacyProtectionExemptionMap>
+<map name="CarrierExemptionMap" />
+</ImsiPrivacyProtectionExemptionMap>
+</WifiConfigStoreData>
diff --git a/wifi/java/android/net/wifi/nl80211/ChannelSettings.java b/wifi/java/android/net/wifi/nl80211/ChannelSettings.java
new file mode 100644
index 000000000000..4c14fd499c28
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/ChannelSettings.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * ChannelSettings for wificond
+ *
+ * @hide
+ */
+public class ChannelSettings implements Parcelable {
+ private static final String TAG = "ChannelSettings";
+
+ public int frequency;
+
+ /** public constructor */
+ public ChannelSettings() { }
+
+ /** override comparator */
+ @Override
+ public boolean equals(Object rhs) {
+ if (this == rhs) return true;
+ if (!(rhs instanceof ChannelSettings)) {
+ return false;
+ }
+ ChannelSettings channel = (ChannelSettings) rhs;
+ if (channel == null) {
+ return false;
+ }
+ return frequency == channel.frequency;
+ }
+
+ /** override hash code */
+ @Override
+ public int hashCode() {
+ return Objects.hash(frequency);
+ }
+
+ /** implement Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * implement Parcelable interface
+ * |flags| is ignored.
+ **/
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(frequency);
+ }
+
+ /** implement Parcelable interface */
+ public static final Parcelable.Creator<ChannelSettings> CREATOR =
+ new Parcelable.Creator<ChannelSettings>() {
+ /**
+ * Caller is responsible for providing a valid parcel.
+ */
+ @Override
+ public ChannelSettings createFromParcel(Parcel in) {
+ ChannelSettings result = new ChannelSettings();
+ result.frequency = in.readInt();
+ if (in.dataAvail() != 0) {
+ Log.e(TAG, "Found trailing data after parcel parsing.");
+ }
+
+ return result;
+ }
+
+ @Override
+ public ChannelSettings[] newArray(int size) {
+ return new ChannelSettings[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java b/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
new file mode 100644
index 000000000000..bb0cc975a3db
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiAnnotations.ChannelWidth;
+import android.net.wifi.WifiAnnotations.WifiStandard;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * DeviceWiphyCapabilities for wificond
+ *
+ * Contains the WiFi physical layer attributes and capabilities of the device.
+ * It is used to collect these attributes from the device driver via wificond.
+ *
+ * @hide
+ */
+@SystemApi
+public final class DeviceWiphyCapabilities implements Parcelable {
+ private static final String TAG = "DeviceWiphyCapabilities";
+
+ private boolean m80211nSupported;
+ private boolean m80211acSupported;
+ private boolean m80211axSupported;
+ private boolean mChannelWidth160MhzSupported;
+ private boolean mChannelWidth80p80MhzSupported;
+ private int mMaxNumberTxSpatialStreams;
+ private int mMaxNumberRxSpatialStreams;
+
+
+ /** public constructor */
+ public DeviceWiphyCapabilities() {
+ m80211nSupported = false;
+ m80211acSupported = false;
+ m80211axSupported = false;
+ mChannelWidth160MhzSupported = false;
+ mChannelWidth80p80MhzSupported = false;
+ mMaxNumberTxSpatialStreams = 1;
+ mMaxNumberRxSpatialStreams = 1;
+ }
+
+ /**
+ * Get the IEEE 802.11 standard support
+ *
+ * @param standard the IEEE 802.11 standard to check on its support.
+ * valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
+ * @return {@code true} if supported, {@code false} otherwise.
+ */
+ public boolean isWifiStandardSupported(@WifiStandard int standard) {
+ switch (standard) {
+ case ScanResult.WIFI_STANDARD_LEGACY:
+ return true;
+ case ScanResult.WIFI_STANDARD_11N:
+ return m80211nSupported;
+ case ScanResult.WIFI_STANDARD_11AC:
+ return m80211acSupported;
+ case ScanResult.WIFI_STANDARD_11AX:
+ return m80211axSupported;
+ default:
+ Log.e(TAG, "isWifiStandardSupported called with invalid standard: " + standard);
+ return false;
+ }
+ }
+
+ /**
+ * Set the IEEE 802.11 standard support
+ *
+ * @param standard the IEEE 802.11 standard to set its support.
+ * valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
+ * @param support {@code true} if supported, {@code false} otherwise.
+ */
+ public void setWifiStandardSupport(@WifiStandard int standard, boolean support) {
+ switch (standard) {
+ case ScanResult.WIFI_STANDARD_11N:
+ m80211nSupported = support;
+ break;
+ case ScanResult.WIFI_STANDARD_11AC:
+ m80211acSupported = support;
+ break;
+ case ScanResult.WIFI_STANDARD_11AX:
+ m80211axSupported = support;
+ break;
+ default:
+ Log.e(TAG, "setWifiStandardSupport called with invalid standard: " + standard);
+ }
+ }
+
+ /**
+ * Get the support for channel bandwidth
+ *
+ * @param chWidth valid values from {@link ScanResult}'s {@code CHANNEL_WIDTH_}
+ *
+ * @return {@code true} if supported, {@code false} otherwise.
+ */
+ public boolean isChannelWidthSupported(@ChannelWidth int chWidth) {
+ switch (chWidth) {
+ case ScanResult.CHANNEL_WIDTH_20MHZ:
+ return true;
+ case ScanResult.CHANNEL_WIDTH_40MHZ:
+ return (m80211nSupported || m80211acSupported || m80211axSupported);
+ case ScanResult.CHANNEL_WIDTH_80MHZ:
+ return (m80211acSupported || m80211axSupported);
+ case ScanResult.CHANNEL_WIDTH_160MHZ:
+ return mChannelWidth160MhzSupported;
+ case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
+ return mChannelWidth80p80MhzSupported;
+ default:
+ Log.e(TAG, "isChannelWidthSupported called with invalid channel width: " + chWidth);
+ }
+ return false;
+ }
+
+ /**
+ * Set support for channel bandwidth
+ *
+ * @param chWidth valid values are {@link ScanResult#CHANNEL_WIDTH_160MHZ} and
+ * {@link ScanResult#CHANNEL_WIDTH_80MHZ_PLUS_MHZ}
+ * @param support {@code true} if supported, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public void setChannelWidthSupported(@ChannelWidth int chWidth, boolean support) {
+ switch (chWidth) {
+ case ScanResult.CHANNEL_WIDTH_160MHZ:
+ mChannelWidth160MhzSupported = support;
+ break;
+ case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
+ mChannelWidth80p80MhzSupported = support;
+ break;
+ default:
+ Log.e(TAG, "setChannelWidthSupported called with Invalid channel width: "
+ + chWidth);
+ }
+ }
+
+ /**
+ * Get maximum number of transmit spatial streams
+ *
+ * @return number of spatial streams
+ */
+ public int getMaxNumberTxSpatialStreams() {
+ return mMaxNumberTxSpatialStreams;
+ }
+
+ /**
+ * Set maximum number of transmit spatial streams
+ *
+ * @param streams number of spatial streams
+ *
+ * @hide
+ */
+ public void setMaxNumberTxSpatialStreams(int streams) {
+ mMaxNumberTxSpatialStreams = streams;
+ }
+
+ /**
+ * Get maximum number of receive spatial streams
+ *
+ * @return number of streams
+ */
+ public int getMaxNumberRxSpatialStreams() {
+ return mMaxNumberRxSpatialStreams;
+ }
+
+ /**
+ * Set maximum number of receive spatial streams
+ *
+ * @param streams number of streams
+ *
+ * @hide
+ */
+ public void setMaxNumberRxSpatialStreams(int streams) {
+ mMaxNumberRxSpatialStreams = streams;
+ }
+
+ /** override comparator */
+ @Override
+ public boolean equals(Object rhs) {
+ if (this == rhs) return true;
+ if (!(rhs instanceof DeviceWiphyCapabilities)) {
+ return false;
+ }
+ DeviceWiphyCapabilities capa = (DeviceWiphyCapabilities) rhs;
+
+ return m80211nSupported == capa.m80211nSupported
+ && m80211acSupported == capa.m80211acSupported
+ && m80211axSupported == capa.m80211axSupported
+ && mChannelWidth160MhzSupported == capa.mChannelWidth160MhzSupported
+ && mChannelWidth80p80MhzSupported == capa.mChannelWidth80p80MhzSupported
+ && mMaxNumberTxSpatialStreams == capa.mMaxNumberTxSpatialStreams
+ && mMaxNumberRxSpatialStreams == capa.mMaxNumberRxSpatialStreams;
+ }
+
+ /** override hash code */
+ @Override
+ public int hashCode() {
+ return Objects.hash(m80211nSupported, m80211acSupported, m80211axSupported,
+ mChannelWidth160MhzSupported, mChannelWidth80p80MhzSupported,
+ mMaxNumberTxSpatialStreams, mMaxNumberRxSpatialStreams);
+ }
+
+ /** implement Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * implement Parcelable interface
+ * |flags| is ignored.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeBoolean(m80211nSupported);
+ out.writeBoolean(m80211acSupported);
+ out.writeBoolean(m80211axSupported);
+ out.writeBoolean(mChannelWidth160MhzSupported);
+ out.writeBoolean(mChannelWidth80p80MhzSupported);
+ out.writeInt(mMaxNumberTxSpatialStreams);
+ out.writeInt(mMaxNumberRxSpatialStreams);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("m80211nSupported:").append(m80211nSupported ? "Yes" : "No");
+ sb.append("m80211acSupported:").append(m80211acSupported ? "Yes" : "No");
+ sb.append("m80211axSupported:").append(m80211axSupported ? "Yes" : "No");
+ sb.append("mChannelWidth160MhzSupported: ")
+ .append(mChannelWidth160MhzSupported ? "Yes" : "No");
+ sb.append("mChannelWidth80p80MhzSupported: ")
+ .append(mChannelWidth80p80MhzSupported ? "Yes" : "No");
+ sb.append("mMaxNumberTxSpatialStreams: ").append(mMaxNumberTxSpatialStreams);
+ sb.append("mMaxNumberRxSpatialStreams: ").append(mMaxNumberRxSpatialStreams);
+
+ return sb.toString();
+ }
+
+ /** implement Parcelable interface */
+ public static final @NonNull Parcelable.Creator<DeviceWiphyCapabilities> CREATOR =
+ new Parcelable.Creator<DeviceWiphyCapabilities>() {
+ /**
+ * Caller is responsible for providing a valid parcel.
+ */
+ @Override
+ public DeviceWiphyCapabilities createFromParcel(Parcel in) {
+ DeviceWiphyCapabilities capabilities = new DeviceWiphyCapabilities();
+ capabilities.m80211nSupported = in.readBoolean();
+ capabilities.m80211acSupported = in.readBoolean();
+ capabilities.m80211axSupported = in.readBoolean();
+ capabilities.mChannelWidth160MhzSupported = in.readBoolean();
+ capabilities.mChannelWidth80p80MhzSupported = in.readBoolean();
+ capabilities.mMaxNumberTxSpatialStreams = in.readInt();
+ capabilities.mMaxNumberRxSpatialStreams = in.readInt();
+ return capabilities;
+ }
+
+ @Override
+ public DeviceWiphyCapabilities[] newArray(int size) {
+ return new DeviceWiphyCapabilities[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nl80211/HiddenNetwork.java b/wifi/java/android/net/wifi/nl80211/HiddenNetwork.java
new file mode 100644
index 000000000000..b1475b2c7b43
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/HiddenNetwork.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * HiddenNetwork for wificond
+ *
+ * @hide
+ */
+public class HiddenNetwork implements Parcelable {
+ private static final String TAG = "HiddenNetwork";
+
+ public byte[] ssid;
+
+ /** public constructor */
+ public HiddenNetwork() { }
+
+ /** override comparator */
+ @Override
+ public boolean equals(Object rhs) {
+ if (this == rhs) return true;
+ if (!(rhs instanceof HiddenNetwork)) {
+ return false;
+ }
+ HiddenNetwork network = (HiddenNetwork) rhs;
+ return Arrays.equals(ssid, network.ssid);
+ }
+
+ /** override hash code */
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(ssid);
+ }
+
+ /** implement Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * implement Parcelable interface
+ * |flags| is ignored.
+ */
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeByteArray(ssid);
+ }
+
+ /** implement Parcelable interface */
+ public static final Parcelable.Creator<HiddenNetwork> CREATOR =
+ new Parcelable.Creator<HiddenNetwork>() {
+ /**
+ * Caller is responsible for providing a valid parcel.
+ */
+ @Override
+ public HiddenNetwork createFromParcel(Parcel in) {
+ HiddenNetwork result = new HiddenNetwork();
+ result.ssid = in.createByteArray();
+ return result;
+ }
+
+ @Override
+ public HiddenNetwork[] newArray(int size) {
+ return new HiddenNetwork[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nl80211/NativeScanResult.java b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
new file mode 100644
index 000000000000..a8e999973fe8
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.net.MacAddress;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Raw scan result data from the wificond daemon.
+ *
+ * @hide
+ */
+@SystemApi
+public final class NativeScanResult implements Parcelable {
+ private static final String TAG = "NativeScanResult";
+
+ /** @hide */
+ @VisibleForTesting
+ public byte[] ssid;
+ /** @hide */
+ @VisibleForTesting
+ public byte[] bssid;
+ /** @hide */
+ @VisibleForTesting
+ public byte[] infoElement;
+ /** @hide */
+ @VisibleForTesting
+ public int frequency;
+ /** @hide */
+ @VisibleForTesting
+ public int signalMbm;
+ /** @hide */
+ @VisibleForTesting
+ public long tsf;
+ /** @hide */
+ @VisibleForTesting
+ @BssCapabilityBits public int capability;
+ /** @hide */
+ @VisibleForTesting
+ public boolean associated;
+ /** @hide */
+ @VisibleForTesting
+ public List<RadioChainInfo> radioChainInfos;
+
+ /**
+ * Returns the SSID raw byte array of the AP represented by this scan result.
+ *
+ * @return A byte array.
+ */
+ @NonNull public byte[] getSsid() {
+ return ssid;
+ }
+
+ /**
+ * Returns the MAC address (BSSID) of the AP represented by this scan result.
+ *
+ * @return a MacAddress or null on error.
+ */
+ @Nullable public MacAddress getBssid() {
+ try {
+ return MacAddress.fromBytes(bssid);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Illegal argument " + Arrays.toString(bssid), e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the raw bytes of the information element advertised by the AP represented by this
+ * scan result.
+ *
+ * @return A byte array, possibly null or containing an invalid TLV configuration.
+ */
+ @NonNull public byte[] getInformationElements() {
+ return infoElement;
+ }
+
+ /**
+ * Returns the frequency (in MHz) on which the AP represented by this scan result was observed.
+ *
+ * @return The frequency in MHz.
+ */
+ public int getFrequencyMhz() {
+ return frequency;
+ }
+
+ /**
+ * Return the signal strength of probe response/beacon in (100 * dBm).
+ *
+ * @return Signal strenght in (100 * dBm).
+ */
+ public int getSignalMbm() {
+ return signalMbm;
+ }
+
+ /**
+ * Return the TSF (Timing Synchronization Function) of the received probe response/beacon.
+ * @return
+ */
+ public long getTsf() {
+ return tsf;
+ }
+
+ /**
+ * Return a boolean indicating whether or not we're associated to the AP represented by this
+ * scan result.
+ *
+ * @return A boolean indicating association.
+ */
+ public boolean isAssociated() {
+ return associated;
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"BSS_CAPABILITY_"},
+ value = {BSS_CAPABILITY_ESS,
+ BSS_CAPABILITY_IBSS,
+ BSS_CAPABILITY_CF_POLLABLE,
+ BSS_CAPABILITY_CF_POLL_REQUEST,
+ BSS_CAPABILITY_PRIVACY,
+ BSS_CAPABILITY_SHORT_PREAMBLE,
+ BSS_CAPABILITY_PBCC,
+ BSS_CAPABILITY_CHANNEL_AGILITY,
+ BSS_CAPABILITY_SPECTRUM_MANAGEMENT,
+ BSS_CAPABILITY_QOS,
+ BSS_CAPABILITY_SHORT_SLOT_TIME,
+ BSS_CAPABILITY_APSD,
+ BSS_CAPABILITY_RADIO_MANAGEMENT,
+ BSS_CAPABILITY_DSSS_OFDM,
+ BSS_CAPABILITY_DELAYED_BLOCK_ACK,
+ BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK
+ })
+ public @interface BssCapabilityBits { }
+
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): ESS.
+ */
+ public static final int BSS_CAPABILITY_ESS = 0x1 << 0;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): IBSS.
+ */
+ public static final int BSS_CAPABILITY_IBSS = 0x1 << 1;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): CF Pollable.
+ */
+ public static final int BSS_CAPABILITY_CF_POLLABLE = 0x1 << 2;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): CF-Poll Request.
+ */
+ public static final int BSS_CAPABILITY_CF_POLL_REQUEST = 0x1 << 3;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): Privacy.
+ */
+ public static final int BSS_CAPABILITY_PRIVACY = 0x1 << 4;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): Short Preamble.
+ */
+ public static final int BSS_CAPABILITY_SHORT_PREAMBLE = 0x1 << 5;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): PBCC.
+ */
+ public static final int BSS_CAPABILITY_PBCC = 0x1 << 6;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): Channel Agility.
+ */
+ public static final int BSS_CAPABILITY_CHANNEL_AGILITY = 0x1 << 7;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): Spectrum Management.
+ */
+ public static final int BSS_CAPABILITY_SPECTRUM_MANAGEMENT = 0x1 << 8;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): QoS.
+ */
+ public static final int BSS_CAPABILITY_QOS = 0x1 << 9;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): Short Slot Time.
+ */
+ public static final int BSS_CAPABILITY_SHORT_SLOT_TIME = 0x1 << 10;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): APSD.
+ */
+ public static final int BSS_CAPABILITY_APSD = 0x1 << 11;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): Radio Management.
+ */
+ public static final int BSS_CAPABILITY_RADIO_MANAGEMENT = 0x1 << 12;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): DSSS-OFDM.
+ */
+ public static final int BSS_CAPABILITY_DSSS_OFDM = 0x1 << 13;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): Delayed Block Ack.
+ */
+ public static final int BSS_CAPABILITY_DELAYED_BLOCK_ACK = 0x1 << 14;
+ /**
+ * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): Immediate Block Ack.
+ */
+ public static final int BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK = 0x1 << 15;
+
+ /**
+ * Returns the capabilities of the AP repseresented by this scan result as advertised in the
+ * received probe response or beacon.
+ *
+ * This is a bit mask describing the capabilities of a BSS. See IEEE Std 802.11: 9.4.1.4: one
+ * of the {@code BSS_CAPABILITY_*} flags.
+ *
+ * @return a bit mask of capabilities.
+ */
+ @BssCapabilityBits public int getCapabilities() {
+ return capability;
+ }
+
+ /**
+ * Returns details of the signal received on each radio chain for the AP represented by this
+ * scan result in a list of {@link RadioChainInfo} elements.
+ *
+ * @return A list of {@link RadioChainInfo} - possibly empty in case of error.
+ */
+ @NonNull public List<RadioChainInfo> getRadioChainInfos() {
+ return radioChainInfos;
+ }
+
+ /**
+ * Construct an empty native scan result.
+ */
+ public NativeScanResult() { }
+
+ /** implement Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** implement Parcelable interface */
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeByteArray(ssid);
+ out.writeByteArray(bssid);
+ out.writeByteArray(infoElement);
+ out.writeInt(frequency);
+ out.writeInt(signalMbm);
+ out.writeLong(tsf);
+ out.writeInt(capability);
+ out.writeInt(associated ? 1 : 0);
+ out.writeTypedList(radioChainInfos);
+ }
+
+ /** implement Parcelable interface */
+ @NonNull public static final Parcelable.Creator<NativeScanResult> CREATOR =
+ new Parcelable.Creator<NativeScanResult>() {
+ @Override
+ public NativeScanResult createFromParcel(Parcel in) {
+ NativeScanResult result = new NativeScanResult();
+ result.ssid = in.createByteArray();
+ if (result.ssid == null) {
+ result.ssid = new byte[0];
+ }
+ result.bssid = in.createByteArray();
+ if (result.bssid == null) {
+ result.bssid = new byte[0];
+ }
+ result.infoElement = in.createByteArray();
+ if (result.infoElement == null) {
+ result.infoElement = new byte[0];
+ }
+ result.frequency = in.readInt();
+ result.signalMbm = in.readInt();
+ result.tsf = in.readLong();
+ result.capability = in.readInt();
+ result.associated = (in.readInt() != 0);
+ result.radioChainInfos = new ArrayList<>();
+ in.readTypedList(result.radioChainInfos, RadioChainInfo.CREATOR);
+ return result;
+ }
+
+ @Override
+ public NativeScanResult[] newArray(int size) {
+ return new NativeScanResult[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nl80211/NativeWifiClient.java b/wifi/java/android/net/wifi/nl80211/NativeWifiClient.java
new file mode 100644
index 000000000000..984d7d034302
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/NativeWifiClient.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.net.MacAddress;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Structure providing information about clients (STAs) associated with a SoftAp.
+ *
+ * @hide
+ */
+@SystemApi
+public final class NativeWifiClient implements Parcelable {
+ private final MacAddress mMacAddress;
+
+ /**
+ * The MAC address of the client (STA) represented by this object. The MAC address may be null
+ * in case of an error.
+ */
+ @Nullable public MacAddress getMacAddress() {
+ return mMacAddress;
+ }
+
+ /**
+ * Construct a native Wi-Fi client.
+ */
+ public NativeWifiClient(@Nullable MacAddress macAddress) {
+ this.mMacAddress = macAddress;
+ }
+
+ /** override comparator */
+ @Override
+ public boolean equals(Object rhs) {
+ if (this == rhs) return true;
+ if (!(rhs instanceof NativeWifiClient)) {
+ return false;
+ }
+ NativeWifiClient other = (NativeWifiClient) rhs;
+ return Objects.equals(mMacAddress, other.mMacAddress);
+ }
+
+ /** override hash code */
+ @Override
+ public int hashCode() {
+ return mMacAddress.hashCode();
+ }
+
+ /** implement Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * implement Parcelable interface
+ * |flag| is ignored.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeByteArray(mMacAddress.toByteArray());
+ }
+
+ /** implement Parcelable interface */
+ @NonNull public static final Parcelable.Creator<NativeWifiClient> CREATOR =
+ new Parcelable.Creator<NativeWifiClient>() {
+ @Override
+ public NativeWifiClient createFromParcel(Parcel in) {
+ MacAddress macAddress;
+ try {
+ macAddress = MacAddress.fromBytes(in.createByteArray());
+ } catch (IllegalArgumentException e) {
+ macAddress = null;
+ }
+ return new NativeWifiClient(macAddress);
+ }
+
+ @Override
+ public NativeWifiClient[] newArray(int size) {
+ return new NativeWifiClient[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nl80211/PnoNetwork.java b/wifi/java/android/net/wifi/nl80211/PnoNetwork.java
new file mode 100644
index 000000000000..e8eff09583b9
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/PnoNetwork.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Configuration for a PNO (preferred network offload) network used in {@link PnoSettings}. A PNO
+ * network allows configuration of a specific network to search for.
+ *
+ * @hide
+ */
+@SystemApi
+public final class PnoNetwork implements Parcelable {
+ private boolean mIsHidden;
+ private byte[] mSsid;
+ private int[] mFrequencies;
+
+ /**
+ * Indicates whether the PNO network configuration is for a hidden SSID - i.e. a network which
+ * does not broadcast its SSID and must be queried explicitly.
+ *
+ * @return True if the configuration is for a hidden network, false otherwise.
+ */
+ public boolean isHidden() {
+ return mIsHidden;
+ }
+
+ /**
+ * Configure whether the PNO network configuration is for a hidden SSID - i.e. a network which
+ * does not broadcast its SSID and must be queried explicitly.
+ *
+ * @param isHidden True if the configuration is for a hidden network, false otherwise.
+ */
+ public void setHidden(boolean isHidden) {
+ mIsHidden = isHidden;
+ }
+
+ /**
+ * Get the raw bytes for the SSID of the PNO network being scanned for.
+ *
+ * @return A byte array.
+ */
+ @NonNull public byte[] getSsid() {
+ return mSsid;
+ }
+
+ /**
+ * Set the raw bytes for the SSID of the PNO network being scanned for.
+ *
+ * @param ssid A byte array.
+ */
+ public void setSsid(@NonNull byte[] ssid) {
+ if (ssid == null) {
+ throw new IllegalArgumentException("null argument");
+ }
+ this.mSsid = ssid;
+ }
+
+ /**
+ * Get the frequencies (in MHz) on which to PNO scan for the current network is being searched
+ * for. A null return (i.e. no frequencies configured) indicates that the network is search for
+ * on all supported frequencies.
+ *
+ * @return A array of frequencies (in MHz), a null indicates no configured frequencies.
+ */
+ @NonNull public int[] getFrequenciesMhz() {
+ return mFrequencies;
+ }
+
+ /**
+ * Set the frequencies (in MHz) on which to PNO scan for the current network is being searched
+ * for. A null configuration (i.e. no frequencies configured) indicates that the network is
+ * search for on all supported frequencies.
+ *
+ * @param frequenciesMhz an array of frequencies (in MHz), null indicating no configured
+ * frequencies.
+ */
+ public void setFrequenciesMhz(@NonNull int[] frequenciesMhz) {
+ if (frequenciesMhz == null) {
+ throw new IllegalArgumentException("null argument");
+ }
+ this.mFrequencies = frequenciesMhz;
+ }
+
+ /** Construct an uninitialized PnoNetwork object */
+ public PnoNetwork() { }
+
+ /** override comparator */
+ @Override
+ public boolean equals(Object rhs) {
+ if (this == rhs) return true;
+ if (!(rhs instanceof PnoNetwork)) {
+ return false;
+ }
+ PnoNetwork network = (PnoNetwork) rhs;
+ return Arrays.equals(mSsid, network.mSsid)
+ && Arrays.equals(mFrequencies, network.mFrequencies)
+ && mIsHidden == network.mIsHidden;
+ }
+
+ /** override hash code */
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mIsHidden,
+ Arrays.hashCode(mSsid),
+ Arrays.hashCode(mFrequencies));
+ }
+
+ /** implement Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * implement Parcelable interface
+ * |flag| is ignored.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mIsHidden ? 1 : 0);
+ out.writeByteArray(mSsid);
+ out.writeIntArray(mFrequencies);
+ }
+
+ /** implement Parcelable interface */
+ @NonNull public static final Parcelable.Creator<PnoNetwork> CREATOR =
+ new Parcelable.Creator<PnoNetwork>() {
+ @Override
+ public PnoNetwork createFromParcel(Parcel in) {
+ PnoNetwork result = new PnoNetwork();
+ result.mIsHidden = in.readInt() != 0 ? true : false;
+ result.mSsid = in.createByteArray();
+ if (result.mSsid == null) {
+ result.mSsid = new byte[0];
+ }
+ result.mFrequencies = in.createIntArray();
+ if (result.mFrequencies == null) {
+ result.mFrequencies = new int[0];
+ }
+ return result;
+ }
+
+ @Override
+ public PnoNetwork[] newArray(int size) {
+ return new PnoNetwork[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nl80211/PnoSettings.java b/wifi/java/android/net/wifi/nl80211/PnoSettings.java
new file mode 100644
index 000000000000..00ebe624ba0d
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/PnoSettings.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Configuration for a PNO (preferred network offload). A mechanism by which scans are offloaded
+ * from the host device to the Wi-Fi chip.
+ *
+ * @hide
+ */
+@SystemApi
+public final class PnoSettings implements Parcelable {
+ private long mIntervalMs;
+ private int mMin2gRssi;
+ private int mMin5gRssi;
+ private int mMin6gRssi;
+ private List<PnoNetwork> mPnoNetworks;
+
+ /** Construct an uninitialized PnoSettings object */
+ public PnoSettings() { }
+
+ /**
+ * Get the requested PNO scan interval in milliseconds.
+ *
+ * @return An interval in milliseconds.
+ */
+ public @DurationMillisLong long getIntervalMillis() {
+ return mIntervalMs;
+ }
+
+ /**
+ * Set the requested PNO scan interval in milliseconds.
+ *
+ * @param intervalMillis An interval in milliseconds.
+ */
+ public void setIntervalMillis(@DurationMillisLong long intervalMillis) {
+ this.mIntervalMs = intervalMillis;
+ }
+
+ /**
+ * Get the requested minimum RSSI threshold (in dBm) for APs to report in scan results in the
+ * 2.4GHz band.
+ *
+ * @return An RSSI value in dBm.
+ */
+ public int getMin2gRssiDbm() {
+ return mMin2gRssi;
+ }
+
+ /**
+ * Set the requested minimum RSSI threshold (in dBm) for APs to report in scan scan results in
+ * the 2.4GHz band.
+ *
+ * @param min2gRssiDbm An RSSI value in dBm.
+ */
+ public void setMin2gRssiDbm(int min2gRssiDbm) {
+ this.mMin2gRssi = min2gRssiDbm;
+ }
+
+ /**
+ * Get the requested minimum RSSI threshold (in dBm) for APs to report in scan results in the
+ * 5GHz band.
+ *
+ * @return An RSSI value in dBm.
+ */
+ public int getMin5gRssiDbm() {
+ return mMin5gRssi;
+ }
+
+ /**
+ * Set the requested minimum RSSI threshold (in dBm) for APs to report in scan scan results in
+ * the 5GHz band.
+ *
+ * @param min5gRssiDbm An RSSI value in dBm.
+ */
+ public void setMin5gRssiDbm(int min5gRssiDbm) {
+ this.mMin5gRssi = min5gRssiDbm;
+ }
+
+ /**
+ * Get the requested minimum RSSI threshold (in dBm) for APs to report in scan results in the
+ * 6GHz band.
+ *
+ * @return An RSSI value in dBm.
+ */
+ public int getMin6gRssiDbm() {
+ return mMin6gRssi;
+ }
+
+ /**
+ * Set the requested minimum RSSI threshold (in dBm) for APs to report in scan scan results in
+ * the 6GHz band.
+ *
+ * @param min6gRssiDbm An RSSI value in dBm.
+ */
+ public void setMin6gRssiDbm(int min6gRssiDbm) {
+ this.mMin6gRssi = min6gRssiDbm;
+ }
+
+ /**
+ * Return the configured list of specific networks to search for in a PNO scan.
+ *
+ * @return A list of {@link PnoNetwork} objects, possibly empty if non configured.
+ */
+ @NonNull public List<PnoNetwork> getPnoNetworks() {
+ return mPnoNetworks;
+ }
+
+ /**
+ * Set the list of specified networks to scan for in a PNO scan. The networks (APs) are
+ * specified using {@link PnoNetwork}s. An empty list indicates that all networks are scanned
+ * for.
+ *
+ * @param pnoNetworks A (possibly empty) list of {@link PnoNetwork} objects.
+ */
+ public void setPnoNetworks(@NonNull List<PnoNetwork> pnoNetworks) {
+ this.mPnoNetworks = pnoNetworks;
+ }
+
+ /** override comparator */
+ @Override
+ public boolean equals(Object rhs) {
+ if (this == rhs) return true;
+ if (!(rhs instanceof PnoSettings)) {
+ return false;
+ }
+ PnoSettings settings = (PnoSettings) rhs;
+ if (settings == null) {
+ return false;
+ }
+ return mIntervalMs == settings.mIntervalMs
+ && mMin2gRssi == settings.mMin2gRssi
+ && mMin5gRssi == settings.mMin5gRssi
+ && mMin6gRssi == settings.mMin6gRssi
+ && mPnoNetworks.equals(settings.mPnoNetworks);
+ }
+
+ /** override hash code */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIntervalMs, mMin2gRssi, mMin5gRssi, mMin6gRssi, mPnoNetworks);
+ }
+
+ /** implement Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * implement Parcelable interface
+ * |flag| is ignored.
+ **/
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeLong(mIntervalMs);
+ out.writeInt(mMin2gRssi);
+ out.writeInt(mMin5gRssi);
+ out.writeInt(mMin6gRssi);
+ out.writeTypedList(mPnoNetworks);
+ }
+
+ /** implement Parcelable interface */
+ @NonNull public static final Parcelable.Creator<PnoSettings> CREATOR =
+ new Parcelable.Creator<PnoSettings>() {
+ @Override
+ public PnoSettings createFromParcel(Parcel in) {
+ PnoSettings result = new PnoSettings();
+ result.mIntervalMs = in.readLong();
+ result.mMin2gRssi = in.readInt();
+ result.mMin5gRssi = in.readInt();
+ result.mMin6gRssi = in.readInt();
+
+ result.mPnoNetworks = new ArrayList<>();
+ in.readTypedList(result.mPnoNetworks, PnoNetwork.CREATOR);
+
+ return result;
+ }
+
+ @Override
+ public PnoSettings[] newArray(int size) {
+ return new PnoSettings[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nl80211/RadioChainInfo.java b/wifi/java/android/net/wifi/nl80211/RadioChainInfo.java
new file mode 100644
index 000000000000..2c12163dc9a1
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/RadioChainInfo.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * A class representing the radio chains of the Wi-Fi modems. Use to provide raw information about
+ * signals received on different radio chains.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RadioChainInfo implements Parcelable {
+ private static final String TAG = "RadioChainInfo";
+
+ /** @hide */
+ @VisibleForTesting
+ public int chainId;
+ /** @hide */
+ @VisibleForTesting
+ public int level;
+
+ /**
+ * Return an identifier for this radio chain. This is an arbitrary ID which is consistent for
+ * the same device.
+ *
+ * @return The radio chain ID.
+ */
+ public int getChainId() {
+ return chainId;
+ }
+
+ /**
+ * Returns the detected signal level on this radio chain in dBm (aka RSSI).
+ *
+ * @return A signal level in dBm.
+ */
+ public int getLevelDbm() {
+ return level;
+ }
+
+ /**
+ * Construct a RadioChainInfo.
+ */
+ public RadioChainInfo(int chainId, int level) {
+ this.chainId = chainId;
+ this.level = level;
+ }
+
+ /** override comparator */
+ @Override
+ public boolean equals(Object rhs) {
+ if (this == rhs) return true;
+ if (!(rhs instanceof RadioChainInfo)) {
+ return false;
+ }
+ RadioChainInfo chainInfo = (RadioChainInfo) rhs;
+ if (chainInfo == null) {
+ return false;
+ }
+ return chainId == chainInfo.chainId && level == chainInfo.level;
+ }
+
+ /** override hash code */
+ @Override
+ public int hashCode() {
+ return Objects.hash(chainId, level);
+ }
+
+
+ /** implement Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * implement Parcelable interface
+ * |flags| is ignored.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(chainId);
+ out.writeInt(level);
+ }
+
+ /** implement Parcelable interface */
+ @NonNull public static final Parcelable.Creator<RadioChainInfo> CREATOR =
+ new Parcelable.Creator<RadioChainInfo>() {
+ /**
+ * Caller is responsible for providing a valid parcel.
+ */
+ @Override
+ public RadioChainInfo createFromParcel(Parcel in) {
+ return new RadioChainInfo(in.readInt(), in.readInt());
+ }
+
+ @Override
+ public RadioChainInfo[] newArray(int size) {
+ return new RadioChainInfo[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nl80211/SingleScanSettings.java b/wifi/java/android/net/wifi/nl80211/SingleScanSettings.java
new file mode 100644
index 000000000000..24b1854fbf6c
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/SingleScanSettings.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * SingleScanSettings for wificond
+ *
+ * @hide
+ */
+public class SingleScanSettings implements Parcelable {
+ private static final String TAG = "SingleScanSettings";
+
+ public int scanType;
+ public ArrayList<ChannelSettings> channelSettings;
+ public ArrayList<HiddenNetwork> hiddenNetworks;
+
+ /** public constructor */
+ public SingleScanSettings() { }
+
+ /** override comparator */
+ @Override
+ public boolean equals(Object rhs) {
+ if (this == rhs) return true;
+ if (!(rhs instanceof SingleScanSettings)) {
+ return false;
+ }
+ SingleScanSettings settings = (SingleScanSettings) rhs;
+ if (settings == null) {
+ return false;
+ }
+ return scanType == settings.scanType
+ && channelSettings.equals(settings.channelSettings)
+ && hiddenNetworks.equals(settings.hiddenNetworks);
+ }
+
+ /** override hash code */
+ @Override
+ public int hashCode() {
+ return Objects.hash(scanType, channelSettings, hiddenNetworks);
+ }
+
+
+ /** implement Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private static boolean isValidScanType(int scanType) {
+ return scanType == IWifiScannerImpl.SCAN_TYPE_LOW_SPAN
+ || scanType == IWifiScannerImpl.SCAN_TYPE_LOW_POWER
+ || scanType == IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+ }
+
+ /**
+ * implement Parcelable interface
+ * |flags| is ignored.
+ */
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ if (!isValidScanType(scanType)) {
+ Log.wtf(TAG, "Invalid scan type " + scanType);
+ }
+ out.writeInt(scanType);
+ out.writeTypedList(channelSettings);
+ out.writeTypedList(hiddenNetworks);
+ }
+
+ /** implement Parcelable interface */
+ public static final Parcelable.Creator<SingleScanSettings> CREATOR =
+ new Parcelable.Creator<SingleScanSettings>() {
+ /**
+ * Caller is responsible for providing a valid parcel.
+ */
+ @Override
+ public SingleScanSettings createFromParcel(Parcel in) {
+ SingleScanSettings result = new SingleScanSettings();
+ result.scanType = in.readInt();
+ if (!isValidScanType(result.scanType)) {
+ Log.wtf(TAG, "Invalid scan type " + result.scanType);
+ }
+ result.channelSettings = new ArrayList<ChannelSettings>();
+ in.readTypedList(result.channelSettings, ChannelSettings.CREATOR);
+ result.hiddenNetworks = new ArrayList<HiddenNetwork>();
+ in.readTypedList(result.hiddenNetworks, HiddenNetwork.CREATOR);
+ if (in.dataAvail() != 0) {
+ Log.e(TAG, "Found trailing data after parcel parsing.");
+ }
+ return result;
+ }
+
+ @Override
+ public SingleScanSettings[] newArray(int size) {
+ return new SingleScanSettings[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
new file mode 100644
index 000000000000..4116234c4c8d
--- /dev/null
+++ b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -0,0 +1,1287 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.net.wifi.SoftApInfo;
+import android.net.wifi.WifiAnnotations;
+import android.net.wifi.WifiScanner;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class encapsulates the interface the wificond daemon presents to the Wi-Fi framework - used
+ * to encapsulate the Wi-Fi 80211nl management interface. The
+ * interface is only for use by the Wi-Fi framework and access is protected by SELinux permissions.
+ *
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.WIFI_NL80211_SERVICE)
+public class WifiNl80211Manager {
+ private static final String TAG = "WifiNl80211Manager";
+ private boolean mVerboseLoggingEnabled = false;
+
+ /**
+ * The {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
+ * timeout, in milliseconds, after which
+ * {@link SendMgmtFrameCallback#onFailure(int)} will be called with reason
+ * {@link #SEND_MGMT_FRAME_ERROR_TIMEOUT}.
+ */
+ private static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000;
+
+ private static final String TIMEOUT_ALARM_TAG = TAG + " Send Management Frame Timeout";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SCAN_TYPE_"},
+ value = {SCAN_TYPE_SINGLE_SCAN,
+ SCAN_TYPE_PNO_SCAN})
+ public @interface ScanResultType {}
+
+ /**
+ * Specifies a scan type: single scan initiated by the framework. Can be used in
+ * {@link #getScanResults(String, int)} to specify the type of scan result to fetch.
+ */
+ public static final int SCAN_TYPE_SINGLE_SCAN = 0;
+
+ /**
+ * Specifies a scan type: PNO scan. Can be used in {@link #getScanResults(String, int)} to
+ * specify the type of scan result to fetch.
+ */
+ public static final int SCAN_TYPE_PNO_SCAN = 1;
+
+ private AlarmManager mAlarmManager;
+ private Handler mEventHandler;
+
+ // Cached wificond binder handlers.
+ private IWificond mWificond;
+ private HashMap<String, IClientInterface> mClientInterfaces = new HashMap<>();
+ private HashMap<String, IApInterface> mApInterfaces = new HashMap<>();
+ private HashMap<String, IWifiScannerImpl> mWificondScanners = new HashMap<>();
+ private HashMap<String, IScanEvent> mScanEventHandlers = new HashMap<>();
+ private HashMap<String, IPnoScanEvent> mPnoScanEventHandlers = new HashMap<>();
+ private HashMap<String, IApInterfaceEventCallback> mApInterfaceListeners = new HashMap<>();
+ private Runnable mDeathEventHandler;
+ /**
+ * Ensures that no more than one sendMgmtFrame operation runs concurrently.
+ */
+ private AtomicBoolean mSendMgmtFrameInProgress = new AtomicBoolean(false);
+
+ /**
+ * Interface used when waiting for scans to be completed (with results).
+ */
+ public interface ScanEventCallback {
+ /**
+ * Called when scan results are available. Scans results should then be obtained from
+ * {@link #getScanResults(String, int)}.
+ */
+ void onScanResultReady();
+
+ /**
+ * Called when a scan has failed.
+ */
+ void onScanFailed();
+ }
+
+ /**
+ * Interface for a callback to provide information about PNO scan request requested with
+ * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}. Note that the
+ * callback are for the status of the request - not the scan itself. The results of the scan
+ * are returned with {@link ScanEventCallback}.
+ */
+ public interface PnoScanRequestCallback {
+ /**
+ * Called when a PNO scan request has been successfully submitted.
+ */
+ void onPnoRequestSucceeded();
+
+ /**
+ * Called when a PNO scan request fails.
+ */
+ void onPnoRequestFailed();
+ }
+
+ private class ScanEventHandler extends IScanEvent.Stub {
+ private Executor mExecutor;
+ private ScanEventCallback mCallback;
+
+ ScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void OnScanResultReady() {
+ Log.d(TAG, "Scan result ready event");
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onScanResultReady());
+ }
+
+ @Override
+ public void OnScanFailed() {
+ Log.d(TAG, "Scan failed event");
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onScanFailed());
+ }
+ }
+
+ /**
+ * Result of a signal poll requested using {@link #signalPoll(String)}.
+ */
+ public static class SignalPollResult {
+ /** @hide */
+ public SignalPollResult(int currentRssiDbm, int txBitrateMbps, int rxBitrateMbps,
+ int associationFrequencyMHz) {
+ this.currentRssiDbm = currentRssiDbm;
+ this.txBitrateMbps = txBitrateMbps;
+ this.rxBitrateMbps = rxBitrateMbps;
+ this.associationFrequencyMHz = associationFrequencyMHz;
+ }
+
+ /**
+ * RSSI value in dBM.
+ */
+ public final int currentRssiDbm;
+
+ /**
+ * Transmission bit rate in Mbps.
+ */
+ public final int txBitrateMbps;
+
+ /**
+ * Last received packet bit rate in Mbps.
+ */
+ public final int rxBitrateMbps;
+
+ /**
+ * Association frequency in MHz.
+ */
+ public final int associationFrequencyMHz;
+ }
+
+ /**
+ * Transmission counters obtained using {@link #getTxPacketCounters(String)}.
+ */
+ public static class TxPacketCounters {
+ /** @hide */
+ public TxPacketCounters(int txPacketSucceeded, int txPacketFailed) {
+ this.txPacketSucceeded = txPacketSucceeded;
+ this.txPacketFailed = txPacketFailed;
+ }
+
+ /**
+ * Number of successfully transmitted packets.
+ */
+ public final int txPacketSucceeded;
+
+ /**
+ * Number of packet transmission failures.
+ */
+ public final int txPacketFailed;
+ }
+
+ /**
+ * Callbacks for SoftAp interface registered using
+ * {@link #registerApCallback(String, Executor, SoftApCallback)}.
+ */
+ public interface SoftApCallback {
+ /**
+ * Invoked when there is a fatal failure and the SoftAp is shutdown.
+ */
+ void onFailure();
+
+ /**
+ * Invoked when there is a change in the associated station (STA).
+ * @param client Information about the client whose status has changed.
+ * @param isConnected Indication as to whether the client is connected (true), or
+ * disconnected (false).
+ */
+ void onConnectedClientsChanged(@NonNull NativeWifiClient client, boolean isConnected);
+
+ /**
+ * Invoked when a channel switch event happens - i.e. the SoftAp is moved to a different
+ * channel. Also called on initial registration.
+ * @param frequencyMhz The new frequency of the SoftAp. A value of 0 is invalid and is an
+ * indication that the SoftAp is not enabled.
+ * @param bandwidth The new bandwidth of the SoftAp.
+ */
+ void onSoftApChannelSwitched(int frequencyMhz, @WifiAnnotations.Bandwidth int bandwidth);
+ }
+
+ /**
+ * Callback to notify the results of a
+ * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} call.
+ * Note: no callbacks will be triggered if the interface dies while sending a frame.
+ */
+ public interface SendMgmtFrameCallback {
+ /**
+ * Called when the management frame was successfully sent and ACKed by the recipient.
+ * @param elapsedTimeMs The elapsed time between when the management frame was sent and when
+ * the ACK was processed, in milliseconds, as measured by wificond.
+ * This includes the time that the send frame spent queuing before it
+ * was sent, any firmware retries, and the time the received ACK spent
+ * queuing before it was processed.
+ */
+ void onAck(int elapsedTimeMs);
+
+ /**
+ * Called when the send failed.
+ * @param reason The error code for the failure.
+ */
+ void onFailure(@SendMgmtFrameError int reason);
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SEND_MGMT_FRAME_ERROR_"},
+ value = {SEND_MGMT_FRAME_ERROR_UNKNOWN,
+ SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED,
+ SEND_MGMT_FRAME_ERROR_NO_ACK,
+ SEND_MGMT_FRAME_ERROR_TIMEOUT,
+ SEND_MGMT_FRAME_ERROR_ALREADY_STARTED})
+ public @interface SendMgmtFrameError {}
+
+ // Send management frame error codes
+
+ /**
+ * Unknown error occurred during call to
+ * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}.
+ */
+ public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1;
+
+ /**
+ * Specifying the MCS rate in
+ * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} is not
+ * supported by this device.
+ */
+ public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2;
+
+ /**
+ * Driver reported that no ACK was received for the frame transmitted using
+ * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}.
+ */
+ public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3;
+
+ /**
+ * Error code for when the driver fails to report on the status of the frame sent by
+ * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
+ * after {@link #SEND_MGMT_FRAME_TIMEOUT_MS} milliseconds.
+ */
+ public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4;
+
+ /**
+ * An existing call to
+ * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
+ * is in progress. Another frame cannot be sent until the first call completes.
+ */
+ public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5;
+
+ /** @hide */
+ public WifiNl80211Manager(Context context) {
+ mAlarmManager = context.getSystemService(AlarmManager.class);
+ mEventHandler = new Handler(context.getMainLooper());
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public WifiNl80211Manager(Context context, IWificond wificond) {
+ this(context);
+ mWificond = wificond;
+ }
+
+ private class PnoScanEventHandler extends IPnoScanEvent.Stub {
+ private Executor mExecutor;
+ private ScanEventCallback mCallback;
+
+ PnoScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void OnPnoNetworkFound() {
+ Log.d(TAG, "Pno scan result event");
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onScanResultReady());
+ }
+
+ @Override
+ public void OnPnoScanFailed() {
+ Log.d(TAG, "Pno Scan failed event");
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onScanFailed());
+ }
+ }
+
+ /**
+ * Listener for AP Interface events.
+ */
+ private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub {
+ private Executor mExecutor;
+ private SoftApCallback mSoftApListener;
+
+ ApInterfaceEventCallback(Executor executor, SoftApCallback listener) {
+ mExecutor = executor;
+ mSoftApListener = listener;
+ }
+
+ @Override
+ public void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected) {
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "onConnectedClientsChanged called with "
+ + client.getMacAddress() + " isConnected: " + isConnected);
+ }
+
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mSoftApListener.onConnectedClientsChanged(client, isConnected));
+ }
+
+ @Override
+ public void onSoftApChannelSwitched(int frequency, int bandwidth) {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mSoftApListener.onSoftApChannelSwitched(frequency,
+ toFrameworkBandwidth(bandwidth)));
+ }
+
+ private @WifiAnnotations.Bandwidth int toFrameworkBandwidth(int bandwidth) {
+ switch(bandwidth) {
+ case IApInterfaceEventCallback.BANDWIDTH_INVALID:
+ return SoftApInfo.CHANNEL_WIDTH_INVALID;
+ case IApInterfaceEventCallback.BANDWIDTH_20_NOHT:
+ return SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT;
+ case IApInterfaceEventCallback.BANDWIDTH_20:
+ return SoftApInfo.CHANNEL_WIDTH_20MHZ;
+ case IApInterfaceEventCallback.BANDWIDTH_40:
+ return SoftApInfo.CHANNEL_WIDTH_40MHZ;
+ case IApInterfaceEventCallback.BANDWIDTH_80:
+ return SoftApInfo.CHANNEL_WIDTH_80MHZ;
+ case IApInterfaceEventCallback.BANDWIDTH_80P80:
+ return SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
+ case IApInterfaceEventCallback.BANDWIDTH_160:
+ return SoftApInfo.CHANNEL_WIDTH_160MHZ;
+ default:
+ return SoftApInfo.CHANNEL_WIDTH_INVALID;
+ }
+ }
+ }
+
+ /**
+ * Callback triggered by wificond.
+ */
+ private class SendMgmtFrameEvent extends ISendMgmtFrameEvent.Stub {
+ private Executor mExecutor;
+ private SendMgmtFrameCallback mCallback;
+ private AlarmManager.OnAlarmListener mTimeoutCallback;
+ /**
+ * ensures that mCallback is only called once
+ */
+ private boolean mWasCalled;
+
+ private void runIfFirstCall(Runnable r) {
+ if (mWasCalled) return;
+ mWasCalled = true;
+
+ mSendMgmtFrameInProgress.set(false);
+ r.run();
+ }
+
+ SendMgmtFrameEvent(@NonNull Executor executor, @NonNull SendMgmtFrameCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ // called in main thread
+ mTimeoutCallback = () -> runIfFirstCall(() -> {
+ if (mVerboseLoggingEnabled) {
+ Log.e(TAG, "Timed out waiting for ACK");
+ }
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT));
+ });
+ mWasCalled = false;
+
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + SEND_MGMT_FRAME_TIMEOUT_MS,
+ TIMEOUT_ALARM_TAG, mTimeoutCallback, mEventHandler);
+ }
+
+ // called in binder thread
+ @Override
+ public void OnAck(int elapsedTimeMs) {
+ // post to main thread
+ mEventHandler.post(() -> runIfFirstCall(() -> {
+ mAlarmManager.cancel(mTimeoutCallback);
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onAck(elapsedTimeMs));
+ }));
+ }
+
+ // called in binder thread
+ @Override
+ public void OnFailure(int reason) {
+ // post to main thread
+ mEventHandler.post(() -> runIfFirstCall(() -> {
+ mAlarmManager.cancel(mTimeoutCallback);
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onFailure(reason));
+ }));
+ }
+ }
+
+ /**
+ * Called by the binder subsystem upon remote object death.
+ * Invoke all the register death handlers and clear state.
+ * @hide
+ */
+ @VisibleForTesting
+ public void binderDied() {
+ mEventHandler.post(() -> {
+ Log.e(TAG, "Wificond died!");
+ clearState();
+ // Invalidate the global wificond handle on death. Will be refreshed
+ // on the next setup call.
+ mWificond = null;
+ if (mDeathEventHandler != null) {
+ mDeathEventHandler.run();
+ }
+ });
+ }
+
+ /**
+ * Enable or disable verbose logging of the WifiNl80211Manager module.
+ * @param enable True to enable verbose logging. False to disable verbose logging.
+ */
+ public void enableVerboseLogging(boolean enable) {
+ mVerboseLoggingEnabled = enable;
+ }
+
+ /**
+ * Register a death notification for the WifiNl80211Manager which acts as a proxy for the
+ * wificond daemon (i.e. the death listener will be called when and if the wificond daemon
+ * dies).
+ *
+ * @param deathEventHandler A {@link Runnable} to be called whenever the wificond daemon dies.
+ */
+ public void setOnServiceDeadCallback(@NonNull Runnable deathEventHandler) {
+ if (mDeathEventHandler != null) {
+ Log.e(TAG, "Death handler already present");
+ }
+ mDeathEventHandler = deathEventHandler;
+ }
+
+ /**
+ * Helper method to retrieve the global wificond handle and register for
+ * death notifications.
+ */
+ private boolean retrieveWificondAndRegisterForDeath() {
+ if (mWificond != null) {
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Wificond handle already retrieved");
+ }
+ // We already have a wificond handle.
+ return true;
+ }
+ IBinder binder = ServiceManager.getService(Context.WIFI_NL80211_SERVICE);
+ mWificond = IWificond.Stub.asInterface(binder);
+ if (mWificond == null) {
+ Log.e(TAG, "Failed to get reference to wificond");
+ return false;
+ }
+ try {
+ mWificond.asBinder().linkToDeath(() -> binderDied(), 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register death notification for wificond");
+ // The remote has already died.
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Set up an interface for client (STA) mode.
+ *
+ * @param ifaceName Name of the interface to configure.
+ * @param executor The Executor on which to execute the callbacks.
+ * @param scanCallback A callback for framework initiated scans.
+ * @param pnoScanCallback A callback for PNO (offloaded) scans.
+ * @return true on success.
+ */
+ public boolean setupInterfaceForClientMode(@NonNull String ifaceName,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) {
+ Log.d(TAG, "Setting up interface for client mode");
+ if (!retrieveWificondAndRegisterForDeath()) {
+ return false;
+ }
+
+ if (scanCallback == null || pnoScanCallback == null || executor == null) {
+ Log.e(TAG, "setupInterfaceForClientMode invoked with null callbacks");
+ return false;
+ }
+
+ IClientInterface clientInterface = null;
+ try {
+ clientInterface = mWificond.createClientInterface(ifaceName);
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to get IClientInterface due to remote exception");
+ return false;
+ }
+
+ if (clientInterface == null) {
+ Log.e(TAG, "Could not get IClientInterface instance from wificond");
+ return false;
+ }
+ Binder.allowBlocking(clientInterface.asBinder());
+
+ // Refresh Handlers
+ mClientInterfaces.put(ifaceName, clientInterface);
+ try {
+ IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
+ if (wificondScanner == null) {
+ Log.e(TAG, "Failed to get WificondScannerImpl");
+ return false;
+ }
+ mWificondScanners.put(ifaceName, wificondScanner);
+ Binder.allowBlocking(wificondScanner.asBinder());
+ ScanEventHandler scanEventHandler = new ScanEventHandler(executor, scanCallback);
+ mScanEventHandlers.put(ifaceName, scanEventHandler);
+ wificondScanner.subscribeScanEvents(scanEventHandler);
+ PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(executor,
+ pnoScanCallback);
+ mPnoScanEventHandlers.put(ifaceName, pnoScanEventHandler);
+ wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
+ }
+
+ return true;
+ }
+
+ /**
+ * Tear down a specific client (STA) interface configured using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
+ *
+ * @param ifaceName Name of the interface to tear down.
+ * @return Returns true on success, false on failure (e.g. when called before an interface was
+ * set up).
+ */
+ public boolean tearDownClientInterface(@NonNull String ifaceName) {
+ if (getClientInterface(ifaceName) == null) {
+ Log.e(TAG, "No valid wificond client interface handler");
+ return false;
+ }
+ try {
+ IWifiScannerImpl scannerImpl = mWificondScanners.get(ifaceName);
+ if (scannerImpl != null) {
+ scannerImpl.unsubscribeScanEvents();
+ scannerImpl.unsubscribePnoScanEvents();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to unsubscribe wificond scanner due to remote exception");
+ return false;
+ }
+
+ if (mWificond == null) {
+ Log.e(TAG, "Reference to wifiCond is null");
+ return false;
+ }
+
+ boolean success;
+ try {
+ success = mWificond.tearDownClientInterface(ifaceName);
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to teardown client interface due to remote exception");
+ return false;
+ }
+ if (!success) {
+ Log.e(TAG, "Failed to teardown client interface");
+ return false;
+ }
+
+ mClientInterfaces.remove(ifaceName);
+ mWificondScanners.remove(ifaceName);
+ mScanEventHandlers.remove(ifaceName);
+ mPnoScanEventHandlers.remove(ifaceName);
+ return true;
+ }
+
+ /**
+ * Set up interface as a Soft AP.
+ *
+ * @param ifaceName Name of the interface to configure.
+ * @return true on success.
+ */
+ public boolean setupInterfaceForSoftApMode(@NonNull String ifaceName) {
+ Log.d(TAG, "Setting up interface for soft ap mode");
+ if (!retrieveWificondAndRegisterForDeath()) {
+ return false;
+ }
+
+ IApInterface apInterface = null;
+ try {
+ apInterface = mWificond.createApInterface(ifaceName);
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to get IApInterface due to remote exception");
+ return false;
+ }
+
+ if (apInterface == null) {
+ Log.e(TAG, "Could not get IApInterface instance from wificond");
+ return false;
+ }
+ Binder.allowBlocking(apInterface.asBinder());
+
+ // Refresh Handlers
+ mApInterfaces.put(ifaceName, apInterface);
+ return true;
+ }
+
+ /**
+ * Tear down a Soft AP interface configured using
+ * {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @param ifaceName Name of the interface to tear down.
+ * @return Returns true on success, false on failure (e.g. when called before an interface was
+ * set up).
+ */
+ public boolean tearDownSoftApInterface(@NonNull String ifaceName) {
+ if (getApInterface(ifaceName) == null) {
+ Log.e(TAG, "No valid wificond ap interface handler");
+ return false;
+ }
+
+ if (mWificond == null) {
+ Log.e(TAG, "Reference to wifiCond is null");
+ return false;
+ }
+
+ boolean success;
+ try {
+ success = mWificond.tearDownApInterface(ifaceName);
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to teardown AP interface due to remote exception");
+ return false;
+ }
+ if (!success) {
+ Log.e(TAG, "Failed to teardown AP interface");
+ return false;
+ }
+ mApInterfaces.remove(ifaceName);
+ mApInterfaceListeners.remove(ifaceName);
+ return true;
+ }
+
+ /**
+ * Tear down all interfaces, whether clients (STA) or Soft AP.
+ *
+ * @return Returns true on success.
+ */
+ public boolean tearDownInterfaces() {
+ Log.d(TAG, "tearing down interfaces in wificond");
+ // Explicitly refresh the wificodn handler because |tearDownInterfaces()|
+ // could be used to cleanup before we setup any interfaces.
+ if (!retrieveWificondAndRegisterForDeath()) {
+ return false;
+ }
+
+ try {
+ for (Map.Entry<String, IWifiScannerImpl> entry : mWificondScanners.entrySet()) {
+ entry.getValue().unsubscribeScanEvents();
+ entry.getValue().unsubscribePnoScanEvents();
+ }
+ mWificond.tearDownInterfaces();
+ clearState();
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to tear down interfaces due to remote exception");
+ }
+
+ return false;
+ }
+
+ /** Helper function to look up the interface handle using name */
+ private IClientInterface getClientInterface(@NonNull String ifaceName) {
+ return mClientInterfaces.get(ifaceName);
+ }
+
+ /**
+ * Request signal polling.
+ *
+ * @param ifaceName Name of the interface on which to poll. The interface must have been
+ * already set up using
+ *{@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @return A {@link SignalPollResult} object containing interface statistics, or a null on
+ * error (e.g. the interface hasn't been set up yet).
+ */
+ @Nullable public SignalPollResult signalPoll(@NonNull String ifaceName) {
+ IClientInterface iface = getClientInterface(ifaceName);
+ if (iface == null) {
+ Log.e(TAG, "No valid wificond client interface handler");
+ return null;
+ }
+
+ int[] resultArray;
+ try {
+ resultArray = iface.signalPoll();
+ if (resultArray == null || resultArray.length != 4) {
+ Log.e(TAG, "Invalid signal poll result from wificond");
+ return null;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to do signal polling due to remote exception");
+ return null;
+ }
+ return new SignalPollResult(resultArray[0], resultArray[1], resultArray[3], resultArray[2]);
+ }
+
+ /**
+ * Get current transmit (Tx) packet counters of the specified interface. The interface must
+ * have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @param ifaceName Name of the interface.
+ * @return {@link TxPacketCounters} of the current interface or null on error (e.g. when
+ * called before the interface has been set up).
+ */
+ @Nullable public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
+ IClientInterface iface = getClientInterface(ifaceName);
+ if (iface == null) {
+ Log.e(TAG, "No valid wificond client interface handler");
+ return null;
+ }
+
+ int[] resultArray;
+ try {
+ resultArray = iface.getPacketCounters();
+ if (resultArray == null || resultArray.length != 2) {
+ Log.e(TAG, "Invalid signal poll result from wificond");
+ return null;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to do signal polling due to remote exception");
+ return null;
+ }
+ return new TxPacketCounters(resultArray[0], resultArray[1]);
+ }
+
+ /** Helper function to look up the scanner impl handle using name */
+ private IWifiScannerImpl getScannerImpl(@NonNull String ifaceName) {
+ return mWificondScanners.get(ifaceName);
+ }
+
+ /**
+ * Fetch the latest scan results of the indicated type for the specified interface. Note that
+ * this method fetches the latest results - it does not initiate a scan. Initiating a scan can
+ * be done using {@link #startScan(String, int, Set, List)} or
+ * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
+ *
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @param ifaceName Name of the interface.
+ * @param scanType The type of scan result to be returned, can be
+ * {@link #SCAN_TYPE_SINGLE_SCAN} or {@link #SCAN_TYPE_PNO_SCAN}.
+ * @return Returns an array of {@link NativeScanResult} or an empty array on failure (e.g. when
+ * called before the interface has been set up).
+ */
+ @NonNull public List<NativeScanResult> getScanResults(@NonNull String ifaceName,
+ @ScanResultType int scanType) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
+ Log.e(TAG, "No valid wificond scanner interface handler");
+ return new ArrayList<>();
+ }
+ List<NativeScanResult> results = null;
+ try {
+ if (scanType == SCAN_TYPE_SINGLE_SCAN) {
+ results = Arrays.asList(scannerImpl.getScanResults());
+ } else {
+ results = Arrays.asList(scannerImpl.getPnoScanResults());
+ }
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to create ScanDetail ArrayList");
+ }
+ if (results == null) {
+ results = new ArrayList<>();
+ }
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "get " + results.size() + " scan results from wificond");
+ }
+
+ return results;
+ }
+
+ /**
+ * Return scan type for the parcelable {@link SingleScanSettings}
+ */
+ private static int getScanType(@WifiAnnotations.ScanType int scanType) {
+ switch (scanType) {
+ case WifiScanner.SCAN_TYPE_LOW_LATENCY:
+ return IWifiScannerImpl.SCAN_TYPE_LOW_SPAN;
+ case WifiScanner.SCAN_TYPE_LOW_POWER:
+ return IWifiScannerImpl.SCAN_TYPE_LOW_POWER;
+ case WifiScanner.SCAN_TYPE_HIGH_ACCURACY:
+ return IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+ default:
+ throw new IllegalArgumentException("Invalid scan type " + scanType);
+ }
+ }
+
+ /**
+ * Start a scan using the specified parameters. A scan is an asynchronous operation. The
+ * result of the operation is returned in the {@link ScanEventCallback} registered when
+ * setting up an interface using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
+ * The latest scans can be obtained using {@link #getScanResults(String, int)} and using a
+ * {@link #SCAN_TYPE_SINGLE_SCAN} for the {@code scanType}.
+ *
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @param ifaceName Name of the interface on which to initiate the scan.
+ * @param scanType Type of scan to perform, can be any of
+ * {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}, {@link WifiScanner#SCAN_TYPE_LOW_POWER}, or
+ * {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}.
+ * @param freqs list of frequencies to scan for, if null scan all supported channels.
+ * @param hiddenNetworkSSIDs List of hidden networks to be scanned for, a null indicates that
+ * no hidden frequencies will be scanned for.
+ * @return Returns true on success, false on failure (e.g. when called before the interface
+ * has been set up).
+ */
+ public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
+ @Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
+ Log.e(TAG, "No valid wificond scanner interface handler");
+ return false;
+ }
+ SingleScanSettings settings = new SingleScanSettings();
+ try {
+ settings.scanType = getScanType(scanType);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Invalid scan type ", e);
+ return false;
+ }
+ settings.channelSettings = new ArrayList<>();
+ settings.hiddenNetworks = new ArrayList<>();
+
+ if (freqs != null) {
+ for (Integer freq : freqs) {
+ ChannelSettings channel = new ChannelSettings();
+ channel.frequency = freq;
+ settings.channelSettings.add(channel);
+ }
+ }
+ if (hiddenNetworkSSIDs != null) {
+ for (byte[] ssid : hiddenNetworkSSIDs) {
+ HiddenNetwork network = new HiddenNetwork();
+ network.ssid = ssid;
+
+ // settings.hiddenNetworks is expected to be very small, so this shouldn't cause
+ // any performance issues.
+ if (!settings.hiddenNetworks.contains(network)) {
+ settings.hiddenNetworks.add(network);
+ }
+ }
+ }
+
+ try {
+ return scannerImpl.scan(settings);
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to request scan due to remote exception");
+ }
+ return false;
+ }
+
+ /**
+ * Request a PNO (Preferred Network Offload). The offload request and the scans are asynchronous
+ * operations. The result of the request are returned in the {@code callback} parameter which
+ * is an {@link PnoScanRequestCallback}. The scan results are are return in the
+ * {@link ScanEventCallback} which is registered when setting up an interface using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
+ * The latest PNO scans can be obtained using {@link #getScanResults(String, int)} with the
+ * {@code scanType} set to {@link #SCAN_TYPE_PNO_SCAN}.
+ *
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @param ifaceName Name of the interface on which to request a PNO.
+ * @param pnoSettings PNO scan configuration.
+ * @param executor The Executor on which to execute the callback.
+ * @param callback Callback for the results of the offload request.
+ * @return true on success, false on failure (e.g. when called before the interface has been set
+ * up).
+ */
+ public boolean startPnoScan(@NonNull String ifaceName, @NonNull PnoSettings pnoSettings,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull PnoScanRequestCallback callback) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
+ Log.e(TAG, "No valid wificond scanner interface handler");
+ return false;
+ }
+
+ if (callback == null || executor == null) {
+ Log.e(TAG, "startPnoScan called with a null callback");
+ return false;
+ }
+
+ try {
+ boolean success = scannerImpl.startPnoScan(pnoSettings);
+ if (success) {
+ executor.execute(callback::onPnoRequestSucceeded);
+ } else {
+ executor.execute(callback::onPnoRequestFailed);
+ }
+ return success;
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to start pno scan due to remote exception");
+ }
+ return false;
+ }
+
+ /**
+ * Stop PNO scan configured with
+ * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
+ *
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @param ifaceName Name of the interface on which the PNO scan was configured.
+ * @return true on success, false on failure (e.g. when called before the interface has been
+ * set up).
+ */
+ public boolean stopPnoScan(@NonNull String ifaceName) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
+ Log.e(TAG, "No valid wificond scanner interface handler");
+ return false;
+ }
+ try {
+ return scannerImpl.stopPnoScan();
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to stop pno scan due to remote exception");
+ }
+ return false;
+ }
+
+ /**
+ * Abort ongoing single scan started with {@link #startScan(String, int, Set, List)}. No failure
+ * callback, e.g. {@link ScanEventCallback#onScanFailed()}, is triggered by this operation.
+ *
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}. If the interface has not been set up then
+ * this method has no impact.
+ *
+ * @param ifaceName Name of the interface on which the scan was started.
+ */
+ public void abortScan(@NonNull String ifaceName) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
+ Log.e(TAG, "No valid wificond scanner interface handler");
+ return;
+ }
+ try {
+ scannerImpl.abortScan();
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to request abortScan due to remote exception");
+ }
+ }
+
+ /**
+ * Query the list of valid frequencies (in MHz) for the provided band.
+ * The result depends on the on the country code that has been set.
+ *
+ * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
+ * The following bands are supported:
+ * {@link WifiScanner#WIFI_BAND_24_GHZ},
+ * {@link WifiScanner#WIFI_BAND_5_GHZ},
+ * {@link WifiScanner#WIFI_BAND_5_GHZ_DFS_ONLY},
+ * {@link WifiScanner#WIFI_BAND_6_GHZ}
+ * @return frequencies vector of valid frequencies (MHz), or an empty array for error.
+ * @throws IllegalArgumentException if band is not recognized.
+ */
+ public @NonNull int[] getChannelsMhzForBand(@WifiAnnotations.WifiBandBasic int band) {
+ if (mWificond == null) {
+ Log.e(TAG, "No valid wificond scanner interface handler");
+ return new int[0];
+ }
+ int[] result = null;
+ try {
+ switch (band) {
+ case WifiScanner.WIFI_BAND_24_GHZ:
+ result = mWificond.getAvailable2gChannels();
+ break;
+ case WifiScanner.WIFI_BAND_5_GHZ:
+ result = mWificond.getAvailable5gNonDFSChannels();
+ break;
+ case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
+ result = mWificond.getAvailableDFSChannels();
+ break;
+ case WifiScanner.WIFI_BAND_6_GHZ:
+ result = mWificond.getAvailable6gChannels();
+ break;
+ default:
+ throw new IllegalArgumentException("unsupported band " + band);
+ }
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to request getChannelsForBand due to remote exception");
+ }
+ if (result == null) {
+ result = new int[0];
+ }
+ return result;
+ }
+
+ /** Helper function to look up the interface handle using name */
+ private IApInterface getApInterface(@NonNull String ifaceName) {
+ return mApInterfaces.get(ifaceName);
+ }
+
+ /**
+ * Get the device phy capabilities for a given interface.
+ *
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @return DeviceWiphyCapabilities or null on error (e.g. when called on an interface which has
+ * not been set up).
+ */
+ @Nullable public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) {
+ if (mWificond == null) {
+ Log.e(TAG, "Can not query for device wiphy capabilities at this time");
+ return null;
+ }
+
+ try {
+ return mWificond.getDeviceWiphyCapabilities(ifaceName);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Register the provided callback handler for SoftAp events. The interface must first be created
+ * using {@link #setupInterfaceForSoftApMode(String)}. The callback registration is valid until
+ * the interface is deleted using {@link #tearDownSoftApInterface(String)} (no deregistration
+ * method is provided).
+ * <p>
+ * Note that only one callback can be registered at a time - any registration overrides previous
+ * registrations.
+ *
+ * @param ifaceName Name of the interface on which to register the callback.
+ * @param executor The Executor on which to execute the callbacks.
+ * @param callback Callback for AP events.
+ * @return true on success, false on failure (e.g. when called on an interface which has not
+ * been set up).
+ */
+ public boolean registerApCallback(@NonNull String ifaceName,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull SoftApCallback callback) {
+ IApInterface iface = getApInterface(ifaceName);
+ if (iface == null) {
+ Log.e(TAG, "No valid ap interface handler");
+ return false;
+ }
+
+ if (callback == null || executor == null) {
+ Log.e(TAG, "registerApCallback called with a null callback");
+ return false;
+ }
+
+ try {
+ IApInterfaceEventCallback wificondCallback = new ApInterfaceEventCallback(executor,
+ callback);
+ mApInterfaceListeners.put(ifaceName, wificondCallback);
+ boolean success = iface.registerCallback(wificondCallback);
+ if (!success) {
+ Log.e(TAG, "Failed to register ap callback.");
+ return false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception in registering AP callback: " + e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Send a management frame on the specified interface at the specified rate. Useful for probing
+ * the link with arbitrary frames.
+ *
+ * Note: The interface must have been already set up using
+ * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
+ * or {@link #setupInterfaceForSoftApMode(String)}.
+ *
+ * @param ifaceName The interface on which to send the frame.
+ * @param frame The raw byte array of the management frame to tramit.
+ * @param mcs The MCS (modulation and coding scheme), i.e. rate, at which to transmit the
+ * frame. Specified per IEEE 802.11.
+ * @param executor The Executor on which to execute the callbacks.
+ * @param callback A {@link SendMgmtFrameCallback} callback for results of the operation.
+ */
+ public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame, int mcs,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull SendMgmtFrameCallback callback) {
+
+ if (callback == null || executor == null) {
+ Log.e(TAG, "callback cannot be null!");
+ return;
+ }
+
+ if (frame == null) {
+ Log.e(TAG, "frame cannot be null!");
+ executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN));
+ return;
+ }
+
+ // TODO (b/112029045) validate mcs
+ IClientInterface clientInterface = getClientInterface(ifaceName);
+ if (clientInterface == null) {
+ Log.e(TAG, "No valid wificond client interface handler");
+ executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN));
+ return;
+ }
+
+ if (!mSendMgmtFrameInProgress.compareAndSet(false, true)) {
+ Log.e(TAG, "An existing management frame transmission is in progress!");
+ executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_ALREADY_STARTED));
+ return;
+ }
+
+ SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(executor, callback);
+ try {
+ clientInterface.SendMgmtFrame(frame, sendMgmtFrameEvent, mcs);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception while starting link probe: " + e);
+ // Call sendMgmtFrameEvent.OnFailure() instead of callback.onFailure() so that
+ // sendMgmtFrameEvent can clean up internal state, such as cancelling the timer.
+ sendMgmtFrameEvent.OnFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN);
+ }
+ }
+
+ /**
+ * Clear all internal handles.
+ */
+ private void clearState() {
+ // Refresh handlers
+ mClientInterfaces.clear();
+ mWificondScanners.clear();
+ mPnoScanEventHandlers.clear();
+ mScanEventHandlers.clear();
+ mApInterfaces.clear();
+ mApInterfaceListeners.clear();
+ mSendMgmtFrameInProgress.set(false);
+ }
+
+ /**
+ * OEM parsed security type
+ */
+ public static class OemSecurityType {
+ /** The protocol defined in {@link android.net.wifi.WifiAnnotations.Protocol}. */
+ public final @WifiAnnotations.Protocol int protocol;
+ /**
+ * Supported key management types defined
+ * in {@link android.net.wifi.WifiAnnotations.KeyMgmt}.
+ */
+ @NonNull public final List<Integer> keyManagement;
+ /**
+ * Supported pairwise cipher types defined
+ * in {@link android.net.wifi.WifiAnnotations.Cipher}.
+ */
+ @NonNull public final List<Integer> pairwiseCipher;
+ /** The group cipher type defined in {@link android.net.wifi.WifiAnnotations.Cipher}. */
+ public final @WifiAnnotations.Cipher int groupCipher;
+ /**
+ * Default constructor for OemSecurityType
+ *
+ * @param protocol The protocol defined in
+ * {@link android.net.wifi.WifiAnnotations.Protocol}.
+ * @param keyManagement Supported key management types defined
+ * in {@link android.net.wifi.WifiAnnotations.KeyMgmt}.
+ * @param pairwiseCipher Supported pairwise cipher types defined
+ * in {@link android.net.wifi.WifiAnnotations.Cipher}.
+ * @param groupCipher The group cipher type defined
+ * in {@link android.net.wifi.WifiAnnotations.Cipher}.
+ */
+ public OemSecurityType(
+ @WifiAnnotations.Protocol int protocol,
+ @NonNull List<Integer> keyManagement,
+ @NonNull List<Integer> pairwiseCipher,
+ @WifiAnnotations.Cipher int groupCipher) {
+ this.protocol = protocol;
+ this.keyManagement = (keyManagement != null)
+ ? keyManagement : new ArrayList<Integer>();
+ this.pairwiseCipher = (pairwiseCipher != null)
+ ? pairwiseCipher : new ArrayList<Integer>();
+ this.groupCipher = groupCipher;
+ }
+ }
+
+ /**
+ * OEM information element parser for security types not parsed by the framework.
+ *
+ * The OEM method should use the method inputs {@code id}, {@code idExt}, and {@code bytes}
+ * to perform the parsing. The method should place the results in an OemSecurityType objct.
+ *
+ * @param id The information element id.
+ * @param idExt The information element extension id. This is valid only when id is
+ * the extension id, {@code 255}.
+ * @param bytes The raw bytes of information element data, 'Element ID' and 'Length' are
+ * stripped off already.
+ * @return an OemSecurityType object if this IE is parsed successfully, null otherwise.
+ */
+ @Nullable public static OemSecurityType parseOemSecurityTypeElement(
+ int id,
+ int idExt,
+ @NonNull byte[] bytes) {
+ return null;
+ }
+}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index a59799b3fc54..d47989235f0b 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -17,6 +17,7 @@
package android.net.wifi.p2p;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -48,29 +49,39 @@ public class WifiP2pConfig implements Parcelable {
*/
public WpsInfo wps;
- /**
- * The network name of a group, should be configured by helper method
- */
+ /** Get the network name of this P2P configuration, or null if unset. */
+ @Nullable
+ public String getNetworkName() {
+ return networkName;
+ }
+
/** @hide */
public String networkName = "";
- /**
- * The passphrase of a group, should be configured by helper method
- */
+ /** Get the passphrase of this P2P configuration, or null if unset. */
+ @Nullable
+ public String getPassphrase() {
+ return passphrase;
+ }
+
/** @hide */
public String passphrase = "";
/**
- * The required band for Group Owner
+ * Get the required band for the group owner.
+ * The result will be one of the following:
+ * {@link #GROUP_OWNER_BAND_AUTO},
+ * {@link #GROUP_OWNER_BAND_2GHZ},
+ * {@link #GROUP_OWNER_BAND_5GHZ}
*/
- /** @hide */
- public int groupOwnerBand = GROUP_OWNER_BAND_AUTO;
+ @GroupOperatingBandType
+ public int getGroupOwnerBand() {
+ return groupOwnerBand;
+ }
/** @hide */
- public static final int MAX_GROUP_OWNER_INTENT = 15;
- /** @hide */
- @UnsupportedAppUsage
- public static final int MIN_GROUP_OWNER_INTENT = 0;
+ @GroupOperatingBandType
+ public int groupOwnerBand = GROUP_OWNER_BAND_AUTO;
/** @hide */
@IntDef(flag = false, prefix = { "GROUP_OWNER_BAND_" }, value = {
@@ -95,17 +106,49 @@ public class WifiP2pConfig implements Parcelable {
public static final int GROUP_OWNER_BAND_5GHZ = 2;
/**
- * This is an integer value between 0 and 15 where 0 indicates the least
- * inclination to be a group owner and 15 indicates the highest inclination
- * to be a group owner.
+ * The least inclination to be a group owner, to be filled in the field
+ * {@link #groupOwnerIntent}.
+ */
+ public static final int GROUP_OWNER_INTENT_MIN = 0;
+
+ /**
+ * The most inclination to be a group owner, to be filled in the field
+ * {@link #groupOwnerIntent}.
+ */
+ public static final int GROUP_OWNER_INTENT_MAX = 15;
+
+ /**
+ * The system can choose an appropriate owner intent value, to be filled in the field
+ * {@link #groupOwnerIntent}.
+ */
+ public static final int GROUP_OWNER_INTENT_AUTO = -1;
+
+ /**
+ * This is an integer value between {@link #GROUP_OWNER_INTENT_MIN} and
+ * {@link #GROUP_OWNER_INTENT_MAX} where
+ * {@link #GROUP_OWNER_INTENT_MIN} indicates the least inclination to be a group owner and
+ * {@link #GROUP_OWNER_INTENT_MAX} indicates the highest inclination to be a group owner.
*
- * A value of -1 indicates the system can choose an appropriate value.
+ * A value of {@link #GROUP_OWNER_INTENT_AUTO} indicates the system can choose an appropriate
+ * value.
+ *
+ * By default this field is set to {@link #GROUP_OWNER_INTENT_AUTO}.
*/
- public int groupOwnerIntent = -1;
+ @IntRange(from = 0, to = 15)
+ public int groupOwnerIntent = GROUP_OWNER_INTENT_AUTO;
/** @hide */
@UnsupportedAppUsage
- public int netId = WifiP2pGroup.PERSISTENT_NET_ID;
+ public int netId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
+
+ /**
+ * Get the network ID of this P2P configuration.
+ * @return either a non-negative network ID, or one of
+ * {@link WifiP2pGroup#NETWORK_ID_PERSISTENT} or {@link WifiP2pGroup#NETWORK_ID_TEMPORARY}.
+ */
+ public int getNetworkId() {
+ return netId;
+ }
public WifiP2pConfig() {
//set defaults
@@ -239,7 +282,7 @@ public class WifiP2pConfig implements Parcelable {
private String mPassphrase = "";
private int mGroupOperatingBand = GROUP_OWNER_BAND_AUTO;
private int mGroupOperatingFrequency = GROUP_OWNER_BAND_AUTO;
- private int mNetId = WifiP2pGroup.TEMPORARY_NET_ID;
+ private int mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
/**
* Specify the peer's MAC address. If not set, the device will
@@ -419,9 +462,9 @@ public class WifiP2pConfig implements Parcelable {
*/
public @NonNull Builder enablePersistentMode(boolean persistent) {
if (persistent) {
- mNetId = WifiP2pGroup.PERSISTENT_NET_ID;
+ mNetId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
} else {
- mNetId = WifiP2pGroup.TEMPORARY_NET_ID;
+ mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
}
return this;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 69aefcce4f5b..710175fee747 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -16,6 +16,8 @@
package android.net.wifi.p2p;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -237,6 +239,12 @@ public class WifiP2pDevice implements Parcelable {
}
}
+ /** The Wifi Display information for this device, or null if unavailable. */
+ @Nullable
+ public WifiP2pWfdInfo getWfdInfo() {
+ return wfdInfo;
+ }
+
/** Returns true if WPS push button configuration is supported */
public boolean wpsPbcSupported() {
return (wpsConfigMethodsSupported & WPS_CONFIG_PUSHBUTTON) != 0;
@@ -278,14 +286,13 @@ public class WifiP2pDevice implements Parcelable {
}
/**
- * Update device details. This will be throw an exception if the device address
- * does not match.
- * @param device to be updated
- * @throws IllegalArgumentException if the device is null or device address does not match
- * @hide
+ * Update this device's details using another {@link WifiP2pDevice} instance.
+ * This will throw an exception if the device address does not match.
+ *
+ * @param device another instance of {@link WifiP2pDevice} used to update this instance.
+ * @throws IllegalArgumentException if the device is null or the device address does not match
*/
- @UnsupportedAppUsage
- public void update(WifiP2pDevice device) {
+ public void update(@NonNull WifiP2pDevice device) {
updateSupplicantDetails(device);
status = device.status;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index b292da193a89..e497b22d7769 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -16,6 +16,7 @@
package android.net.wifi.p2p;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -36,16 +37,27 @@ import java.util.regex.Pattern;
*/
public class WifiP2pGroup implements Parcelable {
- /** The temporary network id.
- * {@hide} */
+ /**
+ * The temporary network id.
+ * @see #getNetworkId()
+ */
+ public static final int NETWORK_ID_TEMPORARY = -1;
+
+ /**
+ * The temporary network id.
+ *
+ * @hide
+ */
@UnsupportedAppUsage
- public static final int TEMPORARY_NET_ID = -1;
+ public static final int TEMPORARY_NET_ID = NETWORK_ID_TEMPORARY;
- /** The persistent network id.
+ /**
+ * The persistent network id.
* If a matching persistent profile is found, use it.
* Otherwise, create a new persistent profile.
- * {@hide} */
- public static final int PERSISTENT_NET_ID = -2;
+ * @see #getNetworkId()
+ */
+ public static final int NETWORK_ID_PERSISTENT = -2;
/** The network name */
private String mNetworkName;
@@ -64,7 +76,7 @@ public class WifiP2pGroup implements Parcelable {
private String mInterface;
- /** The network id in the wpa_supplicant */
+ /** The network ID in wpa_supplicant */
private int mNetId;
/** The frequency (in MHz) used by this group */
@@ -126,13 +138,13 @@ public class WifiP2pGroup implements Parcelable {
mPassphrase = match.group(4);
mOwner = new WifiP2pDevice(match.group(5));
if (match.group(6) != null) {
- mNetId = PERSISTENT_NET_ID;
+ mNetId = NETWORK_ID_PERSISTENT;
} else {
- mNetId = TEMPORARY_NET_ID;
+ mNetId = NETWORK_ID_TEMPORARY;
}
} else if (tokens[0].equals("P2P-INVITATION-RECEIVED")) {
String sa = null;
- mNetId = PERSISTENT_NET_ID;
+ mNetId = NETWORK_ID_PERSISTENT;
for (String token : tokens) {
String[] nameValue = token.split("=");
if (nameValue.length != 2) continue;
@@ -225,10 +237,13 @@ public class WifiP2pGroup implements Parcelable {
return mClients.size() == 0;
}
- /** @hide Returns {@code true} if the device is part of the group */
- public boolean contains(WifiP2pDevice device) {
- if (mOwner.equals(device) || mClients.contains(device)) return true;
- return false;
+ /**
+ * Returns {@code true} if the device is part of the group, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean contains(@Nullable WifiP2pDevice device) {
+ return mOwner.equals(device) || mClients.contains(device);
}
/** Get the list of clients currently part of the p2p group */
@@ -261,8 +276,7 @@ public class WifiP2pGroup implements Parcelable {
return mInterface;
}
- /** @hide */
- @UnsupportedAppUsage
+ /** The network ID of the P2P group in wpa_supplicant. */
public int getNetworkId() {
return mNetId;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl
deleted file mode 100644
index 3d8a47682f6e..000000000000
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.p2p;
-
-parcelable WifiP2pGroupList; \ No newline at end of file
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
index 6068d3a2f697..8a86311defca 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
@@ -15,12 +15,16 @@
*/
package android.net.wifi.p2p;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.LruCache;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
@@ -30,7 +34,8 @@ import java.util.Map;
* {@see WifiP2pManager}
* @hide
*/
-public class WifiP2pGroupList implements Parcelable {
+@SystemApi
+public final class WifiP2pGroupList implements Parcelable {
private static final int CREDENTIAL_MAX_NUM = 32;
@@ -40,6 +45,7 @@ public class WifiP2pGroupList implements Parcelable {
private boolean isClearCalled = false;
+ /** @hide */
public interface GroupDeleteListener {
public void onDeleteGroup(int netId);
}
@@ -71,13 +77,11 @@ public class WifiP2pGroupList implements Parcelable {
}
/**
- * Return the list of p2p group.
- *
- * @return the list of p2p group.
+ * Get the list of P2P groups.
*/
- @UnsupportedAppUsage
- public Collection<WifiP2pGroup> getGroupList() {
- return mGroups.snapshot().values();
+ @NonNull
+ public List<WifiP2pGroup> getGroupList() {
+ return new ArrayList<>(mGroups.snapshot().values());
}
/**
@@ -206,6 +210,7 @@ public class WifiP2pGroupList implements Parcelable {
return false;
}
+ @Override
public String toString() {
StringBuffer sbuf = new StringBuffer();
@@ -217,12 +222,14 @@ public class WifiP2pGroupList implements Parcelable {
}
/** Implement the Parcelable interface */
+ @Override
public int describeContents() {
return 0;
}
/** Implement the Parcelable interface */
- public void writeToParcel(Parcel dest, int flags) {
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
dest.writeInt(groups.size());
for(WifiP2pGroup group : groups) {
@@ -231,7 +238,7 @@ public class WifiP2pGroupList implements Parcelable {
}
/** Implement the Parcelable interface */
- public static final @android.annotation.NonNull Creator<WifiP2pGroupList> CREATOR =
+ public static final @NonNull Creator<WifiP2pGroupList> CREATOR =
new Creator<WifiP2pGroupList>() {
public WifiP2pGroupList createFromParcel(Parcel in) {
WifiP2pGroupList grpList = new WifiP2pGroupList();
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index eec4a0007d8e..724ccf0d7c45 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -43,15 +44,15 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.text.TextUtils;
+import android.util.CloseGuard;
import android.util.Log;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
-import dalvik.system.CloseGuard;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.Reference;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -325,10 +326,17 @@ public class WifiP2pManager {
/**
* Broadcast intent action indicating that remembered persistent groups have changed.
+ *
+ * You can <em>not</em> receive this through components declared
+ * in manifests, only by explicitly registering for it with
+ * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,
+ * android.content.IntentFilter) Context.registerReceiver()}.
+ *
* @hide
*/
- public static final String WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION =
- "android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED";
+ @SystemApi
+ public static final String ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED =
+ "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED";
/**
* The lookup key for a handover message returned by the WifiP2pService.
@@ -345,6 +353,13 @@ public class WifiP2pManager {
"android.net.wifi.p2p.CALLING_PACKAGE";
/**
+ * The lookup key for a calling feature id from WifiP2pManager
+ * @hide
+ */
+ public static final String CALLING_FEATURE_ID =
+ "android.net.wifi.p2p.CALLING_FEATURE_ID";
+
+ /**
* The lookup key for a calling package binder from WifiP2pManager
* @hide
*/
@@ -749,13 +764,18 @@ public class WifiP2pManager {
}
- /** Interface for callback invocation when stored group info list is available {@hide}*/
+ /**
+ * Interface for callback invocation when stored group info list is available
+ *
+ * @hide
+ */
+ @SystemApi
public interface PersistentGroupInfoListener {
/**
* The requested stored p2p group info list is available
* @param groups Wi-Fi p2p group info list
*/
- public void onPersistentGroupInfoAvailable(WifiP2pGroupList groups);
+ void onPersistentGroupInfoAvailable(@NonNull WifiP2pGroupList groups);
}
/**
@@ -855,7 +875,7 @@ public class WifiP2pManager {
private final Object mListenerMapLock = new Object();
private int mListenerKey = 0;
- private final CloseGuard mCloseGuard = CloseGuard.get();
+ private final CloseGuard mCloseGuard = new CloseGuard();
/**
* Close the current P2P connection and indicate to the P2P service that connections
@@ -874,6 +894,7 @@ public class WifiP2pManager {
mAsyncChannel.disconnect();
mCloseGuard.close();
+ Reference.reachabilityFence(this);
}
/** @hide */
@@ -1159,6 +1180,7 @@ public class WifiP2pManager {
== AsyncChannel.STATUS_SUCCESSFUL) {
Bundle bundle = new Bundle();
bundle.putString(CALLING_PACKAGE, c.mContext.getOpPackageName());
+ bundle.putString(CALLING_FEATURE_ID, c.mContext.getAttributionTag());
bundle.putBinder(CALLING_BINDER, binder);
c.mAsyncChannel.sendMessage(UPDATE_CHANNEL_INFO, 0,
c.putListener(null), bundle);
@@ -1194,7 +1216,7 @@ public class WifiP2pManager {
c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
}
- /**
+ /**
* Stop an ongoing peer discovery
*
* <p> The function call immediately returns after sending a stop request
@@ -1277,7 +1299,7 @@ public class WifiP2pManager {
@RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
public void createGroup(Channel c, ActionListener listener) {
checkChannel(c);
- c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.PERSISTENT_NET_ID,
+ c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.NETWORK_ID_PERSISTENT,
c.putListener(listener));
}
@@ -1331,28 +1353,57 @@ public class WifiP2pManager {
}
/**
- * Force p2p to enter or exit listen state
+ * Force p2p to enter listen state
*
* @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}
- * @param enable enables or disables listening
* @param listener for callbacks on success or failure. Can be null.
*
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void listen(Channel c, boolean enable, ActionListener listener) {
+ public void startListening(@NonNull Channel c, @Nullable ActionListener listener) {
checkChannel(c);
- c.mAsyncChannel.sendMessage(enable ? START_LISTEN : STOP_LISTEN,
- 0, c.putListener(listener));
+ c.mAsyncChannel.sendMessage(START_LISTEN, 0, c.putListener(listener));
}
- /** @hide */
- @UnsupportedAppUsage
- public void setWifiP2pChannels(Channel c, int lc, int oc, ActionListener listener) {
+ /**
+ * Force p2p to exit listen state
+ *
+ * @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}
+ * @param listener for callbacks on success or failure. Can be null.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void stopListening(@NonNull Channel c, @Nullable ActionListener listener) {
+ checkChannel(c);
+ c.mAsyncChannel.sendMessage(STOP_LISTEN, 0, c.putListener(listener));
+ }
+
+ /**
+ * Set P2P listening and operating channel.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listeningChannel the listening channel's Wifi channel number. e.g. 1, 6, 11.
+ * @param operatingChannel the operating channel's Wifi channel number. e.g. 1, 6, 11.
+ * @param listener for callbacks on success or failure. Can be null.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.OVERRIDE_WIFI_CONFIG
+ })
+ public void setWifiP2pChannels(@NonNull Channel c, int listeningChannel, int operatingChannel,
+ @Nullable ActionListener listener) {
checkChannel(c);
Bundle p2pChannels = new Bundle();
- p2pChannels.putInt("lc", lc);
- p2pChannels.putInt("oc", oc);
+ p2pChannels.putInt("lc", listeningChannel);
+ p2pChannels.putInt("oc", operatingChannel);
c.mAsyncChannel.sendMessage(SET_CHANNEL, 0, c.putListener(listener), p2pChannels);
}
@@ -1610,23 +1661,47 @@ public class WifiP2pManager {
/**
* Set p2p device name.
- * @hide
+ *
* @param c is the channel created at {@link #initialize}
* @param listener for callback when group info is available. Can be null.
+ *
+ * @hide
*/
- @UnsupportedAppUsage
- public void setDeviceName(Channel c, String devName, ActionListener listener) {
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.OVERRIDE_WIFI_CONFIG
+ })
+ public void setDeviceName(@NonNull Channel c, @NonNull String devName,
+ @Nullable ActionListener listener) {
checkChannel(c);
WifiP2pDevice d = new WifiP2pDevice();
d.deviceName = devName;
c.mAsyncChannel.sendMessage(SET_DEVICE_NAME, 0, c.putListener(listener), d);
}
+ /**
+ * Set Wifi Display information.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param wfdInfo the Wifi Display information to set
+ * @param listener for callbacks on success or failure. Can be null.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ public void setWfdInfo(@NonNull Channel c, @NonNull WifiP2pWfdInfo wfdInfo,
+ @Nullable ActionListener listener) {
+ setWFDInfo(c, wfdInfo, listener);
+ }
+
/** @hide */
@UnsupportedAppUsage
- public void setWFDInfo(
- Channel c, WifiP2pWfdInfo wfdInfo,
- ActionListener listener) {
+ @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ public void setWFDInfo(@NonNull Channel c, @NonNull WifiP2pWfdInfo wfdInfo,
+ @Nullable ActionListener listener) {
checkChannel(c);
try {
mService.checkConfigureWifiDisplayPermission();
@@ -1650,12 +1725,19 @@ public class WifiP2pManager {
* a network id can be obtained by {@link WifiP2pGroup#getNetworkId()}.
*
* @param c is the channel created at {@link #initialize}
- * @param netId he network id of the p2p group.
+ * @param netId the network id of the p2p group.
* @param listener for callbacks on success or failure. Can be null.
+ *
* @hide
*/
- @UnsupportedAppUsage
- public void deletePersistentGroup(Channel c, int netId, ActionListener listener) {
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.OVERRIDE_WIFI_CONFIG
+ })
+ public void deletePersistentGroup(@NonNull Channel c, int netId,
+ @Nullable ActionListener listener) {
checkChannel(c);
c.mAsyncChannel.sendMessage(DELETE_PERSISTENT_GROUP, netId, c.putListener(listener));
}
@@ -1665,23 +1747,66 @@ public class WifiP2pManager {
*
* @param c is the channel created at {@link #initialize}
* @param listener for callback when persistent group info list is available. Can be null.
+ *
* @hide
*/
- @UnsupportedAppUsage
- public void requestPersistentGroupInfo(Channel c, PersistentGroupInfoListener listener) {
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.READ_WIFI_CREDENTIAL
+ })
+ public void requestPersistentGroupInfo(@NonNull Channel c,
+ @Nullable PersistentGroupInfoListener listener) {
checkChannel(c);
c.mAsyncChannel.sendMessage(REQUEST_PERSISTENT_GROUP_INFO, 0, c.putListener(listener));
}
/** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"MIRACAST_"}, value = {
+ MIRACAST_DISABLED,
+ MIRACAST_SOURCE,
+ MIRACAST_SINK})
+ public @interface MiracastMode {}
+
+ /**
+ * Miracast is disabled.
+ * @hide
+ */
+ @SystemApi
public static final int MIRACAST_DISABLED = 0;
- /** @hide */
+ /**
+ * Device acts as a Miracast source.
+ * @hide
+ */
+ @SystemApi
public static final int MIRACAST_SOURCE = 1;
- /** @hide */
+ /**
+ * Device acts as a Miracast sink.
+ * @hide
+ */
+ @SystemApi
public static final int MIRACAST_SINK = 2;
- /** Internal use only @hide */
- @UnsupportedAppUsage
- public void setMiracastMode(int mode) {
+
+ /**
+ * This is used to provide information to drivers to optimize performance depending
+ * on the current mode of operation.
+ * {@link #MIRACAST_DISABLED} - disabled
+ * {@link #MIRACAST_SOURCE} - source operation
+ * {@link #MIRACAST_SINK} - sink operation
+ *
+ * As an example, the driver could reduce the channel dwell time during scanning
+ * when acting as a source or sink to minimize impact on Miracast.
+ *
+ * @param mode mode of operation. One of {@link #MIRACAST_DISABLED}, {@link #MIRACAST_SOURCE},
+ * or {@link #MIRACAST_SINK}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ public void setMiracastMode(@MiracastMode int mode) {
try {
mService.setMiracastMode(mode);
} catch (RemoteException e) {
@@ -1770,8 +1895,10 @@ public class WifiP2pManager {
*
* @param c is the channel created at {@link #initialize}.
* @param listener for callback on success or failure. Can be null.
+ *
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void factoryReset(@NonNull Channel c, @Nullable ActionListener listener) {
checkChannel(c);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
index 7a5f909f93ae..e399b5b9afa6 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -16,75 +16,116 @@
package android.net.wifi.p2p;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
/**
- * A class representing Wifi Display information for a device
- * @hide
+ * A class representing Wifi Display information for a device.
+ *
+ * See Wifi Display technical specification v1.0.0, section 5.1.2.
*/
-public class WifiP2pWfdInfo implements Parcelable {
-
- private static final String TAG = "WifiP2pWfdInfo";
+public final class WifiP2pWfdInfo implements Parcelable {
- private boolean mWfdEnabled;
+ private boolean mEnabled;
+ /** Device information bitmap */
private int mDeviceInfo;
- public static final int WFD_SOURCE = 0;
- public static final int PRIMARY_SINK = 1;
- public static final int SECONDARY_SINK = 2;
- public static final int SOURCE_OR_PRIMARY_SINK = 3;
-
- /* Device information bitmap */
- /** One of {@link #WFD_SOURCE}, {@link #PRIMARY_SINK}, {@link #SECONDARY_SINK}
- * or {@link #SOURCE_OR_PRIMARY_SINK}
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "DEVICE_TYPE_" }, value = {
+ DEVICE_TYPE_WFD_SOURCE,
+ DEVICE_TYPE_PRIMARY_SINK,
+ DEVICE_TYPE_SECONDARY_SINK,
+ DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK})
+ public @interface DeviceType {}
+
+ /** The device is a Wifi Display Source. */
+ public static final int DEVICE_TYPE_WFD_SOURCE = 0;
+ /** The device is a primary sink. */
+ public static final int DEVICE_TYPE_PRIMARY_SINK = 1;
+ /** The device is a secondary sink. */
+ public static final int DEVICE_TYPE_SECONDARY_SINK = 2;
+ /** The device is dual-role capable i.e. either a WFD source or a primary sink. */
+ public static final int DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK = 3;
+
+ /**
+ * {@link #mDeviceInfo} & {@link #DEVICE_TYPE} is one of {@link #DEVICE_TYPE_WFD_SOURCE},
+ * {@link #DEVICE_TYPE_PRIMARY_SINK}, {@link #DEVICE_TYPE_SECONDARY_SINK} or
+ * {@link #DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK}.
+ *
+ * The bit definition is listed in 5.1.2 WFD Device Information Subelement in
+ * Wi-Fi Display Technical Specification.
*/
- private static final int DEVICE_TYPE = 0x3;
- private static final int COUPLED_SINK_SUPPORT_AT_SOURCE = 0x4;
- private static final int COUPLED_SINK_SUPPORT_AT_SINK = 0x8;
- private static final int SESSION_AVAILABLE = 0x30;
- private static final int SESSION_AVAILABLE_BIT1 = 0x10;
- private static final int SESSION_AVAILABLE_BIT2 = 0x20;
+ private static final int DEVICE_TYPE = 1 << 1 | 1 << 0;
+ private static final int COUPLED_SINK_SUPPORT_AT_SOURCE = 1 << 2;
+ private static final int COUPLED_SINK_SUPPORT_AT_SINK = 1 << 3;
+ private static final int SESSION_AVAILABLE_BIT1 = 1 << 4;
+ private static final int SESSION_AVAILABLE_BIT2 = 1 << 5;
+ private static final int SESSION_AVAILABLE =
+ SESSION_AVAILABLE_BIT2 | SESSION_AVAILABLE_BIT1;
+ /* The support of Content Protection using the HDCP system 2.0/2.1. */
+ private static final int CONTENT_PROTECTION_SUPPORT = 1 << 8;
private int mCtrlPort;
private int mMaxThroughput;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public WifiP2pWfdInfo() {
- }
+ /** Default constructor. */
+ public WifiP2pWfdInfo() {}
+ /** @hide */
@UnsupportedAppUsage
public WifiP2pWfdInfo(int devInfo, int ctrlPort, int maxTput) {
- mWfdEnabled = true;
+ mEnabled = true;
mDeviceInfo = devInfo;
mCtrlPort = ctrlPort;
mMaxThroughput = maxTput;
}
- @UnsupportedAppUsage
- public boolean isWfdEnabled() {
- return mWfdEnabled;
+ /** Returns true is Wifi Display is enabled, false otherwise. */
+ public boolean isEnabled() {
+ return mEnabled;
}
- @UnsupportedAppUsage
- public void setWfdEnabled(boolean enabled) {
- mWfdEnabled = enabled;
+ /**
+ * Sets whether Wifi Display should be enabled.
+ *
+ * @param enabled true to enable Wifi Display, false to disable
+ */
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
}
- @UnsupportedAppUsage
+ /**
+ * Get the type of the device.
+ * One of {@link #DEVICE_TYPE_WFD_SOURCE}, {@link #DEVICE_TYPE_PRIMARY_SINK},
+ * {@link #DEVICE_TYPE_SECONDARY_SINK}, {@link #DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK}
+ */
+ @DeviceType
public int getDeviceType() {
- return (mDeviceInfo & DEVICE_TYPE);
+ return mDeviceInfo & DEVICE_TYPE;
}
- @UnsupportedAppUsage
- public boolean setDeviceType(int deviceType) {
- if (deviceType >= WFD_SOURCE && deviceType <= SOURCE_OR_PRIMARY_SINK) {
+ /**
+ * Sets the type of the device.
+ *
+ * @param deviceType One of {@link #DEVICE_TYPE_WFD_SOURCE}, {@link #DEVICE_TYPE_PRIMARY_SINK},
+ * {@link #DEVICE_TYPE_SECONDARY_SINK}, {@link #DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK}
+ * @return true if the device type was successfully set, false otherwise
+ */
+ public boolean setDeviceType(@DeviceType int deviceType) {
+ if (DEVICE_TYPE_WFD_SOURCE <= deviceType
+ && deviceType <= DEVICE_TYPE_SOURCE_OR_PRIMARY_SINK) {
mDeviceInfo &= ~DEVICE_TYPE;
mDeviceInfo |= deviceType;
return true;
@@ -92,35 +133,16 @@ public class WifiP2pWfdInfo implements Parcelable {
return false;
}
- public boolean isCoupledSinkSupportedAtSource() {
- return (mDeviceInfo & COUPLED_SINK_SUPPORT_AT_SINK) != 0;
- }
-
- public void setCoupledSinkSupportAtSource(boolean enabled) {
- if (enabled ) {
- mDeviceInfo |= COUPLED_SINK_SUPPORT_AT_SINK;
- } else {
- mDeviceInfo &= ~COUPLED_SINK_SUPPORT_AT_SINK;
- }
- }
-
- public boolean isCoupledSinkSupportedAtSink() {
- return (mDeviceInfo & COUPLED_SINK_SUPPORT_AT_SINK) != 0;
- }
-
- public void setCoupledSinkSupportAtSink(boolean enabled) {
- if (enabled ) {
- mDeviceInfo |= COUPLED_SINK_SUPPORT_AT_SINK;
- } else {
- mDeviceInfo &= ~COUPLED_SINK_SUPPORT_AT_SINK;
- }
- }
-
+ /** Returns true if a session is available, false otherwise. */
public boolean isSessionAvailable() {
return (mDeviceInfo & SESSION_AVAILABLE) != 0;
}
- @UnsupportedAppUsage
+ /**
+ * Sets whether a session is available.
+ *
+ * @param enabled true to indicate that a session is available, false otherwise.
+ */
public void setSessionAvailable(boolean enabled) {
if (enabled) {
mDeviceInfo |= SESSION_AVAILABLE_BIT1;
@@ -130,32 +152,56 @@ public class WifiP2pWfdInfo implements Parcelable {
}
}
+ /**
+ * @return true if Content Protection using the HDCP system 2.0/2.1 is supported.
+ */
+ public boolean isContentProtectionSupported() {
+ return (mDeviceInfo & CONTENT_PROTECTION_SUPPORT) != 0;
+ }
+
+ /**
+ * Sets whether Content Protection using the HDCP system 2.0/2.1 is supported.
+ *
+ * @param enabled true to indicate that Content Protection is supported, false otherwise.
+ */
+ public void setContentProtectionSupported(boolean enabled) {
+ if (enabled) {
+ mDeviceInfo |= CONTENT_PROTECTION_SUPPORT;
+ } else {
+ mDeviceInfo &= ~CONTENT_PROTECTION_SUPPORT;
+ }
+ }
+
+ /** Returns the TCP port at which the WFD Device listens for RTSP messages. */
public int getControlPort() {
return mCtrlPort;
}
- @UnsupportedAppUsage
- public void setControlPort(int port) {
+ /** Sets the TCP port at which the WFD Device listens for RTSP messages. */
+ public void setControlPort(@IntRange(from = 0) int port) {
mCtrlPort = port;
}
- @UnsupportedAppUsage
- public void setMaxThroughput(int maxThroughput) {
+ /** Sets the maximum average throughput capability of the WFD Device, in megabits/second. */
+ public void setMaxThroughput(@IntRange(from = 0) int maxThroughput) {
mMaxThroughput = maxThroughput;
}
+ /** Returns the maximum average throughput capability of the WFD Device, in megabits/second. */
public int getMaxThroughput() {
return mMaxThroughput;
}
+ /** @hide */
public String getDeviceInfoHex() {
return String.format(
Locale.US, "%04x%04x%04x", mDeviceInfo, mCtrlPort, mMaxThroughput);
}
+ @Override
public String toString() {
StringBuffer sbuf = new StringBuffer();
- sbuf.append("WFD enabled: ").append(mWfdEnabled);
+ sbuf.append("WFD enabled: ").append(mEnabled);
sbuf.append("WFD DeviceInfo: ").append(mDeviceInfo);
sbuf.append("\n WFD CtrlPort: ").append(mCtrlPort);
sbuf.append("\n WFD MaxThroughput: ").append(mMaxThroughput);
@@ -167,11 +213,10 @@ public class WifiP2pWfdInfo implements Parcelable {
return 0;
}
- /** copy constructor */
- @UnsupportedAppUsage
- public WifiP2pWfdInfo(WifiP2pWfdInfo source) {
+ /** Copy constructor. */
+ public WifiP2pWfdInfo(@Nullable WifiP2pWfdInfo source) {
if (source != null) {
- mWfdEnabled = source.mWfdEnabled;
+ mEnabled = source.mEnabled;
mDeviceInfo = source.mDeviceInfo;
mCtrlPort = source.mCtrlPort;
mMaxThroughput = source.mMaxThroughput;
@@ -179,23 +224,23 @@ public class WifiP2pWfdInfo implements Parcelable {
}
/** Implement the Parcelable interface */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mWfdEnabled ? 1 : 0);
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mEnabled ? 1 : 0);
dest.writeInt(mDeviceInfo);
dest.writeInt(mCtrlPort);
dest.writeInt(mMaxThroughput);
}
- public void readFromParcel(Parcel in) {
- mWfdEnabled = (in.readInt() == 1);
+ private void readFromParcel(Parcel in) {
+ mEnabled = (in.readInt() == 1);
mDeviceInfo = in.readInt();
mCtrlPort = in.readInt();
mMaxThroughput = in.readInt();
}
/** Implement the Parcelable interface */
- @UnsupportedAppUsage
- public static final @android.annotation.NonNull Creator<WifiP2pWfdInfo> CREATOR =
+ public static final @NonNull Creator<WifiP2pWfdInfo> CREATOR =
new Creator<WifiP2pWfdInfo>() {
public WifiP2pWfdInfo createFromParcel(Parcel in) {
WifiP2pWfdInfo device = new WifiP2pWfdInfo();
diff --git a/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
index 3e37af06ab27..7c92a6b6bdba 100644
--- a/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
+++ b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
@@ -27,7 +27,7 @@ import android.net.wifi.rtt.RangingRequest;
interface IWifiRttManager
{
boolean isAvailable();
- void startRanging(in IBinder binder, in String callingPackage, in WorkSource workSource,
- in RangingRequest request, in IRttCallback callback);
+ void startRanging(in IBinder binder, in String callingPackage, in String callingFeatureId,
+ in WorkSource workSource, in RangingRequest request, in IRttCallback callback);
void cancelRanging(in WorkSource workSource);
}
diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.java b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
index 64dfc3499aaf..be4eeccd0c31 100644
--- a/wifi/java/android/net/wifi/rtt/ResponderConfig.java
+++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
@@ -16,6 +16,8 @@
package android.net.wifi.rtt;
+import static android.net.wifi.ScanResult.InformationElement.EID_EXTENSION_PRESENT;
+import static android.net.wifi.ScanResult.InformationElement.EID_EXT_HE_CAPABILITIES;
import static android.net.wifi.ScanResult.InformationElement.EID_HT_CAPABILITIES;
import static android.net.wifi.ScanResult.InformationElement.EID_VHT_CAPABILITIES;
@@ -106,7 +108,7 @@ public final class ResponderConfig implements Parcelable {
public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
/** @hide */
- @IntDef({PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT})
+ @IntDef({PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT, PREAMBLE_HE})
@Retention(RetentionPolicy.SOURCE)
public @interface PreambleType {
}
@@ -126,6 +128,10 @@ public final class ResponderConfig implements Parcelable {
*/
public static final int PREAMBLE_VHT = 2;
+ /**
+ * Preamble type: HE.
+ */
+ public static final int PREAMBLE_HE = 3;
/**
* The MAC address of the Responder. Will be null if a Wi-Fi Aware peer identifier (the
@@ -307,14 +313,21 @@ public final class ResponderConfig implements Parcelable {
if (scanResult.informationElements != null && scanResult.informationElements.length != 0) {
boolean htCapabilitiesPresent = false;
boolean vhtCapabilitiesPresent = false;
+ boolean heCapabilitiesPresent = false;
+
for (ScanResult.InformationElement ie : scanResult.informationElements) {
if (ie.id == EID_HT_CAPABILITIES) {
htCapabilitiesPresent = true;
} else if (ie.id == EID_VHT_CAPABILITIES) {
vhtCapabilitiesPresent = true;
+ } else if (ie.id == EID_EXTENSION_PRESENT && ie.idExt == EID_EXT_HE_CAPABILITIES) {
+ heCapabilitiesPresent = true;
}
}
- if (vhtCapabilitiesPresent) {
+
+ if (heCapabilitiesPresent) {
+ preamble = PREAMBLE_HE;
+ } else if (vhtCapabilitiesPresent) {
preamble = PREAMBLE_VHT;
} else if (htCapabilitiesPresent) {
preamble = PREAMBLE_HT;
diff --git a/wifi/java/android/net/wifi/rtt/ResponderLocation.java b/wifi/java/android/net/wifi/rtt/ResponderLocation.java
index 970a75d7c418..218b2dcae71d 100644
--- a/wifi/java/android/net/wifi/rtt/ResponderLocation.java
+++ b/wifi/java/android/net/wifi/rtt/ResponderLocation.java
@@ -21,6 +21,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.location.Address;
import android.location.Location;
@@ -1367,7 +1368,8 @@ public final class ResponderLocation implements Parcelable {
*
*/
@Nullable
- public SparseArray toCivicLocationSparseArray() {
+ @SuppressLint("ChangedType")
+ public SparseArray<String> toCivicLocationSparseArray() {
if (mCivicLocation != null && mCivicLocation.isValid()) {
return mCivicLocation.toSparseArray();
} else {
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index 457e904126a2..865702af695c 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -77,7 +77,7 @@ public class WifiRttManager {
"android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED";
/** @hide */
- public WifiRttManager(Context context, IWifiRttManager service) {
+ public WifiRttManager(@NonNull Context context, @NonNull IWifiRttManager service) {
mContext = context;
mService = service;
}
@@ -146,8 +146,8 @@ public class WifiRttManager {
Binder binder = new Binder();
try {
- mService.startRanging(binder, mContext.getOpPackageName(), workSource, request,
- new IRttCallback.Stub() {
+ mService.startRanging(binder, mContext.getOpPackageName(),
+ mContext.getAttributionTag(), workSource, request, new IRttCallback.Stub() {
@Override
public void onRangingFailure(int status) throws RemoteException {
clearCallingIdentity();
diff --git a/wifi/java/android/net/wifi/util/HexEncoding.java b/wifi/java/android/net/wifi/util/HexEncoding.java
new file mode 100644
index 000000000000..9ebf947e2dc3
--- /dev/null
+++ b/wifi/java/android/net/wifi/util/HexEncoding.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.util;
+
+/**
+ * Hexadecimal encoding where each byte is represented by two hexadecimal digits.
+ *
+ * Note: this is copied from {@link libcore.util.HexEncoding}.
+ *
+ * @hide
+ */
+public class HexEncoding {
+
+ private static final char[] LOWER_CASE_DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ private static final char[] UPPER_CASE_DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ /** Hidden constructor to prevent instantiation. */
+ private HexEncoding() {}
+
+ /**
+ * Encodes the provided byte as a two-digit hexadecimal String value.
+ */
+ public static String encodeToString(byte b, boolean upperCase) {
+ char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;
+ char[] buf = new char[2]; // We always want two digits.
+ buf[0] = digits[(b >> 4) & 0xf];
+ buf[1] = digits[b & 0xf];
+ return new String(buf, 0, 2);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ */
+ public static char[] encode(byte[] data) {
+ return encode(data, 0, data.length, true /* upperCase */);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ */
+ public static char[] encode(byte[] data, boolean upperCase) {
+ return encode(data, 0, data.length, upperCase);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ */
+ public static char[] encode(byte[] data, int offset, int len) {
+ return encode(data, offset, len, true /* upperCase */);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ */
+ private static char[] encode(byte[] data, int offset, int len, boolean upperCase) {
+ char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;
+ char[] result = new char[len * 2];
+ for (int i = 0; i < len; i++) {
+ byte b = data[offset + i];
+ int resultIndex = 2 * i;
+ result[resultIndex] = (digits[(b >> 4) & 0x0f]);
+ result[resultIndex + 1] = (digits[b & 0x0f]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ */
+ public static String encodeToString(byte[] data) {
+ return encodeToString(data, true /* upperCase */);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ */
+ public static String encodeToString(byte[] data, boolean upperCase) {
+ return new String(encode(data, upperCase));
+ }
+
+ /**
+ * Decodes the provided hexadecimal string into a byte array. Odd-length inputs
+ * are not allowed.
+ *
+ * Throws an {@code IllegalArgumentException} if the input is malformed.
+ */
+ public static byte[] decode(String encoded) throws IllegalArgumentException {
+ return decode(encoded.toCharArray());
+ }
+
+ /**
+ * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}
+ * is {@code true} odd-length inputs are allowed and the first character is interpreted
+ * as the lower bits of the first result byte.
+ *
+ * Throws an {@code IllegalArgumentException} if the input is malformed.
+ */
+ public static byte[] decode(String encoded, boolean allowSingleChar)
+ throws IllegalArgumentException {
+ return decode(encoded.toCharArray(), allowSingleChar);
+ }
+
+ /**
+ * Decodes the provided hexadecimal string into a byte array. Odd-length inputs
+ * are not allowed.
+ *
+ * Throws an {@code IllegalArgumentException} if the input is malformed.
+ */
+ public static byte[] decode(char[] encoded) throws IllegalArgumentException {
+ return decode(encoded, false);
+ }
+
+ /**
+ * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}
+ * is {@code true} odd-length inputs are allowed and the first character is interpreted
+ * as the lower bits of the first result byte.
+ *
+ * Throws an {@code IllegalArgumentException} if the input is malformed.
+ */
+ public static byte[] decode(char[] encoded, boolean allowSingleChar)
+ throws IllegalArgumentException {
+ int encodedLength = encoded.length;
+ int resultLengthBytes = (encodedLength + 1) / 2;
+ byte[] result = new byte[resultLengthBytes];
+
+ int resultOffset = 0;
+ int i = 0;
+ if (allowSingleChar) {
+ if ((encodedLength % 2) != 0) {
+ // Odd number of digits -- the first digit is the lower 4 bits of the first result
+ // byte.
+ result[resultOffset++] = (byte) toDigit(encoded, i);
+ i++;
+ }
+ } else {
+ if ((encodedLength % 2) != 0) {
+ throw new IllegalArgumentException("Invalid input length: " + encodedLength);
+ }
+ }
+
+ for (; i < encodedLength; i += 2) {
+ result[resultOffset++] = (byte) ((toDigit(encoded, i) << 4) | toDigit(encoded, i + 1));
+ }
+
+ return result;
+ }
+
+ private static int toDigit(char[] str, int offset) throws IllegalArgumentException {
+ // NOTE: that this isn't really a code point in the traditional sense, since we're
+ // just rejecting surrogate pairs outright.
+ int pseudoCodePoint = str[offset];
+
+ if ('0' <= pseudoCodePoint && pseudoCodePoint <= '9') {
+ return pseudoCodePoint - '0';
+ } else if ('a' <= pseudoCodePoint && pseudoCodePoint <= 'f') {
+ return 10 + (pseudoCodePoint - 'a');
+ } else if ('A' <= pseudoCodePoint && pseudoCodePoint <= 'F') {
+ return 10 + (pseudoCodePoint - 'A');
+ }
+
+ throw new IllegalArgumentException("Illegal char: " + str[offset] + " at offset " + offset);
+ }
+}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
deleted file mode 100644
index fcf8bd5eaa3e..000000000000
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ /dev/null
@@ -1,484 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License") {
- * throw new UnsupportedOperationException();
- }
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wifi;
-
-import android.content.pm.ParceledListSlice;
-import android.net.DhcpInfo;
-import android.net.Network;
-import android.net.wifi.IDppCallback;
-import android.net.wifi.INetworkRequestMatchCallback;
-import android.net.wifi.IOnWifiUsabilityStatsListener;
-import android.net.wifi.ISoftApCallback;
-import android.net.wifi.ITrafficStateCallback;
-import android.net.wifi.IWifiManager;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiActivityEnergyInfo;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiNetworkSuggestion;
-import android.net.wifi.hotspot2.IProvisioningCallback;
-import android.net.wifi.hotspot2.OsuProvider;
-import android.net.wifi.hotspot2.PasspointConfiguration;
-import android.os.IBinder;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.WorkSource;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Empty concrete class implementing IWifiManager with stub methods throwing runtime exceptions.
- *
- * This class is meant to be extended by real implementations of IWifiManager in order to facilitate
- * cross-repo changes to WiFi internal APIs, including the introduction of new APIs, the removal of
- * deprecated APIs, or the migration of existing API signatures.
- *
- * When an existing API is scheduled for removal, it can be removed from IWifiManager.aidl
- * immediately and marked as @Deprecated first in this class. Children inheriting this class are
- * then given a short grace period to update themselves before the @Deprecated stub is removed for
- * good. If the API scheduled for removal has a replacement or an overload (signature change),
- * these should be introduced before the stub is removed to allow children to migrate.
- *
- * When a new API is added to IWifiManager.aidl, a stub should be added in BaseWifiService as
- * well otherwise compilation will fail.
- */
-public class BaseWifiService extends IWifiManager.Stub {
-
- private static final String TAG = BaseWifiService.class.getSimpleName();
-
- @Override
- public long getSupportedFeatures() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public WifiActivityEnergyInfo reportActivityInfo() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void requestActivityInfo(ResultReceiver result) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ParceledListSlice getConfiguredNetworks(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ParceledListSlice getPrivilegedConfiguredNetworks(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Map<String, Map<Integer, List<ScanResult>>> getAllMatchingFqdnsForScanResults(
- List<ScanResult> scanResults) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
- List<ScanResult> scanResults) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
- List<OsuProvider> osuProviders) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addOrUpdatePasspointConfiguration(
- PasspointConfiguration config, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean removePasspointConfiguration(String fqdn, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<PasspointConfiguration> getPasspointConfigurations(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<WifiConfiguration> getWifiConfigsForPasspointProfiles(List<String> fqdnList) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void queryPasspointIcon(long bssid, String fileName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int matchProviderWithCurrentNetwork(String fqdn) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void deauthenticateNetwork(long holdoff, boolean ess) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean removeNetwork(int netId, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean enableNetwork(int netId, boolean disableOthers, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean disableNetwork(int netId, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean startScan(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<ScanResult> getScanResults(String callingPackage) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean disconnect(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean reconnect(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean reassociate(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public WifiInfo getConnectionInfo(String callingPackage) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean setWifiEnabled(String packageName, boolean enable) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getWifiEnabledState() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setCountryCode(String country) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getCountryCode() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isDualBandSupported() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean needs5GHzToAnyApBandConversion() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public DhcpInfo getDhcpInfo() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isScanAlwaysAvailable() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean acquireWifiLock(IBinder lock, int lockType, String tag, WorkSource ws) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean releaseWifiLock(IBinder lock) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void initializeMulticastFiltering() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isMulticastEnabled() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void acquireMulticastLock(IBinder binder, String tag) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void releaseMulticastLock(String tag) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void updateInterfaceIpState(String ifaceName, int mode) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean startSoftAp(WifiConfiguration wifiConfig) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean stopSoftAp() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void stopLocalOnlyHotspot() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void stopWatchLocalOnlyHotspot() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getWifiApEnabledState() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public WifiConfiguration getWifiApConfiguration() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void notifyUserOfApBandConversion(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Messenger getWifiServiceMessenger(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void enableTdls(String remoteIPAddress, boolean enable) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getCurrentNetworkWpsNfcConfigurationToken() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void enableVerboseLogging(int verbose) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getVerboseLoggingLevel() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void enableWifiConnectivityManager(boolean enabled) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void disableEphemeralNetwork(String SSID, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void factoryReset(String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Network getCurrentNetwork() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public byte[] retrieveBackupData() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void restoreBackupData(byte[] data) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void startSubscriptionProvisioning(
- OsuProvider provider, IProvisioningCallback callback) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerSoftApCallback(
- IBinder binder, ISoftApCallback callback, int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unregisterSoftApCallback(int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerTrafficStateCallback(
- IBinder binder, ITrafficStateCallback callback, int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unregisterTrafficStateCallback(int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerNetworkRequestMatchCallback(
- IBinder binder, INetworkRequestMatchCallback callback, int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int addNetworkSuggestions(
- List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int removeNetworkSuggestions(
- List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String[] getFactoryMacAddresses() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setDeviceMobilityState(int state) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri,
- int selectedNetworkId, int netRole, IDppCallback callback) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri,
- IDppCallback callback) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void stopDppSession() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void addOnWifiUsabilityStatsListener(
- IBinder binder, IOnWifiUsabilityStatsListener listener, int listenerIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void removeOnWifiUsabilityStatsListener(int listenerIdentifier) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
new file mode 100644
index 000000000000..6a39959e8cfd
--- /dev/null
+++ b/wifi/tests/Android.bp
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Make test APK
+// ============================================================
+
+android_test {
+ name: "FrameworksWifiApiTests",
+
+ defaults: ["framework-wifi-test-defaults"],
+
+ srcs: ["**/*.java"],
+
+ jacoco: {
+ include_filter: ["android.net.wifi.*"],
+ // TODO(b/147521214) need to exclude test classes
+ exclude_filter: [],
+ },
+
+ static_libs: [
+ "androidx.test.rules",
+ "core-test-rules",
+ "guava",
+ "mockito-target-minus-junit4",
+ "net-tests-utils",
+ "frameworks-base-testutils",
+ "truth-prebuilt",
+ ],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+
+ test_suites: [
+ "device-tests",
+ "mts",
+ ],
+}
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
deleted file mode 100644
index 3453d6ec827f..000000000000
--- a/wifi/tests/Android.mk
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Make test APK
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-# This list is generated from the java source files in this module
-# The list is a comma separated list of class names with * matching zero or more characters.
-# Example:
-# Input files: src/com/android/server/wifi/Test.java src/com/android/server/wifi/AnotherTest.java
-# Generated exclude list: com.android.server.wifi.Test*,com.android.server.wifi.AnotherTest*
-
-# Filter all src files to just java files
-local_java_files := $(filter %.java,$(LOCAL_SRC_FILES))
-# Transform java file names into full class names.
-# This only works if the class name matches the file name and the directory structure
-# matches the package.
-local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
-# Convert class name list to jacoco exclude list
-# This appends a * to all classes and replace the space separators with commas.
-# These patterns will match all classes in this module and their inner classes.
-jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
-
-jacoco_include := android.net.wifi.*
-
-LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include)
-LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.test.rules \
- core-test-rules \
- guava \
- mockito-target-minus-junit4 \
- net-tests-utils \
- frameworks-base-testutils \
- truth-prebuilt \
-
-LOCAL_JAVA_LIBRARIES := \
- android.test.runner \
- android.test.base \
-
-LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
index cae19e46c6af..34e2e3af9cda 100644
--- a/wifi/tests/AndroidTest.xml
+++ b/wifi/tests/AndroidTest.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<configuration description="Runs Frameworks Wifi API Tests.">
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="FrameworksWifiApiTests.apk" />
</target_preparer>
@@ -25,4 +25,10 @@
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
+
+ <!-- Only run FrameworksWifiApiTests in MTS if the Wifi Mainline module is installed. -->
+ <object type="module_controller"
+ class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.wifi" />
+ </object>
</configuration>
diff --git a/wifi/tests/README.md b/wifi/tests/README.md
index b0594f2d29b1..f90940470432 100644
--- a/wifi/tests/README.md
+++ b/wifi/tests/README.md
@@ -8,12 +8,9 @@ libraries.
The easiest way to run tests is simply run
```
-frameworks/base/wifi/tests/runtests.sh
+atest android.net.wifi
```
-`runtests.sh` will build the test project and all of its dependencies and push the APK to the
-connected device. It will then run the tests on the device.
-
To pick up changes in framework/base, you will need to:
1. rebuild the framework library 'make -j32'
2. sync over the updated library to the device 'adb sync'
@@ -24,22 +21,6 @@ To enable syncing data to the device for first time after clean reflash:
2. adb reboot
3. adb remount
-See below for a few example of options to limit which tests are run.
-See the
-[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html)
-for more details on the supported options.
-
-```
-runtests.sh -e package android.net.wifi
-runtests.sh -e class android.net.wifi.WifiScannerTest
-```
-
-If you manually build and push the test APK to the device you can run tests using
-
-```
-adb shell am instrument -w 'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner'
-```
-
## Adding Tests
Tests can be added by adding classes to the src directory. JUnit4 style test cases can
be written by simply annotating test methods with `org.junit.Test`.
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
index 56919c25de46..760c8395e659 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
@@ -12,75 +12,75 @@ VnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSthVEF3TVR3dlRt
OWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVJYjIx
bFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1
dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNB
-OFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklDQWdQQzlPYjJS
-bFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrWlJSRTQ4
-TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1MWF6d3ZWbUZz
-ZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0Fn
-SUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2ClpHVk9ZVzFs
-UGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpoYkhWbFBnb2dJ
-Q0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4VG05a1pUNEtJ
-Q0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVoYldVK0NpQWdJ
-Q0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhiRzA4CkwwNXZa
-R1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHljbVZrTG1OdmJU
-d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lD
-QWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThMMDV2WkdWT1lX
-MWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0ClpU
-NVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lXeDFaVDVxWVcx
-bGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05
-a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BDOU9iMlJsVG1G
-dFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3dlZtRnNkV1Ur
-CkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0Fn
-SUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0Fn
-SUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1GdFpUNUZRVkJV
-ZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1UrTWpFOEwxWmhi
-SFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxQ
-Z29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2WkR3dlRtOWta
-VTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0VmpJOEwxWmhi
-SFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0Np
-QWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BF
-NXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
-QWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQa05sY25ScFpt
-bGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lXeDFaVDU0TlRB
-NWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1
-dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1qVTJSbWx1WjJW
-eWNISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdVKwpNV1l4WmpG
+OFZtRnNkV1UrUlhoaGJYQnNaU0JPWlhSM2IzSnJQQzlXWVd4MVpUNEtJQ0FnCklDQWdJQ0E4TDA1
+dlpHVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStSbEZF
+VGp3dlRtOWsKWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVSthRzkwYzNCdmRDNWxlR0Z0
+Y0d4bExtNWxkRHd2Vm1Gc2RXVStDaUFnSUNBZwpJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhP
+YjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERiMjV6CmIzSjBhWFZ0
+VDBrOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhNakl6TXl3ME5EVTFO
+alk4TDFaaGJIVmwKUGdvZ0lDQWdJQ0FnSUR3dlRtOWtaVDRLSUNBZ0lDQWdQQzlPYjJSbFBnb2dJ
+Q0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05awpaVTVoYldVK1EzSmxaR1Z1ZEdsaGJEd3ZU
+bTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrClpVNWhi
+V1UrVW1WaGJHMDhMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbVY0WVcxd2JH
+VXVZMjl0UEM5V1lXeDEKWlQ0S0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEU1dlpH
+VStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrVlhObApjbTVoYldWUVlYTnpkMjl5WkR3dlRt
+OWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2ClpH
+Vk9ZVzFsUGxWelpYSnVZVzFsUEM5T2IyUmxUbUZ0WlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRlpoYkhW
+bFBuVnpaWEk4TDFaaGJIVmwKUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNB
+Z1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsVG1GdApaVDVRWVhOemQyOXlaRHd2VG05
+a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1alIwWjZZek5rZG1OdFVUMDhMMVpo
+CmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFn
+SUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNUZRVkJOWlhSb2IyUThMMDV2WkdWT1lXMWxQZ29n
+SUNBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZwpJQ0E4VG05a1pVNWhiV1Ur
+UlVGUVZIbHdaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqSXhQ
+QzlXCllXeDFaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThU
+bTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWcKSUNBOFRtOWtaVTVoYldVK1NXNXVaWEpOWlhSb2IyUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1TgpVeTFEU0VGUUxWWXlQ
+QzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2Iy
+UmxQZ29nCklDQWdJQ0FnSUR3dlRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lD
+QWdJRHhPYjJSbFRtRnRaVDVFYVdkcGRHRnMKUTJWeWRHbG1hV05oZEdVOEwwNXZaR1ZPWVcxbFBn
+b2dJQ0FnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbApUbUZ0WlQ1RFpY
+SjBhV1pwWTJGMFpWUjVjR1U4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+K2VEVXdPWFl6ClBDOVdZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNB
+Z0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQTgKVG05a1pVNWhiV1UrUTJWeWRGTklRVEkxTmta
+cGJtZGxjbkJ5YVc1MFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaApiSFZsUGpG
bU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZt
-TVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNBOEwwNXZaR1Ur
-Q2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0Fn
-UEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4VG05awpaVDRL
-SUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJ
-Q0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNBOEwwNXZa
-R1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2WkdWT1lXMWxQ
-a1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1UrTWpROApM
-MVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lD
-QWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQQzlOWjIxMFZI
-SmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXg1MDktY2Et
-Y2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFDUlVkSlRpQkRS
-VkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtRVWxNYkVaa2Qz
-cE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5UbFlLUWtGTlZF
-SXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpUazFxV1hkTlZF
-RTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5VVEJGZUUxSlNV
-Skpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMwTkJVVVZCQ25w
-dVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZYTldkVzFFWWxs
-SWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01TdHZSMWhhZGto
-M2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJVRkRaV1pXYW1v
-d2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJoU1FqZzFNVEpR
-UWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdKck1IVjVhM1Jr
-WW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtzM2FFUTRjRkIy
-WmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxhCmFYQllOREY0
-UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVXTTJreGRIRXdO
-R3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZHU1hkWU5IWnpP
-RUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFFYlVGR1NYZFlO
-SFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJkMFJuCldVUldV
-VkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldVakJVUWtGVmQw
-RjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZMDVCVVVWTVFs
-RkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZDamxIUlZBdmRX
-OW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNYZEpWV00zCmQy
-azNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1EwOTBhWE5rUW5F
-eWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JXMVdUQW94Y1VK
-S2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVFMXVWR3c0ZUVW
-WFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhwaFNFb3hkVlk0
-Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpGS1VDdHNlRllL
-YlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNSa1RrNTJRMWw2
-YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmtsRFFWUkZMUzB0
-TFMwSwotLXtib3VuZGFyeX0tLQo=
+TVdZeFpqRm1NV1l4ClpqRm1NV1l4WmpGbU1XWThMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlP
+YjJSbFBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWcKSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0Fn
+SUNBZ0lEeE9iMlJsVG1GdFpUNVRTVTA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZwpQRTV2
+WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVKVFZOSlBDOU9iMlJsVG1GdFpUNEtJ
+Q0FnSUNBZ0lDQWdJQ0FnClBGWmhiSFZsUGpFeU16UTFOaW84TDFaaGJIVmxQZ29nSUNBZ0lDQWdJ
+Q0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVSsKQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9i
+MlJsVG1GdFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaApi
+SFZsUGpJelBDOVdZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOEww
+NXZaR1UrQ2lBZ0lDQWdJRHd2ClRtOWtaVDRLSUNBZ0lEd3ZUbTlrWlQ0S0lDQThMMDV2WkdVK0Nq
+d3ZUV2R0ZEZSeVpXVSsKCi0te2JvdW5kYXJ5fQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL3gt
+eDUwOS1jYS1jZXJ0CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NAoKTFMwdExTMUNS
+VWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUkxSRU5EUVdoRFowRjNTVUpCWjBsS1FV
+bE1iRVprZDNwTQpWblZ5VFVFd1IwTlRjVWRUU1dJelJGRkZRa04zVlVGTlFrbDRSVVJCVDBKblRs
+WUtRa0ZOVkVJd1ZrSlZRMEpFVVZSRmQwaG9ZMDVOClZGbDNUVlJGZVUxVVJURk5SRVV4VjJoalRr
+MXFXWGROVkVFMVRWUkZNVTFFUlRGWGFrRlRUVkpCZHdwRVoxbEVWbEZSUkVWM1pFWlIKVmtGblVU
+QkZlRTFKU1VKSmFrRk9RbWRyY1docmFVYzVkekJDUVZGRlJrRkJUME5CVVRoQlRVbEpRa05uUzBO
+QlVVVkJDbnB1UVZCVgplakkyVFhOaFpUUjNjelF6WTNwU05ERXZTakpSZEhKVFNWcFZTMjFXVlhO
+V2RXMUVZbGxJY2xCT2RsUllTMU5OV0VGalpYZFBVa1JSCldWZ0tVbkYyU0had2JqaERjMk5DTVN0
+dlIxaGFka2gzZUdvMGVsWXdWMHR2U3pKNlpWaHJZWFV6ZG1ONWJETklTVXQxY0VwbWNUSlUKUlVG
+RFpXWldhbW93ZEFwS1Z5dFlNelZRUjFkd09TOUlOWHBKVlU1V1RsWnFVemRWYlhNNE5FbDJTMmhT
+UWpnMU1USlFRamxWZVVoaApaMWhaVmxnMVIxZHdRV05XY0hsbWNteFNDa1pKT1ZGa2FHZ3JVR0py
+TUhWNWEzUmtZbVl2UTJSbVowaFBiMlZpY2xSMGQxSnNhazB3CmIwUjBXQ3N5UTNZMmFqQjNRa3Mz
+YUVRNGNGQjJaakVyZFhrS1IzcGplbWxuUVZVdk5FdDNOMlZhY1hsa1pqbENLelZTZFhCU0swbGEK
+YVhCWU5ERjRSV2xKY2t0U2QzRnBOVEUzVjFkNldHTnFZVWN5WTA1aVpqUTFNUXA0Y0VnMVVHNVdN
+Mmt4ZEhFd05HcE5SMUZWZWtaMwpTVVJCVVVGQ2J6UkhRVTFJTkhkSVVWbEVWbEl3VDBKQ1dVVkdT
+WGRZTkhaek9FSnBRbU5UWTI5a0NqVnViMXBJVWswNFJUUXJhVTFGClNVZEJNVlZrU1hkUk4wMUVi
+VUZHU1hkWU5IWnpPRUpwUW1OVFkyOWtOVzV2V2toU1RUaEZOQ3RwYjFKaGEwWkVRVk1LVFZKQmQw
+Um4KV1VSV1VWRkVSWGRrUmxGV1FXZFJNRVY0WjJkclFXZDFWVll6UkUxMFZ6WnpkMFJCV1VSV1Vq
+QlVRa0ZWZDBGM1JVSXZla0ZNUW1kTwpWZ3BJVVRoRlFrRk5RMEZSV1hkRVVWbEtTMjlhU1doMlkw
+NUJVVVZNUWxGQlJHZG5SVUpCUm1aUmNVOVVRVGRTZGpkTEsyeDFVVGR3CmJtRnpORUpaZDBoRkNq
+bEhSVkF2ZFc5b2RqWkxUM2t3VkVkUlJtSnlVbFJxUm05TVZrNUNPVUphTVhsdFRVUmFNQzlVU1hk
+SlZXTTMKZDJrM1lUaDBOVzFGY1ZsSU1UVXpkMWNLWVZkdmIybFRhbmxNVEdoMVNUUnpUbkpPUTA5
+MGFYTmtRbkV5Y2pKTlJsaDBObWd3YlVGUgpXVTlRZGpoU09FczNMMlpuVTNoSFJuRjZhSGxPYlcx
+V1RBb3hjVUpLYkdSNE16UlRjSGR6VkVGTVVWWlFZalJvUjNkS2VscG1jakZRClkzQkZVWGcyZUUx
+dVZHdzRlRVZYV2tVelRYTTVPWFZoVlhoaVVYRkpkMUoxQ2t4blFVOXJUa050V1RKdE9EbFdhSHBo
+U0VveGRWWTQKTlVGa1RTOTBSQ3RaYzIxc2JtNXFkRGxNVWtObGFtSkNhWEJxU1VkcVQxaHlaekZL
+VUN0c2VGWUtiWFZOTkhaSUsxQXZiV3h0ZUhOUQpVSG93WkRZMVlpdEZSMjFLV25CdlRHdFBMM1Jr
+VGs1MlExbDZha3B3VkVWWGNFVnpUelpPVFdoTFdXODlDaTB0TFMwdFJVNUVJRU5GClVsUkpSa2xE
+UVZSRkxTMHRMUzBLCi0te2JvdW5kYXJ5fS0tCg== \ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
index a44b54222589..5b4e4cb947cd 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
@@ -13,38 +13,38 @@ YTptbzpob3RzcG90MmRvdDAtcGVycHJvdmlkZXJzdWJzY3JpcHRpb246MS4wPC9EREZOYW1lPgog
ICAgICA8L1R5cGU+CiAgICA8L1JUUHJvcGVydGllcz4KICAgIDxOb2RlPgogICAgICA8Tm9kZU5h
bWU+aTAwMTwvTm9kZU5hbWU+CiAgICAgIDxOb2RlPgogICAgICAgIDxOb2RlTmFtZT5Ib21lU1A8
L05vZGVOYW1lPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZyaWVuZGx5TmFt
-ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8VmFsdWU+Q2VudHVyeSBIb3VzZTwvVmFsdWU+CiAgICAg
-ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZRRE48L05vZGVO
-YW1lPgogICAgICAgICAgPFZhbHVlPm1pNi5jby51azwvVmFsdWU+CiAgICAgICAgPC9Ob2RlPgog
-ICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlJvYW1pbmdDb25zb3J0aXVtT0k8L05v
-ZGVOYW1lPgogICAgICAgICAgPFZhbHVlPjExMjIzMyw0NDU1NjY8L1ZhbHVlPgogICAgICAgIDwv
-Tm9kZT4KICAgICAgPC9Ob2RlPgogICAgICA8Tm9kZT4KICAgICAgICA8Tm9kZU5hbWU+Q3JlZGVu
-dGlhbDwvTm9kZU5hbWU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9kZU5hbWU+UmVhbG08
-L05vZGVOYW1lPgogICAgICAgICAgPFZhbHVlPnNoYWtlbi5zdGlycmVkLmNvbTwvVmFsdWU+CiAg
-ICAgICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlVzZXJuYW1l
-UGFzc3dvcmQ8L05vZGVOYW1lPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2RlTmFt
-ZT5Vc2VybmFtZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT5qYW1lczwvVmFsdWU+CiAg
-ICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1lPlBh
-c3N3b3JkPC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZhbHVlPlltOXVaREF3Tnc9PTwvVmFsdWU+
-CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
-PkVBUE1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO
-b2RlTmFtZT5FQVBUeXBlPC9Ob2RlTmFtZT4KICAgICAgICAgICAgICA8VmFsdWU+MjE8L1ZhbHVl
-PgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO
-b2RlTmFtZT5Jbm5lck1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgICAgPFZhbHVlPk1TLUNI
-QVAtVjI8L1ZhbHVlPgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8L05vZGU+CiAgICAg
-ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkRpZ2l0YWxDZXJ0
-aWZpY2F0ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
-PkNlcnRpZmljYXRlVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT54NTA5djM8L1Zh
+ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8VmFsdWU+RXhhbXBsZSBOZXR3b3JrPC9WYWx1ZT4KICAg
+ICAgICA8L05vZGU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9kZU5hbWU+RlFETjwvTm9k
+ZU5hbWU+CiAgICAgICAgICA8VmFsdWU+aG90c3BvdC5leGFtcGxlLm5ldDwvVmFsdWU+CiAgICAg
+ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlJvYW1pbmdDb25z
+b3J0aXVtT0k8L05vZGVOYW1lPgogICAgICAgICAgPFZhbHVlPjExMjIzMyw0NDU1NjY8L1ZhbHVl
+PgogICAgICAgIDwvTm9kZT4KICAgICAgPC9Ob2RlPgogICAgICA8Tm9kZT4KICAgICAgICA8Tm9k
+ZU5hbWU+Q3JlZGVudGlhbDwvTm9kZU5hbWU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9k
+ZU5hbWU+UmVhbG08L05vZGVOYW1lPgogICAgICAgICAgPFZhbHVlPmV4YW1wbGUuY29tPC9WYWx1
+ZT4KICAgICAgICA8L05vZGU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9kZU5hbWU+VXNl
+cm5hbWVQYXNzd29yZDwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5v
+ZGVOYW1lPlVzZXJuYW1lPC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZhbHVlPnVzZXI8L1ZhbHVl
+PgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2RlTmFt
+ZT5QYXNzd29yZDwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT5jR0Z6YzNkdmNtUT08L1Zh
bHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl
-TmFtZT5DZXJ0U0hBMjU2RmluZ2VycHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
-MWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx
-ZjFmMWYxZjwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgPC9Ob2RlPgogICAgICAg
-IDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlNJTTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9k
-ZT4KICAgICAgICAgICAgPE5vZGVOYW1lPklNU0k8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFs
-dWU+aW1zaTwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAg
-ICAgICAgPE5vZGVOYW1lPkVBUFR5cGU8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+MjQ8
-L1ZhbHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgIDwvTm9kZT4KICAgICAgPC9Ob2RlPgog
-ICAgPC9Ob2RlPgogIDwvTm9kZT4KPC9NZ210VHJlZT4K
+TmFtZT5FQVBNZXRob2Q8L05vZGVOYW1lPgogICAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAg
+ICA8Tm9kZU5hbWU+RUFQVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgICAgPFZhbHVlPjIxPC9W
+YWx1ZT4KICAgICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAg
+ICA8Tm9kZU5hbWU+SW5uZXJNZXRob2Q8L05vZGVOYW1lPgogICAgICAgICAgICAgIDxWYWx1ZT5N
+Uy1DSEFQLVYyPC9WYWx1ZT4KICAgICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPC9Ob2RlPgog
+ICAgICAgIDwvTm9kZT4KICAgICAgICA8Tm9kZT4KICAgICAgICAgIDxOb2RlTmFtZT5EaWdpdGFs
+Q2VydGlmaWNhdGU8L05vZGVOYW1lPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl
+TmFtZT5DZXJ0aWZpY2F0ZVR5cGU8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+eDUwOXYz
+PC9WYWx1ZT4KICAgICAgICAgIDwvTm9kZT4KICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICA8
+Tm9kZU5hbWU+Q2VydFNIQTI1NkZpbmdlcnByaW50PC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZh
+bHVlPjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx
+ZjFmMWYxZjFmMWY8L1ZhbHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgIDwvTm9kZT4KICAg
+ICAgICA8Tm9kZT4KICAgICAgICAgIDxOb2RlTmFtZT5TSU08L05vZGVOYW1lPgogICAgICAgICAg
+PE5vZGU+CiAgICAgICAgICAgIDxOb2RlTmFtZT5JTVNJPC9Ob2RlTmFtZT4KICAgICAgICAgICAg
+PFZhbHVlPjEyMzQ1Nio8L1ZhbHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+
+CiAgICAgICAgICAgIDxOb2RlTmFtZT5FQVBUeXBlPC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZh
+bHVlPjIzPC9WYWx1ZT4KICAgICAgICAgIDwvTm9kZT4KICAgICAgICA8L05vZGU+CiAgICAgIDwv
+Tm9kZT4KICAgIDwvTm9kZT4KICA8L05vZGU+CjwvTWdtdFRyZWU+
--{boundary}
Content-Type: application/x-x509-ca-cert
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
index 906bfb397464..2775a9f419f9 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
@@ -1,85 +1,86 @@
-Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
-dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
-cHBsaWNhdGlvbi9wYXNzcG9pbnQtcHJvZmlsZQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBi
-YXNlNjQKClBFMW5iWFJVY21WbElIaHRiRzV6UFNKemVXNWpiV3c2Wkcxa1pHWXhMaklpUGdvZ0lE
-eFdaWEpFVkVRK01TNHlQQzlXWlhKRVZFUSsKQ2lBZ1BFNXZaR1UrQ2lBZ0lDQThUbTlrWlU1aGJX
-VStVR1Z5VUhKdmRtbGtaWEpUZFdKelkzSnBjSFJwYjI0OEwwNXZaR1ZPWVcxbApQZ29nSUNBZ1BG
-SlVVSEp2Y0dWeWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldV
-K2RYSnVPbmRtCllUcHRienBvYjNSemNHOTBNbVJ2ZERBdGNHVnljSEp2ZG1sa1pYSnpkV0p6WTNK
-cGNIUnBiMjQ2TVM0d1BDOUVSRVpPWVcxbFBnb2cKSUNBZ0lDQThMMVI1Y0dVK0NpQWdJQ0E4TDFK
-VVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQThUbTlrWlU1aApiV1UrYVRB
-d01Ud3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0
-WlQ1SWIyMWxVMUE4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0Fn
-SUNBZ1BFNXZaR1ZPWVcxbFBrWnlhV1Z1Wkd4NVRtRnQKWlR3dlRtOWtaVTVoYldVK0NpQWdJQ0Fn
-SUNBZ0lDQThWbUZzZFdVK1EyVnVkSFZ5ZVNCSWIzVnpaVHd2Vm1Gc2RXVStDaUFnSUNBZwpJQ0Fn
-UEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQ
-a1pSUkU0OEwwNXZaR1ZPCllXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbTFwTmk1amJ5NTFh
-end2Vm1Gc2RXVStDaUFnSUNBZ0lDQWdQQzlPYjJSbFBnb2cKSUNBZ0lDQWdJRHhPYjJSbFBnb2dJ
-Q0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERiMjV6YjNKMGFYVnRUMGs4TDA1dgpa
-R1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhNakl6TXl3ME5EVTFOalk4TDFaaGJI
-VmxQZ29nSUNBZ0lDQWdJRHd2ClRtOWtaVDRLSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBOFRt
-OWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUTNKbFpHVnUKZEdsaGJEd3ZUbTlrWlU1aGJX
-VStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStVbVZoYkcw
-OApMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbk5vWVd0bGJpNXpkR2x5Y21W
-a0xtTnZiVHd2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJS
-bFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbFZ6WlhKdVlXMWwKVUdGemMzZHZjbVE4TDA1
-dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJs
-VG1GdApaVDVWYzJWeWJtRnRaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx
-WlQ1cVlXMWxjend2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0Fn
-SUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsQmgKYzNOM2IzSmtQQzlP
-YjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGxsdE9YVmFSRUYzVG5jOVBUd3ZW
-bUZzZFdVKwpDaUFnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pUNEtJ
-Q0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsClBrVkJVRTFsZEdodlpEd3ZUbTlrWlU1aGJXVStD
-aUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRa
-VDVGUVZCVWVYQmxQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdVK01q
-RThMMVpoYkhWbApQZ29nSUNBZ0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lE
-eE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQWdJRHhPCmIyUmxUbUZ0WlQ1SmJtNWxjazFsZEdodlpE
-d3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGsxVExVTkkKUVZBdFZq
-SThMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4TDA1
-dlpHVStDaUFnSUNBZwpJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNB
-Z0lDQWdQRTV2WkdWT1lXMWxQa1JwWjJsMFlXeERaWEowCmFXWnBZMkYwWlR3dlRtOWtaVTVoYldV
-K0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtO
-bGNuUnBabWxqWVhSbFZIbHdaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx
-WlQ1NE5UQTVkak04TDFaaApiSFZsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0Fn
-SUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsClRtRnRaVDVEWlhKMFUwaEJNalUy
-Um1sdVoyVnlVSEpwYm5ROEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVSsK
-TVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1N
-V1l4WmpGbU1XWXhaakZtTVdZeApaakZtTVdZeFpqd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lDQThM
-MDV2WkdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnCklEeE9iMlJsUGdvZ0lDQWdJ
-Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBsTkpUVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBOFRt
-OWsKWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQa2xOVTBrOEwwNXZaR1ZPWVcxbFBn
-b2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1GcwpkV1UrYVcxemFUd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lD
-QThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnCklDQWdJQ0FnUEU1dlpH
-Vk9ZVzFsUGtWQlVGUjVjR1U4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
-K01qUTgKTDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHd2VG05
-a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnUEM5T2IyUmxQZ29nSUR3dlRtOWtaVDRLUEM5
-TloyMTBWSEpsWlQ0SwoKLS17Ym91bmRhcnl9CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24veC14
-NTA5LWNhLWNlcnQKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgpMUzB0TFMxQ1JV
-ZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VSTFJFTkRRV2hEWjBGM1NVSkJaMGxLUVVs
-TWJFWmtkM3BNClZuVnlUVUV3UjBOVGNVZFRTV0l6UkZGRlFrTjNWVUZOUWtsNFJVUkJUMEpuVGxZ
-S1FrRk5WRUl3VmtKVlEwSkVVVlJGZDBob1kwNU4KVkZsM1RWUkZlVTFVUlRGTlJFVXhWMmhqVGsx
-cVdYZE5WRUUxVFZSRk1VMUVSVEZYYWtGVFRWSkJkd3BFWjFsRVZsRlJSRVYzWkVaUgpWa0ZuVVRC
-RmVFMUpTVUpKYWtGT1FtZHJjV2hyYVVjNWR6QkNRVkZGUmtGQlQwTkJVVGhCVFVsSlFrTm5TME5C
-VVVWQkNucHVRVkJWCmVqSTJUWE5oWlRSM2N6UXpZM3BTTkRFdlNqSlJkSEpUU1ZwVlMyMVdWWE5X
-ZFcxRVlsbEljbEJPZGxSWVMxTk5XRUZqWlhkUFVrUlIKV1ZnS1VuRjJTSFp3YmpoRGMyTkNNU3R2
-UjFoYWRraDNlR28wZWxZd1YwdHZTeko2WlZocllYVXpkbU41YkROSVNVdDFjRXBtY1RKVQpSVUZE
-WldaV2Ftb3dkQXBLVnl0WU16VlFSMWR3T1M5SU5YcEpWVTVXVGxacVV6ZFZiWE00TkVsMlMyaFNR
-amcxTVRKUVFqbFZlVWhoCloxaFpWbGcxUjFkd1FXTldjSGxtY214U0NrWkpPVkZrYUdnclVHSnJN
-SFY1YTNSa1ltWXZRMlJtWjBoUGIyVmljbFIwZDFKc2FrMHcKYjBSMFdDc3lRM1kyYWpCM1FrczNh
-RVE0Y0ZCMlpqRXJkWGtLUjNwamVtbG5RVlV2TkV0M04yVmFjWGxrWmpsQ0t6VlNkWEJTSzBsYQph
-WEJZTkRGNFJXbEpja3RTZDNGcE5URTNWMWQ2V0dOcVlVY3lZMDVpWmpRMU1RcDRjRWcxVUc1V00y
-a3hkSEV3TkdwTlIxRlZla1ozClNVUkJVVUZDYnpSSFFVMUlOSGRJVVZsRVZsSXdUMEpDV1VWR1NY
-ZFlOSFp6T0VKcFFtTlRZMjlrQ2pWdWIxcElVazA0UlRRcmFVMUYKU1VkQk1WVmtTWGRSTjAxRWJV
-RkdTWGRZTkhaek9FSnBRbU5UWTI5a05XNXZXa2hTVFRoRk5DdHBiMUpoYTBaRVFWTUtUVkpCZDBS
-bgpXVVJXVVZGRVJYZGtSbEZXUVdkUk1FVjRaMmRyUVdkMVZWWXpSRTEwVnpaemQwUkJXVVJXVWpC
-VVFrRlZkMEYzUlVJdmVrRk1RbWRPClZncElVVGhGUWtGTlEwRlJXWGRFVVZsS1MyOWFTV2gyWTA1
-QlVVVk1RbEZCUkdkblJVSkJSbVpSY1U5VVFUZFNkamRMSzJ4MVVUZHcKYm1Gek5FSlpkMGhGQ2ps
-SFJWQXZkVzlvZGpaTFQza3dWRWRSUm1KeVVsUnFSbTlNVms1Q09VSmFNWGx0VFVSYU1DOVVTWGRK
-VldNMwpkMmszWVRoME5XMUZjVmxJTVRVemQxY0tZVmR2YjJsVGFubE1UR2gxU1RSelRuSk9RMDkw
-YVhOa1FuRXljakpOUmxoME5tZ3diVUZSCldVOVFkamhTT0VzM0wyWm5VM2hIUm5GNmFIbE9iVzFX
-VEFveGNVSktiR1I0TXpSVGNIZHpWRUZNVVZaUVlqUm9SM2RLZWxwbWNqRlEKWTNCRlVYZzJlRTF1
-Vkd3NGVFVlhXa1V6VFhNNU9YVmhWWGhpVVhGSmQxSjFDa3huUVU5clRrTnRXVEp0T0RsV2FIcGhT
-RW94ZFZZNApOVUZrVFM5MFJDdFpjMjFzYm01cWREbE1Va05sYW1KQ2FYQnFTVWRxVDFoeVp6RktV
-Q3RzZUZZS2JYVk5OSFpJSzFBdmJXeHRlSE5RClVIb3daRFkxWWl0RlIyMUtXbkJ2VEd0UEwzUmtU
-azUyUTFsNmFrcHdWRVZYY0VWelR6Wk9UV2hMV1c4OUNpMHRMUzB0UlU1RUlFTkYKVWxSSlJrbERR
-VlJGTFMwdExTMEsKLS17Ym91bmRhcnl9LS0K
+TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5
+PXtib3VuZGFyeX07IGNoYXJzZXQ9VVRGLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFz
+ZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9wYXNzcG9pbnQtcHJv
+ZmlsZTsgY2hhcnNldD1VVEYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKClBF
+MW5iWFJVY21WbElIaHRiRzV6UFNKemVXNWpiV3c2Wkcxa1pHWXhMaklpUGdvZ0lEeFdaWEpFVkVR
+K01TNHlQQzlXWlhKRVZFUSsKQ2lBZ1BFNXZaR1UrQ2lBZ0lDQThUbTlrWlU1aGJXVStVR1Z5VUhK
+dmRtbGtaWEpUZFdKelkzSnBjSFJwYjI0OEwwNXZaR1ZPWVcxbApQZ29nSUNBZ1BGSlVVSEp2Y0dW
+eWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldVK2RYSnVPbmRt
+CllUcHRienBvYjNSemNHOTBNbVJ2ZERBdGNHVnljSEp2ZG1sa1pYSnpkV0p6WTNKcGNIUnBiMjQ2
+TVM0d1BDOUVSRVpPWVcxbFBnb2cKSUNBZ0lDQThMMVI1Y0dVK0NpQWdJQ0E4TDFKVVVISnZjR1Z5
+ZEdsbGN6NEtJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQThUbTlrWlU1aApiV1UrYVRBd01Ud3ZUbTlr
+WlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1SWIyMWxV
+MUE4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZa
+R1ZPWVcxbFBrWnlhV1Z1Wkd4NVRtRnQKWlR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThW
+bUZzZFdVK1JYaGhiWEJzWlNCT1pYUjNiM0pyUEM5V1lXeDFaVDRLSUNBZwpJQ0FnSUNBOEwwNXZa
+R1UrQ2lBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUmxGRVRq
+d3ZUbTlrClpVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBOFZtRnNkV1UrYUc5MGMzQnZkQzVsZUdGdGNH
+eGxMbTVsZER3dlZtRnNkV1UrQ2lBZ0lDQWcKSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2Iy
+UmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxKdllXMXBibWREYjI1egpiM0owYVhWdFQw
+azhMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakV4TWpJek15dzBORFUxTmpZ
+OEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNB
+Z0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWsKWlU1aGJXVStRM0psWkdWdWRHbGhiRHd2VG05
+a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05awpaVTVoYldV
+K1VtVmhiRzA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUG1WNFlXMXdiR1V1
+WTI5dFBDOVdZV3gxClpUNEtJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ1BFNXZaR1Ur
+Q2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1ZYTmwKY201aGJXVlFZWE56ZDI5eVpEd3ZUbTlr
+WlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dgpaR1ZP
+WVcxbFBsVnpaWEp1WVcxbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQ
+blZ6WlhJOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQ
+RTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnQKWlQ1UVlYTnpkMjl5WkR3dlRtOWta
+VTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhXWVd4MVpUNWpSMFo2WXpOa2RtTnRVVDA4TDFaaApi
+SFZsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lD
+QWdJQ0FnSUNBZ0lEeE9iMlJsClRtRnRaVDVGUVZCTlpYUm9iMlE4TDA1dlpHVk9ZVzFsUGdvZ0lD
+QWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWcKSUNBOFRtOWtaVTVoYldVK1JV
+RlFWSGx3WlR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakl4UEM5
+VwpZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4VG05
+a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnCklDQThUbTlrWlU1aGJXVStTVzV1WlhKTlpYUm9iMlE4TDA1
+dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQWdJRHhXWVd4MVpUNU4KVXkxRFNFRlFMVll5UEM5
+V1lXeDFaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJs
+UGdvZwpJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxUbUZ0WlQ1RWFXZHBkR0ZzClEyVnlkR2xtYVdOaGRHVThMMDV2WkdWT1lXMWxQZ29n
+SUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEow
+YVdacFkyRjBaVlI1Y0dVOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVStl
+RFV3T1hZegpQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZ0lDQWdJ
+RHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4ClRtOWtaVTVoYldVK1EyVnlkRk5JUVRJMU5rWnBi
+bWRsY25CeWFXNTBQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmgKYkhWbFBqRm1N
+V1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1X
+WXhaakZtTVdZeApaakZtTVdZeFpqRm1NV1k4TDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2Iy
+UmxQZ29nSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnCklDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lD
+QWdJRHhPYjJSbFRtRnRaVDVUU1UwOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWcKUEU1dlpH
+VStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1SlRWTkpQQzlPYjJSbFRtRnRaVDRLSUNB
+Z0lDQWdJQ0FnSUNBZwpQRlpoYkhWbFBqRXlNelExTmlvOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNB
+Z1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrCkNpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJS
+bFRtRnRaVDVGUVZCVWVYQmxQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmgKYkhW
+bFBqSXpQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZ0lDQThMMDV2
+WkdVK0NpQWdJQ0FnSUR3dgpUbTlrWlQ0S0lDQWdJRHd2VG05a1pUNEtJQ0E4TDA1dlpHVStDand2
+VFdkdGRGUnlaV1UrCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXg1
+MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFDUlVk
+SlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtRVWxN
+YkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5UbFlL
+UWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpUazFx
+V1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5VVEJG
+ZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMwTkJV
+VVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZYTldk
+VzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01TdHZS
+MWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJVRkRa
+V1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJoU1Fq
+ZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdKck1I
+VjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtzM2FF
+UTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxhCmFY
+QllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVXTTJr
+eGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZHU1hk
+WU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFFYlVG
+R1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJkMFJu
+CldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldVakJV
+UWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZMDVC
+VVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZDamxI
+UlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNYZEpW
+V00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1EwOTBh
+WE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JXMVdU
+QW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVFMXVW
+R3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhwaFNF
+b3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpGS1VD
+dHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNSa1Rr
+NTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmtsRFFW
+UkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo= \ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
index 3fa97d1cdd76..7023453b3992 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
@@ -1,85 +1,86 @@
-Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
-dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
-cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
-IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
-SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
-YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
-UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
-V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
-M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
-MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
-VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
-RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
-QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
-QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
-QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
-bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
-MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
-Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
-ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
-YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
-VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
-YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
-RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
-bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
-MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
-MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
-UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
-eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
-QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
-OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
-dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
-S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
-K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
-dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
-TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
-SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
-WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
-VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
-MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
-Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
-V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
-a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
-eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
-QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
-VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
-KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
-bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
-OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
-Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
-VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
-UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
-SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
-WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
-V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
-bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
-QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
-LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
-UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
-VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
-bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
-azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
-VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
-TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
-TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
-dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
-RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
-U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
-ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
-M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
-CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
-TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
-U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
-YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
-MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
-akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
-MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
-amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
-ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
-OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
-MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
-MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
-aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
-S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
-a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
-RFFWUkZMUzB0TFMwSwo=
+TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5
+PXtib3VuZGFyeX07IGNoYXJzZXQ9VVRGLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFz
+ZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXBhc3Nwb2ludC1w
+cm9maWxlOyBjaGFyc2V0PVVURi04CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NAoK
+UEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29nSUR4V1pYSkVW
+RVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVoYldVK1VHVnlV
+SEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0FnUEZKVVVISnZj
+R1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhiV1UrZFhKdU9u
+ZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZM0pwY0hScGIy
+NDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThMMUpVVUhKdmNH
+VnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSthVEF3TVR3dlRt
+OWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVJYjIx
+bFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1
+dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNB
+OFZtRnNkV1UrUlhoaGJYQnNaU0JPWlhSM2IzSnJQQzlXWVd4MVpUNEtJQ0FnCklDQWdJQ0E4TDA1
+dlpHVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStSbEZF
+VGp3dlRtOWsKWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVSthRzkwYzNCdmRDNWxlR0Z0
+Y0d4bExtNWxkRHd2Vm1Gc2RXVStDaUFnSUNBZwpJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhP
+YjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERiMjV6CmIzSjBhWFZ0
+VDBrOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhNakl6TXl3ME5EVTFO
+alk4TDFaaGJIVmwKUGdvZ0lDQWdJQ0FnSUR3dlRtOWtaVDRLSUNBZ0lDQWdQQzlPYjJSbFBnb2dJ
+Q0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05awpaVTVoYldVK1EzSmxaR1Z1ZEdsaGJEd3ZU
+bTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrClpVNWhi
+V1UrVW1WaGJHMDhMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbVY0WVcxd2JH
+VXVZMjl0UEM5V1lXeDEKWlQ0S0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEU1dlpH
+VStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrVlhObApjbTVoYldWUVlYTnpkMjl5WkR3dlRt
+OWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2ClpH
+Vk9ZVzFsUGxWelpYSnVZVzFsUEM5T2IyUmxUbUZ0WlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRlpoYkhW
+bFBuVnpaWEk4TDFaaGJIVmwKUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNB
+Z1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsVG1GdApaVDVRWVhOemQyOXlaRHd2VG05
+a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1alIwWjZZek5rZG1OdFVUMDhMMVpo
+CmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFn
+SUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNUZRVkJOWlhSb2IyUThMMDV2WkdWT1lXMWxQZ29n
+SUNBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZwpJQ0E4VG05a1pVNWhiV1Ur
+UlVGUVZIbHdaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqSXhQ
+QzlXCllXeDFaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThU
+bTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWcKSUNBOFRtOWtaVTVoYldVK1NXNXVaWEpOWlhSb2IyUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1TgpVeTFEU0VGUUxWWXlQ
+QzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2Iy
+UmxQZ29nCklDQWdJQ0FnSUR3dlRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lD
+QWdJRHhPYjJSbFRtRnRaVDVFYVdkcGRHRnMKUTJWeWRHbG1hV05oZEdVOEwwNXZaR1ZPWVcxbFBn
+b2dJQ0FnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbApUbUZ0WlQ1RFpY
+SjBhV1pwWTJGMFpWUjVjR1U4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+K2VEVXdPWFl6ClBDOVdZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNB
+Z0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQTgKVG05a1pVNWhiV1UrUTJWeWRGTklRVEkxTmta
+cGJtZGxjbkJ5YVc1MFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaApiSFZsUGpG
+bU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZt
+TVdZeFpqRm1NV1l4ClpqRm1NV1l4WmpGbU1XWThMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlP
+YjJSbFBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWcKSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0Fn
+SUNBZ0lEeE9iMlJsVG1GdFpUNVRTVTA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZwpQRTV2
+WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVKVFZOSlBDOU9iMlJsVG1GdFpUNEtJ
+Q0FnSUNBZ0lDQWdJQ0FnClBGWmhiSFZsUGpFeU16UTFOaW84TDFaaGJIVmxQZ29nSUNBZ0lDQWdJ
+Q0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVSsKQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9i
+MlJsVG1GdFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaApi
+SFZsUGpJelBDOVdZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOEww
+NXZaR1UrQ2lBZ0lDQWdJRHd2ClRtOWtaVDRLSUNBZ0lEd3ZUbTlrWlQ0S0lDQThMMDV2WkdVK0Nq
+d3ZUV2R0ZEZSeVpXVSsKCi0te2JvdW5kYXJ5fQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL3gt
+eDUwOS1jYS1jZXJ0CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NAoKTFMwdExTMUNS
+VWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUkxSRU5EUVdoRFowRjNTVUpCWjBsS1FV
+bE1iRVprZDNwTQpWblZ5VFVFd1IwTlRjVWRUU1dJelJGRkZRa04zVlVGTlFrbDRSVVJCVDBKblRs
+WUtRa0ZOVkVJd1ZrSlZRMEpFVVZSRmQwaG9ZMDVOClZGbDNUVlJGZVUxVVJURk5SRVV4VjJoalRr
+MXFXWGROVkVFMVRWUkZNVTFFUlRGWGFrRlRUVkpCZHdwRVoxbEVWbEZSUkVWM1pFWlIKVmtGblVU
+QkZlRTFKU1VKSmFrRk9RbWRyY1docmFVYzVkekJDUVZGRlJrRkJUME5CVVRoQlRVbEpRa05uUzBO
+QlVVVkJDbnB1UVZCVgplakkyVFhOaFpUUjNjelF6WTNwU05ERXZTakpSZEhKVFNWcFZTMjFXVlhO
+V2RXMUVZbGxJY2xCT2RsUllTMU5OV0VGalpYZFBVa1JSCldWZ0tVbkYyU0had2JqaERjMk5DTVN0
+dlIxaGFka2gzZUdvMGVsWXdWMHR2U3pKNlpWaHJZWFV6ZG1ONWJETklTVXQxY0VwbWNUSlUKUlVG
+RFpXWldhbW93ZEFwS1Z5dFlNelZRUjFkd09TOUlOWHBKVlU1V1RsWnFVemRWYlhNNE5FbDJTMmhT
+UWpnMU1USlFRamxWZVVoaApaMWhaVmxnMVIxZHdRV05XY0hsbWNteFNDa1pKT1ZGa2FHZ3JVR0py
+TUhWNWEzUmtZbVl2UTJSbVowaFBiMlZpY2xSMGQxSnNhazB3CmIwUjBXQ3N5UTNZMmFqQjNRa3Mz
+YUVRNGNGQjJaakVyZFhrS1IzcGplbWxuUVZVdk5FdDNOMlZhY1hsa1pqbENLelZTZFhCU0swbGEK
+YVhCWU5ERjRSV2xKY2t0U2QzRnBOVEUzVjFkNldHTnFZVWN5WTA1aVpqUTFNUXA0Y0VnMVVHNVdN
+Mmt4ZEhFd05HcE5SMUZWZWtaMwpTVVJCVVVGQ2J6UkhRVTFJTkhkSVVWbEVWbEl3VDBKQ1dVVkdT
+WGRZTkhaek9FSnBRbU5UWTI5a0NqVnViMXBJVWswNFJUUXJhVTFGClNVZEJNVlZrU1hkUk4wMUVi
+VUZHU1hkWU5IWnpPRUpwUW1OVFkyOWtOVzV2V2toU1RUaEZOQ3RwYjFKaGEwWkVRVk1LVFZKQmQw
+Um4KV1VSV1VWRkVSWGRrUmxGV1FXZFJNRVY0WjJkclFXZDFWVll6UkUxMFZ6WnpkMFJCV1VSV1Vq
+QlVRa0ZWZDBGM1JVSXZla0ZNUW1kTwpWZ3BJVVRoRlFrRk5RMEZSV1hkRVVWbEtTMjlhU1doMlkw
+NUJVVVZNUWxGQlJHZG5SVUpCUm1aUmNVOVVRVGRTZGpkTEsyeDFVVGR3CmJtRnpORUpaZDBoRkNq
+bEhSVkF2ZFc5b2RqWkxUM2t3VkVkUlJtSnlVbFJxUm05TVZrNUNPVUphTVhsdFRVUmFNQzlVU1hk
+SlZXTTMKZDJrM1lUaDBOVzFGY1ZsSU1UVXpkMWNLWVZkdmIybFRhbmxNVEdoMVNUUnpUbkpPUTA5
+MGFYTmtRbkV5Y2pKTlJsaDBObWd3YlVGUgpXVTlRZGpoU09FczNMMlpuVTNoSFJuRjZhSGxPYlcx
+V1RBb3hjVUpLYkdSNE16UlRjSGR6VkVGTVVWWlFZalJvUjNkS2VscG1jakZRClkzQkZVWGcyZUUx
+dVZHdzRlRVZYV2tVelRYTTVPWFZoVlhoaVVYRkpkMUoxQ2t4blFVOXJUa050V1RKdE9EbFdhSHBo
+U0VveGRWWTQKTlVGa1RTOTBSQ3RaYzIxc2JtNXFkRGxNVWtObGFtSkNhWEJxU1VkcVQxaHlaekZL
+VUN0c2VGWUtiWFZOTkhaSUsxQXZiV3h0ZUhOUQpVSG93WkRZMVlpdEZSMjFLV25CdlRHdFBMM1Jr
+VGs1MlExbDZha3B3VkVWWGNFVnpUelpPVFdoTFdXODlDaTB0TFMwdFJVNUVJRU5GClVsUkpSa2xE
+UVZSRkxTMHRMUzBLCg== \ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
index 975f8e539cc3..5c23f61b1711 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
@@ -1,85 +1,86 @@
-Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
-dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTMyCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
-cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
-IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
-SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
-YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
-UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
-V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
-M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
-MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
-VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
-RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
-QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
-QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
-QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
-bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
-MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
-Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
-ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
-YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
-VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
-YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
-RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
-bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
-MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
-MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
-UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
-eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
-QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
-OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
-dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
-S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
-K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
-dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
-TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
-SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
-WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
-VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
-MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
-Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
-V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
-a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
-eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
-QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
-VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
-KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
-bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
-OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
-Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
-VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
-UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
-SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
-WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
-V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
-bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
-QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
-LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
-UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
-VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
-bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
-azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
-VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
-TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
-TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
-dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
-RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
-U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
-ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
-M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
-CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
-TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
-U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
-YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
-MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
-akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
-MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
-amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
-ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
-OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
-MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
-MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
-aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
-S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
-a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
-RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
+TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5
+PXtib3VuZGFyeX07IGNoYXJzZXQ9VVRGLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogOGJp
+dAoKLS17Ym91bmRhcnl9CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24veC1wYXNzcG9pbnQtcHJv
+ZmlsZTsgY2hhcnNldD1VVEYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKClBF
+MW5iWFJVY21WbElIaHRiRzV6UFNKemVXNWpiV3c2Wkcxa1pHWXhMaklpUGdvZ0lEeFdaWEpFVkVR
+K01TNHlQQzlXWlhKRVZFUSsKQ2lBZ1BFNXZaR1UrQ2lBZ0lDQThUbTlrWlU1aGJXVStVR1Z5VUhK
+dmRtbGtaWEpUZFdKelkzSnBjSFJwYjI0OEwwNXZaR1ZPWVcxbApQZ29nSUNBZ1BGSlVVSEp2Y0dW
+eWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldVK2RYSnVPbmRt
+CllUcHRienBvYjNSemNHOTBNbVJ2ZERBdGNHVnljSEp2ZG1sa1pYSnpkV0p6WTNKcGNIUnBiMjQ2
+TVM0d1BDOUVSRVpPWVcxbFBnb2cKSUNBZ0lDQThMMVI1Y0dVK0NpQWdJQ0E4TDFKVVVISnZjR1Z5
+ZEdsbGN6NEtJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQThUbTlrWlU1aApiV1UrYVRBd01Ud3ZUbTlr
+WlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1SWIyMWxV
+MUE4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZa
+R1ZPWVcxbFBrWnlhV1Z1Wkd4NVRtRnQKWlR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThW
+bUZzZFdVK1JYaGhiWEJzWlNCT1pYUjNiM0pyUEM5V1lXeDFaVDRLSUNBZwpJQ0FnSUNBOEwwNXZa
+R1UrQ2lBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUmxGRVRq
+d3ZUbTlrClpVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBOFZtRnNkV1UrYUc5MGMzQnZkQzVsZUdGdGNH
+eGxMbTVsZER3dlZtRnNkV1UrQ2lBZ0lDQWcKSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2Iy
+UmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxKdllXMXBibWREYjI1egpiM0owYVhWdFQw
+azhMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakV4TWpJek15dzBORFUxTmpZ
+OEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNB
+Z0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWsKWlU1aGJXVStRM0psWkdWdWRHbGhiRHd2VG05
+a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05awpaVTVoYldV
+K1VtVmhiRzA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUG1WNFlXMXdiR1V1
+WTI5dFBDOVdZV3gxClpUNEtJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ1BFNXZaR1Ur
+Q2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1ZYTmwKY201aGJXVlFZWE56ZDI5eVpEd3ZUbTlr
+WlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dgpaR1ZP
+WVcxbFBsVnpaWEp1WVcxbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQ
+blZ6WlhJOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQ
+RTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnQKWlQ1UVlYTnpkMjl5WkR3dlRtOWta
+VTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhXWVd4MVpUNWpSMFo2WXpOa2RtTnRVVDA4TDFaaApi
+SFZsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lD
+QWdJQ0FnSUNBZ0lEeE9iMlJsClRtRnRaVDVGUVZCTlpYUm9iMlE4TDA1dlpHVk9ZVzFsUGdvZ0lD
+QWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWcKSUNBOFRtOWtaVTVoYldVK1JV
+RlFWSGx3WlR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakl4UEM5
+VwpZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4VG05
+a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnCklDQThUbTlrWlU1aGJXVStTVzV1WlhKTlpYUm9iMlE4TDA1
+dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQWdJRHhXWVd4MVpUNU4KVXkxRFNFRlFMVll5UEM5
+V1lXeDFaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJs
+UGdvZwpJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxUbUZ0WlQ1RWFXZHBkR0ZzClEyVnlkR2xtYVdOaGRHVThMMDV2WkdWT1lXMWxQZ29n
+SUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEow
+YVdacFkyRjBaVlI1Y0dVOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVStl
+RFV3T1hZegpQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZ0lDQWdJ
+RHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4ClRtOWtaVTVoYldVK1EyVnlkRk5JUVRJMU5rWnBi
+bWRsY25CeWFXNTBQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmgKYkhWbFBqRm1N
+V1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1X
+WXhaakZtTVdZeApaakZtTVdZeFpqRm1NV1k4TDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2Iy
+UmxQZ29nSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnCklDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lD
+QWdJRHhPYjJSbFRtRnRaVDVUU1UwOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWcKUEU1dlpH
+VStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1SlRWTkpQQzlPYjJSbFRtRnRaVDRLSUNB
+Z0lDQWdJQ0FnSUNBZwpQRlpoYkhWbFBqRXlNelExTmlvOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNB
+Z1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrCkNpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJS
+bFRtRnRaVDVGUVZCVWVYQmxQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmgKYkhW
+bFBqSXpQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZ0lDQThMMDV2
+WkdVK0NpQWdJQ0FnSUR3dgpUbTlrWlQ0S0lDQWdJRHd2VG05a1pUNEtJQ0E4TDA1dlpHVStDand2
+VFdkdGRGUnlaV1UrCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXg1
+MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFDUlVk
+SlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtRVWxN
+YkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5UbFlL
+UWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpUazFx
+V1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5VVEJG
+ZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMwTkJV
+VVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZYTldk
+VzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01TdHZS
+MWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJVRkRa
+V1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJoU1Fq
+ZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdKck1I
+VjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtzM2FF
+UTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxhCmFY
+QllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVXTTJr
+eGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZHU1hk
+WU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFFYlVG
+R1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJkMFJu
+CldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldVakJV
+UWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZMDVC
+VVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZDamxI
+UlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNYZEpW
+V00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1EwOTBh
+WE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JXMVdU
+QW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVFMXVW
+R3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhwaFNF
+b3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpGS1VD
+dHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNSa1Rr
+NTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmtsRFFW
+UkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo= \ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithUpdateIdentifier.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithUpdateIdentifier.base64
new file mode 100644
index 000000000000..bab7607512c8
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithUpdateIdentifier.base64
@@ -0,0 +1,88 @@
+TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5
+PXtib3VuZGFyeX07IGNoYXJzZXQ9VVRGLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFz
+ZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXBhc3Nwb2ludC1w
+cm9maWxlOyBjaGFyc2V0PVVURi04CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NAoK
+UEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29nSUR4V1pYSkVW
+RVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVoYldVK1VHVnlV
+SEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0FnUEZKVVVISnZj
+R1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhiV1UrZFhKdU9u
+ZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZM0pwY0hScGIy
+NDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThMMUpVVUhKdmNH
+VnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVStWWEJrWVhSbFNX
+UmxiblJwWm1sbGNqd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lEeFdZV3gxWlQ0eE1qTTBQQzlXWVd4
+MVpUNEsKSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoYldV
+K2FUQXdNVHd2VG05a1pVNWhiV1UrQ2lBZwpJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJS
+bFRtRnRaVDVJYjIxbFUxQThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJRHhPCmIyUmxQZ29nSUNB
+Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdFpUd3ZUbTlrWlU1aGJXVStDaUFn
+SUNBZ0lDQWcKSUNBOFZtRnNkV1UrUlhoaGJYQnNaU0JPWlhSM2IzSnJQQzlXWVd4MVpUNEtJQ0Fn
+SUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZwpQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlr
+WlU1aGJXVStSbEZFVGp3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthRzkw
+YzNCdmRDNWxlR0Z0Y0d4bExtNWxkRHd2Vm1Gc2RXVStDaUFnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJ
+Q0FnSUNBZ0lEeE8KYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERi
+MjV6YjNKMGFYVnRUMGs4TDA1dlpHVk9ZVzFsUGdvZwpJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhN
+akl6TXl3ME5EVTFOalk4TDFaaGJIVmxQZ29nSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnCklDQWdQ
+QzlPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUTNKbFpH
+VnVkR2xoYkR3dlRtOWsKWlU1aGJXVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lD
+QThUbTlrWlU1aGJXVStVbVZoYkcwOEwwNXZaR1ZPWVcxbApQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJI
+VmxQbVY0WVcxd2JHVXVZMjl0UEM5V1lXeDFaVDRLSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnCklD
+QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrVlhObGNtNWhiV1ZRWVhO
+emQyOXlaRHd2VG05a1pVNWgKYldVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNB
+Z0lDQWdQRTV2WkdWT1lXMWxQbFZ6WlhKdVlXMWxQQzlPYjJSbApUbUZ0WlQ0S0lDQWdJQ0FnSUNB
+Z0lDQWdQRlpoYkhWbFBuVnpaWEk4TDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29n
+CklDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsVG1GdFpUNVFZWE56
+ZDI5eVpEd3ZUbTlrWlU1aGJXVSsKQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1alIwWjZZek5r
+ZG1OdFVUMDhMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbApQZ29nSUNBZ0lDQWdJQ0Fn
+UEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1RlFWQk5aWFJvYjJROEwwNXZa
+R1ZPCllXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ0lDQThU
+bTlrWlU1aGJXVStSVUZRVkhsd1pUd3YKVG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdQ
+RlpoYkhWbFBqSXhQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEM5TwpiMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrU1c1dVpY
+Sk5aWFJvCmIyUThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1TlV5
+MURTRUZRTFZZeVBDOVdZV3gxWlQ0S0lDQWcKSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZwpJQ0E4VG05a1pU
+NEtJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVFYVdkcGRHRnNRMlZ5ZEdsbWFXTmhkR1U4TDA1
+dlpHVk9ZVzFsClBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJS
+bFRtRnRaVDVEWlhKMGFXWnBZMkYwWlZSNWNHVTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNB
+Z0lDQThWbUZzZFdVK2VEVXdPWFl6UEM5V1lXeDFaVDRLSUNBZ0lDQWdJQ0FnSUR3dgpUbTlrWlQ0
+S0lDQWdJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRMlZ5
+ZEZOSVFUSTFOa1pwCmJtZGxjbkJ5YVc1MFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0Fn
+UEZaaGJIVmxQakZtTVdZeFpqRm1NV1l4WmpGbU1XWXgKWmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4
+WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZOEwxWmhiSFZsUGdvZwpJQ0Fn
+SUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWta
+VDRLSUNBZ0lDQWdJQ0FnCklEeE9iMlJsVG1GdFpUNVRTVTA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKVFZOSlBDOU9i
+MlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakV5TXpRMU5pbzhMMVpoYkhWbApQ
+Z29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lD
+QWdJQ0FnSUR4T2IyUmxUbUZ0ClpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lD
+QWdJQ0FnUEZaaGJIVmxQakl6UEM5V1lXeDFaVDRLSUNBZ0lDQWcKSUNBZ0lEd3ZUbTlrWlQ0S0lD
+QWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUR3dlRtOWtaVDRLSUNB
+OApMMDV2WkdVK0Nqd3ZUV2R0ZEZSeVpXVSsKCi0te2JvdW5kYXJ5fQpDb250ZW50LVR5cGU6IGFw
+cGxpY2F0aW9uL3gteDUwOS1jYS1jZXJ0CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2
+NAoKTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUkxSRU5EUVdoRFow
+RjNTVUpCWjBsS1FVbE1iRVprZDNwTQpWblZ5VFVFd1IwTlRjVWRUU1dJelJGRkZRa04zVlVGTlFr
+bDRSVVJCVDBKblRsWUtRa0ZOVkVJd1ZrSlZRMEpFVVZSRmQwaG9ZMDVOClZGbDNUVlJGZVUxVVJU
+Rk5SRVV4VjJoalRrMXFXWGROVkVFMVRWUkZNVTFFUlRGWGFrRlRUVkpCZHdwRVoxbEVWbEZSUkVW
+M1pFWlIKVmtGblVUQkZlRTFKU1VKSmFrRk9RbWRyY1docmFVYzVkekJDUVZGRlJrRkJUME5CVVRo
+QlRVbEpRa05uUzBOQlVVVkJDbnB1UVZCVgplakkyVFhOaFpUUjNjelF6WTNwU05ERXZTakpSZEhK
+VFNWcFZTMjFXVlhOV2RXMUVZbGxJY2xCT2RsUllTMU5OV0VGalpYZFBVa1JSCldWZ0tVbkYyU0ha
+d2JqaERjMk5DTVN0dlIxaGFka2gzZUdvMGVsWXdWMHR2U3pKNlpWaHJZWFV6ZG1ONWJETklTVXQx
+Y0VwbWNUSlUKUlVGRFpXWldhbW93ZEFwS1Z5dFlNelZRUjFkd09TOUlOWHBKVlU1V1RsWnFVemRW
+YlhNNE5FbDJTMmhTUWpnMU1USlFRamxWZVVoaApaMWhaVmxnMVIxZHdRV05XY0hsbWNteFNDa1pK
+T1ZGa2FHZ3JVR0pyTUhWNWEzUmtZbVl2UTJSbVowaFBiMlZpY2xSMGQxSnNhazB3CmIwUjBXQ3N5
+UTNZMmFqQjNRa3MzYUVRNGNGQjJaakVyZFhrS1IzcGplbWxuUVZVdk5FdDNOMlZhY1hsa1pqbENL
+elZTZFhCU0swbGEKYVhCWU5ERjRSV2xKY2t0U2QzRnBOVEUzVjFkNldHTnFZVWN5WTA1aVpqUTFN
+UXA0Y0VnMVVHNVdNMmt4ZEhFd05HcE5SMUZWZWtaMwpTVVJCVVVGQ2J6UkhRVTFJTkhkSVVWbEVW
+bEl3VDBKQ1dVVkdTWGRZTkhaek9FSnBRbU5UWTI5a0NqVnViMXBJVWswNFJUUXJhVTFGClNVZEJN
+VlZrU1hkUk4wMUViVUZHU1hkWU5IWnpPRUpwUW1OVFkyOWtOVzV2V2toU1RUaEZOQ3RwYjFKaGEw
+WkVRVk1LVFZKQmQwUm4KV1VSV1VWRkVSWGRrUmxGV1FXZFJNRVY0WjJkclFXZDFWVll6UkUxMFZ6
+WnpkMFJCV1VSV1VqQlVRa0ZWZDBGM1JVSXZla0ZNUW1kTwpWZ3BJVVRoRlFrRk5RMEZSV1hkRVVW
+bEtTMjlhU1doMlkwNUJVVVZNUWxGQlJHZG5SVUpCUm1aUmNVOVVRVGRTZGpkTEsyeDFVVGR3CmJt
+RnpORUpaZDBoRkNqbEhSVkF2ZFc5b2RqWkxUM2t3VkVkUlJtSnlVbFJxUm05TVZrNUNPVUphTVhs
+dFRVUmFNQzlVU1hkSlZXTTMKZDJrM1lUaDBOVzFGY1ZsSU1UVXpkMWNLWVZkdmIybFRhbmxNVEdo
+MVNUUnpUbkpPUTA5MGFYTmtRbkV5Y2pKTlJsaDBObWd3YlVGUgpXVTlRZGpoU09FczNMMlpuVTNo
+SFJuRjZhSGxPYlcxV1RBb3hjVUpLYkdSNE16UlRjSGR6VkVGTVVWWlFZalJvUjNkS2VscG1jakZR
+ClkzQkZVWGcyZUUxdVZHdzRlRVZYV2tVelRYTTVPWFZoVlhoaVVYRkpkMUoxQ2t4blFVOXJUa050
+V1RKdE9EbFdhSHBoU0VveGRWWTQKTlVGa1RTOTBSQ3RaYzIxc2JtNXFkRGxNVWtObGFtSkNhWEJx
+U1VkcVQxaHlaekZLVUN0c2VGWUtiWFZOTkhaSUsxQXZiV3h0ZUhOUQpVSG93WkRZMVlpdEZSMjFL
+V25CdlRHdFBMM1JrVGs1MlExbDZha3B3VkVWWGNFVnpUelpPVFdoTFdXODlDaTB0TFMwdFJVNUVJ
+RU5GClVsUkpSa2xEUVZSRkxTMHRMUzBLCi0te2JvdW5kYXJ5fS0tCg== \ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/README.txt b/wifi/tests/assets/hsr1/README.txt
index d1f8384fc979..9f3cdc274ee1 100644
--- a/wifi/tests/assets/hsr1/README.txt
+++ b/wifi/tests/assets/hsr1/README.txt
@@ -2,4 +2,5 @@ HSR1ProfileWithCACert.conf - unencoded installation file that contains a Passpoi
HSR1ProfileWithCACert.base64 - base64 encoded of the data contained in HSR1ProfileWithCAWith.conf
HSR1ProfileWithNonBase64Part.base64 - base64 encoded installation file that contains a part of non-base64 encoding type
HSR1ProfileWithMissingBoundary.base64 - base64 encoded installation file with missing end-boundary in the MIME data
-HSR1ProfileWithInvalidContentType.base64 - base64 encoded installation file with that contains a MIME part with an invalid content type.
+HSR1ProfileWithInvalidContentType.base64 - base64 encoded installation file with that contains a MIME part with an invalid content type
+HSR1ProfileWithUpdateIdentifier.base64 - base64 encoded installation file with that contains an R2 update identifier
diff --git a/wifi/tests/assets/pps/PerProviderSubscription.xml b/wifi/tests/assets/pps/PerProviderSubscription.xml
index e4472ce19d51..e9afb35fec94 100644
--- a/wifi/tests/assets/pps/PerProviderSubscription.xml
+++ b/wifi/tests/assets/pps/PerProviderSubscription.xml
@@ -19,6 +19,30 @@
<NodeName>VendorSpecific</NodeName>
<Value>Test</Value>
</Node>
+ <Node>
+ <NodeName>VendorExtension</NodeName>
+ <Node>
+ <NodeName>VendorAttribute</NodeName>
+ <Value>VendorValue</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>Android</NodeName>
+ <Node>
+ <NodeName>AAAServerTrustedNames</NodeName>
+ <Node>
+ <NodeName>FQDN</NodeName>
+ <Value>trusted.fqdn.com;another-trusted.fqdn.com</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>NewSubTree</NodeName>
+ <Node>
+ <NodeName>NewAttribute</NodeName>
+ <Value>NewValue</Value>
+ </Node>
+ </Node>
+ </Node>
</Node>
<Node>
<NodeName>HomeSP</NodeName>
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
deleted file mode 100755
index 219a45ee188f..000000000000
--- a/wifi/tests/runtests.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env bash
-
-if [ -z $ANDROID_BUILD_TOP ]; then
- echo "You need to source and lunch before you can use this script"
- exit 1
-fi
-
-echo "Running tests"
-
-set -e # fail early
-
-echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests"
-# NOTE Don't actually run the command above since this shell doesn't inherit functions from the
-# caller.
-make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-wifi-tests
-
-set -x # print commands
-
-adb root
-adb wait-for-device
-
-TARGET_ARCH=$($ANDROID_BUILD_TOP/build/soong/soong_ui.bash --dumpvar-mode TARGET_ARCH)
-adb install -r -g "$OUT/testcases/FrameworksWifiApiTests/$TARGET_ARCH/FrameworksWifiApiTests.apk"
-
-adb shell am instrument --no-hidden-api-checks -w "$@" \
- 'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner'
diff --git a/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java b/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
new file mode 100644
index 000000000000..b10141434b0b
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.util.SparseArray;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.EasyConnectStatusCallbackTest}.
+ */
+@SmallTest
+public class EasyConnectStatusCallbackTest {
+ private EasyConnectStatusCallback mEasyConnectStatusCallback = new EasyConnectStatusCallback() {
+ @Override
+ public void onEnrolleeSuccess(int newNetworkId) {
+
+ }
+
+ @Override
+ public void onConfiguratorSuccess(int code) {
+
+ }
+
+ @Override
+ public void onProgress(int code) {
+
+ }
+
+ @Override
+ public void onFailure(int code) {
+ mOnFailureR1EventReceived = true;
+ mLastCode = code;
+ }
+ };
+ private boolean mOnFailureR1EventReceived;
+ private int mLastCode;
+
+ @Before
+ public void setUp() {
+ mOnFailureR1EventReceived = false;
+ mLastCode = 0;
+ }
+
+ /**
+ * Test that the legacy R1 onFailure is called by default if the R2 onFailure is not overridden
+ * by the app.
+ */
+ @Test
+ public void testR1OnFailureCalled() {
+
+ SparseArray<int[]> channelList = new SparseArray<>();
+ int[] channelArray = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+
+ channelList.append(81, channelArray);
+ mEasyConnectStatusCallback.onFailure(
+ EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
+ "SomeSSID", channelList, new int[] {81});
+
+ assertTrue(mOnFailureR1EventReceived);
+ assertEquals(mLastCode,
+ EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK);
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/ScanResultTest.java b/wifi/tests/src/android/net/wifi/ScanResultTest.java
index 54ec32502878..5516f433070f 100644
--- a/wifi/tests/src/android/net/wifi/ScanResultTest.java
+++ b/wifi/tests/src/android/net/wifi/ScanResultTest.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.validateMockitoUsage;
+import android.net.wifi.ScanResult.InformationElement;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -41,6 +42,70 @@ public class ScanResultTest {
public static final int TEST_LEVEL = -56;
public static final int TEST_FREQUENCY = 2412;
public static final long TEST_TSF = 04660l;
+ public static final @WifiAnnotations.WifiStandard int TEST_WIFI_STANDARD =
+ ScanResult.WIFI_STANDARD_11AC;
+
+ /**
+ * Frequency to channel map. This include some frequencies used outside the US.
+ * Representing it using a vector (instead of map) for simplification.
+ */
+ private static final int[] FREQUENCY_TO_CHANNEL_MAP = {
+ 2412, WifiScanner.WIFI_BAND_24_GHZ, 1,
+ 2417, WifiScanner.WIFI_BAND_24_GHZ, 2,
+ 2422, WifiScanner.WIFI_BAND_24_GHZ, 3,
+ 2427, WifiScanner.WIFI_BAND_24_GHZ, 4,
+ 2432, WifiScanner.WIFI_BAND_24_GHZ, 5,
+ 2437, WifiScanner.WIFI_BAND_24_GHZ, 6,
+ 2442, WifiScanner.WIFI_BAND_24_GHZ, 7,
+ 2447, WifiScanner.WIFI_BAND_24_GHZ, 8,
+ 2452, WifiScanner.WIFI_BAND_24_GHZ, 9,
+ 2457, WifiScanner.WIFI_BAND_24_GHZ, 10,
+ 2462, WifiScanner.WIFI_BAND_24_GHZ, 11,
+ /* 12, 13 are only legitimate outside the US. */
+ 2467, WifiScanner.WIFI_BAND_24_GHZ, 12,
+ 2472, WifiScanner.WIFI_BAND_24_GHZ, 13,
+ /* 14 is for Japan, DSSS and CCK only. */
+ 2484, WifiScanner.WIFI_BAND_24_GHZ, 14,
+ /* 34 valid in Japan. */
+ 5170, WifiScanner.WIFI_BAND_5_GHZ, 34,
+ 5180, WifiScanner.WIFI_BAND_5_GHZ, 36,
+ 5190, WifiScanner.WIFI_BAND_5_GHZ, 38,
+ 5200, WifiScanner.WIFI_BAND_5_GHZ, 40,
+ 5210, WifiScanner.WIFI_BAND_5_GHZ, 42,
+ 5220, WifiScanner.WIFI_BAND_5_GHZ, 44,
+ 5230, WifiScanner.WIFI_BAND_5_GHZ, 46,
+ 5240, WifiScanner.WIFI_BAND_5_GHZ, 48,
+ 5260, WifiScanner.WIFI_BAND_5_GHZ, 52,
+ 5280, WifiScanner.WIFI_BAND_5_GHZ, 56,
+ 5300, WifiScanner.WIFI_BAND_5_GHZ, 60,
+ 5320, WifiScanner.WIFI_BAND_5_GHZ, 64,
+ 5500, WifiScanner.WIFI_BAND_5_GHZ, 100,
+ 5520, WifiScanner.WIFI_BAND_5_GHZ, 104,
+ 5540, WifiScanner.WIFI_BAND_5_GHZ, 108,
+ 5560, WifiScanner.WIFI_BAND_5_GHZ, 112,
+ 5580, WifiScanner.WIFI_BAND_5_GHZ, 116,
+ /* 120, 124, 128 valid in Europe/Japan. */
+ 5600, WifiScanner.WIFI_BAND_5_GHZ, 120,
+ 5620, WifiScanner.WIFI_BAND_5_GHZ, 124,
+ 5640, WifiScanner.WIFI_BAND_5_GHZ, 128,
+ /* 132+ valid in US. */
+ 5660, WifiScanner.WIFI_BAND_5_GHZ, 132,
+ 5680, WifiScanner.WIFI_BAND_5_GHZ, 136,
+ 5700, WifiScanner.WIFI_BAND_5_GHZ, 140,
+ /* 144 is supported by a subset of WiFi chips. */
+ 5720, WifiScanner.WIFI_BAND_5_GHZ, 144,
+ 5745, WifiScanner.WIFI_BAND_5_GHZ, 149,
+ 5765, WifiScanner.WIFI_BAND_5_GHZ, 153,
+ 5785, WifiScanner.WIFI_BAND_5_GHZ, 157,
+ 5805, WifiScanner.WIFI_BAND_5_GHZ, 161,
+ 5825, WifiScanner.WIFI_BAND_5_GHZ, 165,
+ 5845, WifiScanner.WIFI_BAND_5_GHZ, 169,
+ 5865, WifiScanner.WIFI_BAND_5_GHZ, 173,
+ /* Now some 6GHz channels */
+ 5945, WifiScanner.WIFI_BAND_6_GHZ, 1,
+ 5960, WifiScanner.WIFI_BAND_6_GHZ, 4,
+ 6100, WifiScanner.WIFI_BAND_6_GHZ, 32
+ };
/**
* Setup before tests.
@@ -124,17 +189,37 @@ public class ScanResultTest {
}
/**
+ * Verify parcel read/write for ScanResult with Information Element
+ */
+ @Test
+ public void verifyScanResultParcelWithInformationElement() throws Exception {
+ ScanResult writeScanResult = createScanResult();
+ writeScanResult.informationElements = new ScanResult.InformationElement[2];
+ writeScanResult.informationElements[0] = new ScanResult.InformationElement();
+ writeScanResult.informationElements[0].id = InformationElement.EID_HT_OPERATION;
+ writeScanResult.informationElements[0].idExt = 0;
+ writeScanResult.informationElements[0].bytes = new byte[]{0x11, 0x22, 0x33};
+ writeScanResult.informationElements[1] = new ScanResult.InformationElement();
+ writeScanResult.informationElements[1].id = InformationElement.EID_EXTENSION_PRESENT;
+ writeScanResult.informationElements[1].idExt = InformationElement.EID_EXT_HE_OPERATION;
+ writeScanResult.informationElements[1].bytes = new byte[]{0x44, 0x55, 0x66};
+ ScanResult readScanResult = new ScanResult(writeScanResult);
+ assertScanResultEquals(writeScanResult, readScanResult);
+ }
+
+ /**
* Verify toString for ScanResult.
*/
@Test
public void verifyScanResultToStringWithoutRadioChainInfo() throws Exception {
ScanResult scanResult = createScanResult();
- assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, " +
- "level: -56, frequency: 2412, timestamp: 2480, distance: 0(cm), distanceSd: 0(cm), " +
- "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, " +
- "80211mcResponder: is not supported, Carrier AP: no, " +
- "Carrier AP EAP Type: 0, Carrier name: null, " +
- "Radio Chain Infos: null", scanResult.toString());
+ assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, "
+ + "level: -56, frequency: 2412, timestamp: 2480, "
+ + "distance: 0(cm), distanceSd: 0(cm), "
+ + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, "
+ + "standard: 11ac, "
+ + "80211mcResponder: is not supported, "
+ + "Radio Chain Infos: null", scanResult.toString());
}
/**
@@ -150,13 +235,33 @@ public class ScanResultTest {
scanResult.radioChainInfos[1] = new ScanResult.RadioChainInfo();
scanResult.radioChainInfos[1].id = 1;
scanResult.radioChainInfos[1].level = -54;
- assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, " +
- "level: -56, frequency: 2412, timestamp: 2480, distance: 0(cm), distanceSd: 0(cm), " +
- "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, " +
- "80211mcResponder: is not supported, Carrier AP: no, " +
- "Carrier AP EAP Type: 0, Carrier name: null, " +
- "Radio Chain Infos: [RadioChainInfo: id=0, level=-45, " +
- "RadioChainInfo: id=1, level=-54]", scanResult.toString());
+ assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, "
+ + "level: -56, frequency: 2412, timestamp: 2480, distance: 0(cm), "
+ + "distanceSd: 0(cm), "
+ + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, "
+ + "standard: 11ac, "
+ + "80211mcResponder: is not supported, "
+ + "Radio Chain Infos: [RadioChainInfo: id=0, level=-45, "
+ + "RadioChainInfo: id=1, level=-54]", scanResult.toString());
+ }
+
+ /**
+ * verify frequency to channel conversion for all possible frequencies.
+ */
+ @Test
+ public void convertFrequencyToChannel() throws Exception {
+ for (int i = 0; i < FREQUENCY_TO_CHANNEL_MAP.length; i += 3) {
+ assertEquals(FREQUENCY_TO_CHANNEL_MAP[i + 2],
+ ScanResult.convertFrequencyMhzToChannel(FREQUENCY_TO_CHANNEL_MAP[i]));
+ }
+ }
+
+ /**
+ * Verify frequency to channel conversion failed for an invalid frequency.
+ */
+ @Test
+ public void convertFrequencyToChannelWithInvalidFreq() throws Exception {
+ assertEquals(-1, ScanResult.convertFrequencyMhzToChannel(8000));
}
/**
@@ -177,6 +282,7 @@ public class ScanResultTest {
result.level = TEST_LEVEL;
result.frequency = TEST_FREQUENCY;
result.timestamp = TEST_TSF;
+ result.setWifiStandard(TEST_WIFI_STANDARD);
return result;
}
@@ -187,6 +293,8 @@ public class ScanResultTest {
assertEquals(expected.level, actual.level);
assertEquals(expected.frequency, actual.frequency);
assertEquals(expected.timestamp, actual.timestamp);
+ assertEquals(expected.getWifiStandard(), actual.getWifiStandard());
assertArrayEquals(expected.radioChainInfos, actual.radioChainInfos);
+ assertArrayEquals(expected.informationElements, actual.informationElements);
}
}
diff --git a/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java b/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java
new file mode 100644
index 000000000000..73b501a4d8f2
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.os.Parcel;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.SoftApCapability}.
+ */
+@SmallTest
+public class SoftApCapabilityTest {
+
+ /**
+ * Verifies copy constructor.
+ */
+ @Test
+ public void testCopyOperator() throws Exception {
+ long testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
+ | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
+ SoftApCapability capability = new SoftApCapability(testSoftApFeature);
+ capability.setMaxSupportedClients(10);
+
+ SoftApCapability copiedCapability = new SoftApCapability(capability);
+
+ assertEquals(capability, copiedCapability);
+ assertEquals(capability.hashCode(), copiedCapability.hashCode());
+ }
+
+ /**
+ * Verifies parcel serialization/deserialization.
+ */
+ @Test
+ public void testParcelOperation() throws Exception {
+ long testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
+ | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
+ SoftApCapability capability = new SoftApCapability(testSoftApFeature);
+ capability.setMaxSupportedClients(10);
+
+ Parcel parcelW = Parcel.obtain();
+ capability.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ SoftApCapability fromParcel = SoftApCapability.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(capability, fromParcel);
+ assertEquals(capability.hashCode(), fromParcel.hashCode());
+ }
+
+}
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java b/wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
new file mode 100644
index 000000000000..f49f387cbc6b
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Unit tests for {@link android.net.wifi.SoftApConfToXmlMigrationUtilTest}.
+ */
+@SmallTest
+public class SoftApConfToXmlMigrationUtilTest {
+ private static final String TEST_SSID = "SSID";
+ private static final String TEST_PASSPHRASE = "TestPassphrase";
+ private static final int TEST_CHANNEL = 0;
+ private static final boolean TEST_HIDDEN = false;
+ private static final int TEST_BAND = SoftApConfiguration.BAND_5GHZ;
+ private static final int TEST_SECURITY = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+
+ private static final String TEST_EXPECTED_XML_STRING =
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<WifiConfigStoreData>\n"
+ + "<int name=\"Version\" value=\"3\" />\n"
+ + "<SoftAp>\n"
+ + "<string name=\"SSID\">" + TEST_SSID + "</string>\n"
+ + "<int name=\"ApBand\" value=\"" + TEST_BAND + "\" />\n"
+ + "<int name=\"Channel\" value=\"" + TEST_CHANNEL + "\" />\n"
+ + "<boolean name=\"HiddenSSID\" value=\"" + TEST_HIDDEN + "\" />\n"
+ + "<int name=\"SecurityType\" value=\"" + TEST_SECURITY + "\" />\n"
+ + "<string name=\"Passphrase\">" + TEST_PASSPHRASE + "</string>\n"
+ + "<int name=\"MaxNumberOfClients\" value=\"0\" />\n"
+ + "<boolean name=\"ClientControlByUser\" value=\"false\" />\n"
+ + "<boolean name=\"AutoShutdownEnabled\" value=\"true\" />\n"
+ + "<long name=\"ShutdownTimeoutMillis\" value=\"0\" />\n"
+ + "<BlockedClientList />\n"
+ + "<AllowedClientList />\n"
+ + "</SoftAp>\n"
+ + "</WifiConfigStoreData>\n";
+
+ private byte[] createLegacyApConfFile(WifiConfiguration config) throws Exception {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(outputStream);
+ out.writeInt(3);
+ out.writeUTF(config.SSID);
+ out.writeInt(config.apBand);
+ out.writeInt(config.apChannel);
+ out.writeBoolean(config.hiddenSSID);
+ int authType = config.getAuthType();
+ out.writeInt(authType);
+ if (authType != WifiConfiguration.KeyMgmt.NONE) {
+ out.writeUTF(config.preSharedKey);
+ }
+ out.close();
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * Generate a SoftApConfiguration based on the specified parameters.
+ */
+ private SoftApConfiguration setupApConfig(
+ String ssid, String preSharedKey, int keyManagement, int band, int channel,
+ boolean hiddenSSID) {
+ SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
+ configBuilder.setSsid(ssid);
+ configBuilder.setPassphrase(preSharedKey, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ if (channel == 0) {
+ configBuilder.setBand(band);
+ } else {
+ configBuilder.setChannel(channel, band);
+ }
+ configBuilder.setHiddenSsid(hiddenSSID);
+ return configBuilder.build();
+ }
+
+ /**
+ * Generate a WifiConfiguration based on the specified parameters.
+ */
+ private WifiConfiguration setupWifiConfigurationApConfig(
+ String ssid, String preSharedKey, int keyManagement, int band, int channel,
+ boolean hiddenSSID) {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = ssid;
+ config.preSharedKey = preSharedKey;
+ config.allowedKeyManagement.set(keyManagement);
+ config.apBand = band;
+ config.apChannel = channel;
+ config.hiddenSSID = hiddenSSID;
+ return config;
+ }
+
+ /**
+ * Asserts that the WifiConfigurations equal to SoftApConfiguration.
+ * This only compares the elements saved
+ * for softAp used.
+ */
+ public static void assertWifiConfigurationEqualSoftApConfiguration(
+ WifiConfiguration backup, SoftApConfiguration restore) {
+ assertEquals(backup.SSID, restore.getSsid());
+ assertEquals(backup.BSSID, restore.getBssid());
+ assertEquals(SoftApConfToXmlMigrationUtil.convertWifiConfigBandToSoftApConfigBand(
+ backup.apBand),
+ restore.getBand());
+ assertEquals(backup.apChannel, restore.getChannel());
+ assertEquals(backup.preSharedKey, restore.getPassphrase());
+ if (backup.getAuthType() == WifiConfiguration.KeyMgmt.WPA2_PSK) {
+ assertEquals(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, restore.getSecurityType());
+ } else {
+ assertEquals(SoftApConfiguration.SECURITY_TYPE_OPEN, restore.getSecurityType());
+ }
+ assertEquals(backup.hiddenSSID, restore.isHiddenSsid());
+ }
+
+ /**
+ * Note: This is a copy of {@link AtomicFile#readFully()} modified to use the passed in
+ * {@link InputStream} which was returned using {@link AtomicFile#openRead()}.
+ */
+ private static byte[] readFully(InputStream stream) throws IOException {
+ try {
+ int pos = 0;
+ int avail = stream.available();
+ byte[] data = new byte[avail];
+ while (true) {
+ int amt = stream.read(data, pos, data.length - pos);
+ if (amt <= 0) {
+ return data;
+ }
+ pos += amt;
+ avail = stream.available();
+ if (avail > data.length - pos) {
+ byte[] newData = new byte[pos + avail];
+ System.arraycopy(data, 0, newData, 0, pos);
+ data = newData;
+ }
+ }
+ } finally {
+ stream.close();
+ }
+ }
+
+ /**
+ * Tests conversion from legacy .conf file to XML file format.
+ */
+ @Test
+ public void testConversion() throws Exception {
+ WifiConfiguration backupConfig = setupWifiConfigurationApConfig(
+ TEST_SSID, /* SSID */
+ TEST_PASSPHRASE, /* preshared key */
+ WifiConfiguration.KeyMgmt.WPA2_PSK, /* key management */
+ 1, /* AP band (5GHz) */
+ TEST_CHANNEL, /* AP channel */
+ TEST_HIDDEN /* Hidden SSID */);
+ SoftApConfiguration expectedConfig = setupApConfig(
+ TEST_SSID, /* SSID */
+ TEST_PASSPHRASE, /* preshared key */
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, /* security type */
+ SoftApConfiguration.BAND_5GHZ, /* AP band (5GHz) */
+ TEST_CHANNEL, /* AP channel */
+ TEST_HIDDEN /* Hidden SSID */);
+
+ assertWifiConfigurationEqualSoftApConfiguration(backupConfig, expectedConfig);
+
+ byte[] confBytes = createLegacyApConfFile(backupConfig);
+ assertNotNull(confBytes);
+
+ InputStream xmlStream = SoftApConfToXmlMigrationUtil.convert(
+ new ByteArrayInputStream(confBytes));
+
+ byte[] xmlBytes = readFully(xmlStream);
+ assertNotNull(xmlBytes);
+
+ assertEquals(TEST_EXPECTED_XML_STRING, new String(xmlBytes));
+ }
+
+}
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
new file mode 100644
index 000000000000..1a4427034756
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertNull;
+
+import android.net.MacAddress;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+@SmallTest
+public class SoftApConfigurationTest {
+ private static final String TEST_CHAR_SET_AS_STRING = "abcdefghijklmnopqrstuvwxyz0123456789";
+
+ private SoftApConfiguration parcelUnparcel(SoftApConfiguration configIn) {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeParcelable(configIn, 0);
+ parcel.setDataPosition(0);
+ SoftApConfiguration configOut =
+ parcel.readParcelable(SoftApConfiguration.class.getClassLoader());
+ parcel.recycle();
+ return configOut;
+ }
+
+ /**
+ * Helper method to generate random string.
+ *
+ * Note: this method has limited use as a random string generator.
+ * The characters used in this method do no not cover all valid inputs.
+ * @param length number of characters to generate for the string
+ * @return String generated string of random characters
+ */
+ private String generateRandomString(int length) {
+ Random random = new Random();
+ StringBuilder stringBuilder = new StringBuilder(length);
+ int index = -1;
+ while (stringBuilder.length() < length) {
+ index = random.nextInt(TEST_CHAR_SET_AS_STRING.length());
+ stringBuilder.append(TEST_CHAR_SET_AS_STRING.charAt(index));
+ }
+ return stringBuilder.toString();
+ }
+
+ @Test
+ public void testBasicSettings() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setSsid("ssid")
+ .setBssid(MacAddress.fromString("11:22:33:44:55:66"))
+ .build();
+ assertThat(original.getSsid()).isEqualTo("ssid");
+ assertThat(original.getBssid()).isEqualTo(MacAddress.fromString("11:22:33:44:55:66"));
+ assertThat(original.getPassphrase()).isNull();
+ assertThat(original.getSecurityType()).isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+ assertThat(original.getChannel()).isEqualTo(0);
+ assertThat(original.isHiddenSsid()).isEqualTo(false);
+ assertThat(original.getMaxNumberOfClients()).isEqualTo(0);
+
+ SoftApConfiguration unparceled = parcelUnparcel(original);
+ assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isEqualTo(original);
+ assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+ SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+ assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isEqualTo(original);
+ assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ public void testWpa2() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .build();
+ assertThat(original.getPassphrase()).isEqualTo("secretsecret");
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+ assertThat(original.getChannel()).isEqualTo(0);
+ assertThat(original.isHiddenSsid()).isEqualTo(false);
+ assertThat(original.getMaxNumberOfClients()).isEqualTo(0);
+
+ SoftApConfiguration unparceled = parcelUnparcel(original);
+ assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isEqualTo(original);
+ assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+ SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+ assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isEqualTo(original);
+ assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ public void testWpa2WithAllFieldCustomized() {
+ List<MacAddress> testBlockedClientList = new ArrayList<>();
+ List<MacAddress> testAllowedClientList = new ArrayList<>();
+ testBlockedClientList.add(MacAddress.fromString("11:22:33:44:55:66"));
+ testAllowedClientList.add(MacAddress.fromString("aa:bb:cc:dd:ee:ff"));
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .setMaxNumberOfClients(10)
+ .setAutoShutdownEnabled(true)
+ .setShutdownTimeoutMillis(500000)
+ .setClientControlByUserEnabled(true)
+ .setBlockedClientList(testBlockedClientList)
+ .setAllowedClientList(testAllowedClientList)
+ .build();
+ assertThat(original.getPassphrase()).isEqualTo("secretsecret");
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
+ assertThat(original.getChannel()).isEqualTo(149);
+ assertThat(original.isHiddenSsid()).isEqualTo(true);
+ assertThat(original.getMaxNumberOfClients()).isEqualTo(10);
+ assertThat(original.isAutoShutdownEnabled()).isEqualTo(true);
+ assertThat(original.getShutdownTimeoutMillis()).isEqualTo(500000);
+ assertThat(original.isClientControlByUserEnabled()).isEqualTo(true);
+ assertThat(original.getBlockedClientList()).isEqualTo(testBlockedClientList);
+ assertThat(original.getAllowedClientList()).isEqualTo(testAllowedClientList);
+
+ SoftApConfiguration unparceled = parcelUnparcel(original);
+ assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isEqualTo(original);
+ assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+ SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+ assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isEqualTo(original);
+ assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ public void testWpa3Sae() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ assertThat(original.getPassphrase()).isEqualTo("secretsecret");
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
+ assertThat(original.getChannel()).isEqualTo(149);
+ assertThat(original.isHiddenSsid()).isEqualTo(true);
+
+
+ SoftApConfiguration unparceled = parcelUnparcel(original);
+ assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isEqualTo(original);
+ assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+ SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+ assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isEqualTo(original);
+ assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ public void testWpa3SaeTransition() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+ assertThat(original.getPassphrase()).isEqualTo("secretsecret");
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
+ assertThat(original.getChannel()).isEqualTo(149);
+ assertThat(original.isHiddenSsid()).isEqualTo(true);
+
+
+ SoftApConfiguration unparceled = parcelUnparcel(original);
+ assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isEqualTo(original);
+ assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+ SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+ assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isEqualTo(original);
+ assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidShortPasswordLengthForWpa2() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MIN_LEN - 1),
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidLongPasswordLengthForWpa2() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MAX_LEN + 1),
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidShortPasswordLengthForWpa3SaeTransition() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MIN_LEN - 1),
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidLongPasswordLengthForWpa3SaeTransition() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MAX_LEN + 1),
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalieShutdownTimeoutMillis() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setShutdownTimeoutMillis(-1)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetClientListExceptionWhenExistMacAddressInBothList() {
+ final MacAddress testMacAddress_1 = MacAddress.fromString("22:33:44:55:66:77");
+ final MacAddress testMacAddress_2 = MacAddress.fromString("aa:bb:cc:dd:ee:ff");
+ ArrayList<MacAddress> testAllowedClientList = new ArrayList<>();
+ testAllowedClientList.add(testMacAddress_1);
+ testAllowedClientList.add(testMacAddress_2);
+ ArrayList<MacAddress> testBlockedClientList = new ArrayList<>();
+ testBlockedClientList.add(testMacAddress_1);
+ SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
+ configBuilder.setBlockedClientList(testBlockedClientList)
+ .setAllowedClientList(testAllowedClientList)
+ .build();
+ }
+
+ @Test
+ public void testToWifiConfigurationWithUnsupportedParameter() {
+ SoftApConfiguration sae_config = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)
+ .build();
+
+ assertNull(sae_config.toWifiConfiguration());
+ SoftApConfiguration band_6g_config = new SoftApConfiguration.Builder()
+ .setBand(SoftApConfiguration.BAND_6GHZ)
+ .build();
+
+ assertNull(band_6g_config.toWifiConfiguration());
+ SoftApConfiguration sae_transition_config = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
+ .build();
+
+ assertNull(sae_transition_config.toWifiConfiguration());
+ }
+
+ @Test
+ public void testToWifiConfigurationWithSupportedParameter() {
+ SoftApConfiguration softApConfig_2g = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setChannel(11, SoftApConfiguration.BAND_2GHZ)
+ .setHiddenSsid(true)
+ .build();
+ WifiConfiguration wifiConfig_2g = softApConfig_2g.toWifiConfiguration();
+ assertThat(wifiConfig_2g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
+ assertThat(wifiConfig_2g.preSharedKey).isEqualTo("secretsecret");
+ assertThat(wifiConfig_2g.apBand).isEqualTo(WifiConfiguration.AP_BAND_2GHZ);
+ assertThat(wifiConfig_2g.apChannel).isEqualTo(11);
+ assertThat(wifiConfig_2g.hiddenSSID).isEqualTo(true);
+
+ SoftApConfiguration softApConfig_5g = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ WifiConfiguration wifiConfig_5g = softApConfig_5g.toWifiConfiguration();
+ assertThat(wifiConfig_5g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
+ assertThat(wifiConfig_5g.preSharedKey).isEqualTo("secretsecret");
+ assertThat(wifiConfig_5g.apBand).isEqualTo(WifiConfiguration.AP_BAND_5GHZ);
+ assertThat(wifiConfig_5g.apChannel).isEqualTo(149);
+ assertThat(wifiConfig_5g.hiddenSSID).isEqualTo(true);
+
+ SoftApConfiguration softApConfig_2g5g = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ WifiConfiguration wifiConfig_2g5g = softApConfig_2g5g.toWifiConfiguration();
+ assertThat(wifiConfig_2g5g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
+ assertThat(wifiConfig_2g5g.preSharedKey).isEqualTo("secretsecret");
+ assertThat(wifiConfig_2g5g.apBand).isEqualTo(WifiConfiguration.AP_BAND_ANY);
+ assertThat(wifiConfig_2g5g.apChannel).isEqualTo(0);
+ assertThat(wifiConfig_2g5g.hiddenSSID).isEqualTo(true);
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/SoftApInfoTest.java b/wifi/tests/src/android/net/wifi/SoftApInfoTest.java
new file mode 100644
index 000000000000..929f3ab88fd8
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/SoftApInfoTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.os.Parcel;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.SoftApInfo}.
+ */
+@SmallTest
+public class SoftApInfoTest {
+
+ /**
+ * Verifies copy constructor.
+ */
+ @Test
+ public void testCopyOperator() throws Exception {
+ SoftApInfo info = new SoftApInfo();
+ info.setFrequency(2412);
+ info.setBandwidth(SoftApInfo.CHANNEL_WIDTH_20MHZ);
+
+ SoftApInfo copiedInfo = new SoftApInfo(info);
+
+ assertEquals(info, copiedInfo);
+ assertEquals(info.hashCode(), copiedInfo.hashCode());
+ }
+
+ /**
+ * Verifies parcel serialization/deserialization.
+ */
+ @Test
+ public void testParcelOperation() throws Exception {
+ SoftApInfo info = new SoftApInfo();
+ info.setFrequency(2412);
+ info.setBandwidth(SoftApInfo.CHANNEL_WIDTH_20MHZ);
+
+ Parcel parcelW = Parcel.obtain();
+ info.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ SoftApInfo fromParcel = SoftApInfo.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(info, fromParcel);
+ assertEquals(info.hashCode(), fromParcel.hashCode());
+ }
+
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index fe30ddd3765a..a7b6765e886a 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -16,10 +16,19 @@
package android.net.wifi;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import android.net.MacAddress;
@@ -33,9 +42,6 @@ import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-
/**
* Unit tests for {@link android.net.wifi.WifiConfiguration}.
*/
@@ -77,7 +83,7 @@ public class WifiConfigurationTest {
// lacking a useful config.equals, check two fields near the end.
assertEquals(cookie, reconfig.getMoTree());
- assertEquals(macBeforeParcel, reconfig.getOrCreateRandomizedMacAddress());
+ assertEquals(macBeforeParcel, reconfig.getRandomizedMacAddress());
assertEquals(config.updateIdentifier, reconfig.updateIdentifier);
assertFalse(reconfig.trusted);
assertTrue(config.fromWifiNetworkSpecifier);
@@ -92,37 +98,6 @@ public class WifiConfigurationTest {
}
@Test
- public void testNetworkSelectionStatusCopy() {
- NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
- networkSelectionStatus.setNotRecommended(true);
-
- NetworkSelectionStatus copy = new NetworkSelectionStatus();
- copy.copy(networkSelectionStatus);
-
- assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
- }
-
- @Test
- public void testNetworkSelectionStatusParcel() {
- NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
- networkSelectionStatus.setNotRecommended(true);
-
- Parcel parcelW = Parcel.obtain();
- networkSelectionStatus.writeToParcel(parcelW);
- byte[] bytes = parcelW.marshall();
- parcelW.recycle();
-
- Parcel parcelR = Parcel.obtain();
- parcelR.unmarshall(bytes, 0, bytes.length);
- parcelR.setDataPosition(0);
-
- NetworkSelectionStatus copy = new NetworkSelectionStatus();
- copy.readFromParcel(parcelR);
-
- assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
- }
-
- @Test
public void testIsOpenNetwork_IsOpen_NullWepKeys() {
WifiConfiguration config = new WifiConfiguration();
config.allowedKeyManagement.clear();
@@ -195,19 +170,6 @@ public class WifiConfigurationTest {
}
@Test
- public void testGetOrCreateRandomizedMacAddress_SavesAndReturnsSameAddress() {
- WifiConfiguration config = new WifiConfiguration();
- MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
- assertEquals(defaultMac, config.getRandomizedMacAddress());
-
- MacAddress firstMacAddress = config.getOrCreateRandomizedMacAddress();
- MacAddress secondMacAddress = config.getOrCreateRandomizedMacAddress();
-
- assertNotEquals(defaultMac, firstMacAddress);
- assertEquals(firstMacAddress, secondMacAddress);
- }
-
- @Test
public void testSetRandomizedMacAddress_ChangesSavedAddress() {
WifiConfiguration config = new WifiConfiguration();
MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
@@ -221,36 +183,6 @@ public class WifiConfigurationTest {
}
@Test
- public void testGetOrCreateRandomizedMacAddress_ReRandomizesInvalidAddress() {
- WifiConfiguration config = new WifiConfiguration();
-
- MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
- MacAddress macAddressZeroes = MacAddress.ALL_ZEROS_ADDRESS;
- MacAddress macAddressMulticast = MacAddress.fromString("03:ff:ff:ff:ff:ff");
- MacAddress macAddressGlobal = MacAddress.fromString("fc:ff:ff:ff:ff:ff");
-
- config.setRandomizedMacAddress(null);
- MacAddress macAfterChange = config.getOrCreateRandomizedMacAddress();
- assertNotEquals(macAfterChange, null);
-
- config.setRandomizedMacAddress(defaultMac);
- macAfterChange = config.getOrCreateRandomizedMacAddress();
- assertNotEquals(macAfterChange, defaultMac);
-
- config.setRandomizedMacAddress(macAddressZeroes);
- macAfterChange = config.getOrCreateRandomizedMacAddress();
- assertNotEquals(macAfterChange, macAddressZeroes);
-
- config.setRandomizedMacAddress(macAddressMulticast);
- macAfterChange = config.getOrCreateRandomizedMacAddress();
- assertNotEquals(macAfterChange, macAddressMulticast);
-
- config.setRandomizedMacAddress(macAddressGlobal);
- macAfterChange = config.getOrCreateRandomizedMacAddress();
- assertNotEquals(macAfterChange, macAddressGlobal);
- }
-
- @Test
public void testSetRandomizedMacAddress_DoesNothingWhenNull() {
WifiConfiguration config = new WifiConfiguration();
MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
@@ -271,33 +203,6 @@ public class WifiConfigurationTest {
}
/**
- * Verifies that the serialization/de-serialization for softap config works.
- */
- @Test
- public void testSoftApConfigBackupAndRestore() throws Exception {
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = "TestAP";
- config.apBand = WifiConfiguration.AP_BAND_5GHZ;
- config.apChannel = 40;
- config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
- config.preSharedKey = "TestPsk";
- config.hiddenSSID = true;
-
- byte[] data = config.getBytesForBackup();
- ByteArrayInputStream bais = new ByteArrayInputStream(data);
- DataInputStream in = new DataInputStream(bais);
- WifiConfiguration restoredConfig = WifiConfiguration.getWifiConfigFromBackup(in);
-
- assertEquals(config.SSID, restoredConfig.SSID);
- assertEquals(config.preSharedKey, restoredConfig.preSharedKey);
- assertEquals(config.getAuthType(), restoredConfig.getAuthType());
- assertEquals(config.apBand, restoredConfig.apBand);
- assertEquals(config.apChannel, restoredConfig.apChannel);
- assertEquals(config.hiddenSSID, restoredConfig.hiddenSSID);
- }
-
-
- /**
* Verifies that getKeyIdForCredentials returns the expected string for Enterprise networks
* @throws Exception
*/
@@ -436,7 +341,23 @@ public class WifiConfigurationTest {
config.allowedKeyManagement.clear();
assertEquals(mSsid + "WEP", config.getSsidAndSecurityTypeString());
+ // set WEP key and give a valid index.
+ config.wepKeys[0] = null;
+ config.wepKeys[2] = "TestWep";
+ config.wepTxKeyIndex = 2;
+ config.allowedKeyManagement.clear();
+ assertEquals(mSsid + "WEP", config.getSsidAndSecurityTypeString());
+
+ // set WEP key but does not give a valid index.
+ config.wepKeys[0] = null;
+ config.wepKeys[2] = "TestWep";
+ config.wepTxKeyIndex = 0;
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.OWE);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getSsidAndSecurityTypeString());
+
config.wepKeys[0] = null;
+ config.wepTxKeyIndex = 0;
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.OWE);
assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getSsidAndSecurityTypeString());
@@ -453,5 +374,167 @@ public class WifiConfigurationTest {
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.NONE);
assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getSsidAndSecurityTypeString());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.WAPI_PSK);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_PSK],
+ config.getSsidAndSecurityTypeString());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.WAPI_CERT);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_CERT],
+ config.getSsidAndSecurityTypeString());
+ }
+
+ /**
+ * Ensure that the {@link NetworkSelectionStatus.DisableReasonInfo}s are populated in
+ * {@link NetworkSelectionStatus#DISABLE_REASON_INFOS} for reason codes from 0 to
+ * {@link NetworkSelectionStatus#NETWORK_SELECTION_DISABLED_MAX} - 1.
+ */
+ @Test
+ public void testNetworkSelectionDisableReasonInfosPopulated() {
+ assertEquals(NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX,
+ NetworkSelectionStatus.DISABLE_REASON_INFOS.size());
+ for (int i = 0; i < NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; i++) {
+ assertNotNull(NetworkSelectionStatus.DISABLE_REASON_INFOS.get(i));
+ }
+ }
+
+ /**
+ * Ensure that {@link NetworkSelectionStatus#getMaxNetworkSelectionDisableReason()} returns
+ * the maximum disable reason.
+ */
+ @Test
+ public void testNetworkSelectionGetMaxNetworkSelectionDisableReason() {
+ int maxReason = Integer.MIN_VALUE;
+ for (int i = 0; i < NetworkSelectionStatus.DISABLE_REASON_INFOS.size(); i++) {
+ int reason = NetworkSelectionStatus.DISABLE_REASON_INFOS.keyAt(i);
+ maxReason = Math.max(maxReason, reason);
+ }
+ assertEquals(maxReason, NetworkSelectionStatus.getMaxNetworkSelectionDisableReason());
+ }
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for SAE security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForSae() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_SAE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
+ assertTrue(config.requirePmf);
+ }
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for OWE security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForOwe() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_OWE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
+ assertTrue(config.requirePmf);
+ }
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for Suite-B security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForSuiteB() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
+ assertTrue(config.allowedGroupManagementCiphers
+ .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
+ assertTrue(config.requirePmf);
+ }
+
+ /**
+ * Test that the NetworkSelectionStatus Builder returns the same values that was set, and that
+ * calling build multiple times returns different instances.
+ */
+ @Test
+ public void testNetworkSelectionStatusBuilder() throws Exception {
+ NetworkSelectionStatus.Builder builder = new NetworkSelectionStatus.Builder()
+ .setNetworkSelectionDisableReason(
+ NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION)
+ .setNetworkSelectionStatus(
+ NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED);
+
+ NetworkSelectionStatus status1 = builder.build();
+
+ assertEquals(NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION,
+ status1.getNetworkSelectionDisableReason());
+ assertEquals(NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED,
+ status1.getNetworkSelectionStatus());
+
+ NetworkSelectionStatus status2 = builder
+ .setNetworkSelectionDisableReason(NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD)
+ .build();
+
+ // different instances
+ assertNotSame(status1, status2);
+
+ // assert that status1 didn't change
+ assertEquals(NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION,
+ status1.getNetworkSelectionDisableReason());
+ assertEquals(NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED,
+ status1.getNetworkSelectionStatus());
+
+ // assert that status2 changed
+ assertEquals(NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD,
+ status2.getNetworkSelectionDisableReason());
+ assertEquals(NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED,
+ status2.getNetworkSelectionStatus());
+ }
+
+ @Test
+ public void testNeedsPreSharedKey() throws Exception {
+ WifiConfiguration configuration = new WifiConfiguration();
+
+ configuration.setSecurityParams(SECURITY_TYPE_PSK);
+ assertTrue(configuration.needsPreSharedKey());
+
+ configuration.setSecurityParams(SECURITY_TYPE_SAE);
+ assertTrue(configuration.needsPreSharedKey());
+
+ configuration.setSecurityParams(SECURITY_TYPE_WAPI_PSK);
+ assertTrue(configuration.needsPreSharedKey());
+
+ configuration.setSecurityParams(SECURITY_TYPE_OPEN);
+ assertFalse(configuration.needsPreSharedKey());
+
+ configuration.setSecurityParams(SECURITY_TYPE_OWE);
+ assertFalse(configuration.needsPreSharedKey());
+
+ configuration.setSecurityParams(SECURITY_TYPE_EAP);
+ assertFalse(configuration.needsPreSharedKey());
+
+ configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+ assertFalse(configuration.needsPreSharedKey());
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index beed6666f28f..62485ecb6f7b 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.net.wifi.WifiEnterpriseConfig.Eap;
import android.net.wifi.WifiEnterpriseConfig.Phase2;
@@ -46,6 +47,7 @@ public class WifiEnterpriseConfigTest {
public static final String KEYSTORE_URI = "keystore://";
public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
public static final String KEYSTORES_URI = "keystores://";
+ private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
private WifiEnterpriseConfig mEnterpriseConfig;
@@ -343,11 +345,13 @@ public class WifiEnterpriseConfigTest {
enterpriseConfig.setPassword("*");
enterpriseConfig.setEapMethod(Eap.TTLS);
enterpriseConfig.setPhase2Method(Phase2.GTC);
+ enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_CERT_STATUS);
mEnterpriseConfig = new WifiEnterpriseConfig();
mEnterpriseConfig.copyFromExternal(enterpriseConfig, "*");
assertEquals("TTLS", getSupplicantEapMethod());
assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
assertNotEquals("*", mEnterpriseConfig.getPassword());
+ assertEquals(enterpriseConfig.getOcsp(), mEnterpriseConfig.getOcsp());
}
/** Verfies that parceling a WifiEnterpriseConfig preseves method information. */
@@ -487,4 +491,87 @@ public class WifiEnterpriseConfigTest {
assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
assertTrue(mEnterpriseConfig.isAppInstalledCaCert());
}
+
+ /** Verifies that OCSP value is set correctly. */
+ @Test
+ public void testOcspSetGet() throws Exception {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+
+ enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_NONE);
+ assertEquals(WifiEnterpriseConfig.OCSP_NONE, enterpriseConfig.getOcsp());
+
+ enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_CERT_STATUS);
+ assertEquals(WifiEnterpriseConfig.OCSP_REQUIRE_CERT_STATUS, enterpriseConfig.getOcsp());
+
+ enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_REQUEST_CERT_STATUS);
+ assertEquals(WifiEnterpriseConfig.OCSP_REQUEST_CERT_STATUS, enterpriseConfig.getOcsp());
+
+ enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS);
+ assertEquals(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS,
+ enterpriseConfig.getOcsp());
+ }
+
+ /** Verifies that an exception is thrown when invalid OCSP is set. */
+ @Test
+ public void testInvalidOcspValue() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ try {
+ enterpriseConfig.setOcsp(-1);
+ fail("Should raise an IllegalArgumentException here.");
+ } catch (IllegalArgumentException e) {
+ // expected exception.
+ }
+ }
+
+ /** Verifies that the EAP inner method is reset when we switch to Unauth-TLS */
+ @Test
+ public void eapPhase2MethodForUnauthTls() {
+ // Initially select an EAP method that supports an phase2.
+ mEnterpriseConfig.setEapMethod(Eap.PEAP);
+ mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+ assertEquals("PEAP", getSupplicantEapMethod());
+ assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+ // Change the EAP method to another type which supports a phase2.
+ mEnterpriseConfig.setEapMethod(Eap.TTLS);
+ assertEquals("TTLS", getSupplicantEapMethod());
+ assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+ // Change the EAP method to Unauth-TLS which does not support a phase2.
+ mEnterpriseConfig.setEapMethod(Eap.UNAUTH_TLS);
+ assertEquals(null, getSupplicantPhase2Method());
+ }
+
+ @Test
+ public void testIsEnterpriseConfigSecure() {
+ WifiEnterpriseConfig baseConfig = new WifiEnterpriseConfig();
+ baseConfig.setEapMethod(Eap.PEAP);
+ baseConfig.setPhase2Method(Phase2.MSCHAPV2);
+ assertTrue(baseConfig.isInsecure());
+
+ WifiEnterpriseConfig noMatchConfig = new WifiEnterpriseConfig(baseConfig);
+ noMatchConfig.setCaCertificate(FakeKeys.CA_CERT0);
+ // Missing match is insecure.
+ assertTrue(noMatchConfig.isInsecure());
+
+ WifiEnterpriseConfig noCaConfig = new WifiEnterpriseConfig(baseConfig);
+ noCaConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+ // Missing CA certificate is insecure.
+ assertTrue(noCaConfig.isInsecure());
+
+ WifiEnterpriseConfig secureConfig = new WifiEnterpriseConfig();
+ secureConfig.setEapMethod(Eap.PEAP);
+ secureConfig.setPhase2Method(Phase2.MSCHAPV2);
+ secureConfig.setCaCertificate(FakeKeys.CA_CERT0);
+ secureConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+ assertFalse(secureConfig.isInsecure());
+
+ WifiEnterpriseConfig secureConfigWithCaAlias = new WifiEnterpriseConfig();
+ secureConfigWithCaAlias.setEapMethod(Eap.PEAP);
+ secureConfigWithCaAlias.setPhase2Method(Phase2.MSCHAPV2);
+ secureConfigWithCaAlias.setCaCertificateAliases(new String[]{"alias1", "alisa2"});
+ secureConfigWithCaAlias.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+ assertFalse(secureConfigWithCaAlias.isInsecure());
+ }
+
}
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index 0ce5d66cf4f7..311bbc41b8fe 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -18,6 +18,7 @@ package android.net.wifi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
@@ -26,6 +27,8 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
+import java.nio.charset.StandardCharsets;
+
/**
* Unit tests for {@link android.net.wifi.WifiInfo}.
*/
@@ -38,6 +41,14 @@ public class WifiInfoTest {
private static final String TEST_PACKAGE_NAME = "com.test.example";
private static final String TEST_FQDN = "test.com";
private static final String TEST_PROVIDER_NAME = "test";
+ private static final int TEST_WIFI_STANDARD = ScanResult.WIFI_STANDARD_11AC;
+ private static final int TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS = 866;
+ private static final int TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS = 1200;
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_BSSID = "12:12:12:12:12:12";
+ private static final int TEST_RSSI = -60;
+ private static final int TEST_NETWORK_ID = 5;
+ private static final int TEST_NETWORK_ID2 = 6;
/**
* Verify parcel write/read with WifiInfo.
@@ -53,7 +64,10 @@ public class WifiInfoTest {
writeWifiInfo.setOsuAp(true);
writeWifiInfo.setFQDN(TEST_FQDN);
writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
- writeWifiInfo.setNetworkSuggestionOrSpecifierPackageName(TEST_PACKAGE_NAME);
+ writeWifiInfo.setRequestingPackageName(TEST_PACKAGE_NAME);
+ writeWifiInfo.setWifiStandard(TEST_WIFI_STANDARD);
+ writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS);
+ writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS);
Parcel parcel = Parcel.obtain();
writeWifiInfo.writeToParcel(parcel, 0);
@@ -69,8 +83,69 @@ public class WifiInfoTest {
assertTrue(readWifiInfo.isTrusted());
assertTrue(readWifiInfo.isOsuAp());
assertTrue(readWifiInfo.isPasspointAp());
- assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getNetworkSuggestionOrSpecifierPackageName());
+ assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName());
assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn());
assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName());
+ assertEquals(TEST_WIFI_STANDARD, readWifiInfo.getWifiStandard());
+ assertEquals(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS,
+ readWifiInfo.getMaxSupportedTxLinkSpeedMbps());
+ assertEquals(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS,
+ readWifiInfo.getMaxSupportedRxLinkSpeedMbps());
+ }
+
+ /**
+ * Verify values after reset()
+ */
+ @Test
+ public void testWifiInfoResetValue() throws Exception {
+ WifiInfo wifiInfo = new WifiInfo();
+ wifiInfo.reset();
+ assertEquals(WifiInfo.LINK_SPEED_UNKNOWN, wifiInfo.getMaxSupportedTxLinkSpeedMbps());
+ assertEquals(WifiInfo.LINK_SPEED_UNKNOWN, wifiInfo.getMaxSupportedRxLinkSpeedMbps());
+ assertEquals(WifiInfo.LINK_SPEED_UNKNOWN, wifiInfo.getTxLinkSpeedMbps());
+ assertEquals(WifiInfo.LINK_SPEED_UNKNOWN, wifiInfo.getRxLinkSpeedMbps());
+ assertEquals(WifiInfo.INVALID_RSSI, wifiInfo.getRssi());
+ assertEquals(WifiManager.UNKNOWN_SSID, wifiInfo.getSSID());
+ assertEquals(null, wifiInfo.getBSSID());
+ assertEquals(-1, wifiInfo.getNetworkId());
+ }
+
+ /**
+ * Test that the WifiInfo Builder returns the same values that was set, and that
+ * calling build multiple times returns different instances.
+ */
+ @Test
+ public void testWifiInfoBuilder() throws Exception {
+ WifiInfo.Builder builder = new WifiInfo.Builder()
+ .setSsid(TEST_SSID.getBytes(StandardCharsets.UTF_8))
+ .setBssid(TEST_BSSID)
+ .setRssi(TEST_RSSI)
+ .setNetworkId(TEST_NETWORK_ID);
+
+ WifiInfo info1 = builder.build();
+
+ assertEquals("\"" + TEST_SSID + "\"", info1.getSSID());
+ assertEquals(TEST_BSSID, info1.getBSSID());
+ assertEquals(TEST_RSSI, info1.getRssi());
+ assertEquals(TEST_NETWORK_ID, info1.getNetworkId());
+
+ WifiInfo info2 = builder
+ .setNetworkId(TEST_NETWORK_ID2)
+ .build();
+
+ // different instances
+ assertNotSame(info1, info2);
+
+ // assert that info1 didn't change
+ assertEquals("\"" + TEST_SSID + "\"", info1.getSSID());
+ assertEquals(TEST_BSSID, info1.getBSSID());
+ assertEquals(TEST_RSSI, info1.getRssi());
+ assertEquals(TEST_NETWORK_ID, info1.getNetworkId());
+
+ // assert that info2 changed
+ assertEquals("\"" + TEST_SSID + "\"", info2.getSSID());
+ assertEquals(TEST_BSSID, info2.getBSSID());
+ assertEquals(TEST_RSSI, info2.getRssi());
+ assertEquals(TEST_NETWORK_ID2, info2.getNetworkId());
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index b130c1737c62..1398bfeef031 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -16,18 +16,31 @@
package android.net.wifi;
-import static android.net.wifi.WifiManager.HOTSPOT_FAILED;
-import static android.net.wifi.WifiManager.HOTSPOT_STARTED;
-import static android.net.wifi.WifiManager.HOTSPOT_STOPPED;
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED;
+import static android.net.wifi.WifiManager.ActionListener;
+import static android.net.wifi.WifiManager.BUSY;
+import static android.net.wifi.WifiManager.ERROR;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.REQUEST_REGISTERED;
+import static android.net.wifi.WifiManager.NOT_AUTHORIZED;
+import static android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener;
import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL;
+import static android.net.wifi.WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS;
+import static android.net.wifi.WifiManager.STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_P2P;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_PASSPOINT;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_SCANNER;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B;
+import static android.net.wifi.WifiManager.WpsCallback;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -37,6 +50,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyList;
@@ -52,9 +66,11 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.net.DhcpInfo;
+import android.net.MacAddress;
import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
import android.net.wifi.WifiManager.LocalOnlyHotspotObserver;
import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
@@ -62,15 +78,20 @@ import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription;
import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
import android.net.wifi.WifiManager.OnWifiUsabilityStatsListener;
+import android.net.wifi.WifiManager.ScanResultsCallback;
import android.net.wifi.WifiManager.SoftApCallback;
+import android.net.wifi.WifiManager.SuggestionConnectionStatusListener;
import android.net.wifi.WifiManager.TrafficStateCallback;
+import android.net.wifi.WifiManager.WifiConnectedNetworkScorer;
+import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.connectivity.WifiActivityEnergyInfo;
import android.os.test.TestLooper;
+import android.util.SparseArray;
import androidx.test.filters.SmallTest;
@@ -85,6 +106,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -98,25 +120,78 @@ public class WifiManagerTest {
private static final int TEST_UID = 14553;
private static final int TEST_NETWORK_ID = 143;
private static final String TEST_PACKAGE_NAME = "TestPackage";
+ private static final String TEST_FEATURE_ID = "TestFeature";
private static final String TEST_COUNTRY_CODE = "US";
private static final String[] TEST_MAC_ADDRESSES = {"da:a1:19:0:0:0"};
+ private static final int TEST_AP_FREQUENCY = 2412;
+ private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ;
@Mock Context mContext;
@Mock android.net.wifi.IWifiManager mWifiService;
@Mock ApplicationInfo mApplicationInfo;
@Mock WifiConfiguration mApConfig;
- @Mock IBinder mAppBinder;
@Mock SoftApCallback mSoftApCallback;
@Mock TrafficStateCallback mTrafficStateCallback;
@Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback;
@Mock OnWifiUsabilityStatsListener mOnWifiUsabilityStatsListener;
+ @Mock OnWifiActivityEnergyInfoListener mOnWifiActivityEnergyInfoListener;
+ @Mock SuggestionConnectionStatusListener mListener;
+ @Mock Runnable mRunnable;
+ @Mock Executor mExecutor;
+ @Mock Executor mAnotherExecutor;
+ @Mock ActivityManager mActivityManager;
+ @Mock WifiConnectedNetworkScorer mWifiConnectedNetworkScorer;
- private Executor mExecutor;
private Handler mHandler;
private TestLooper mLooper;
private WifiManager mWifiManager;
- private Messenger mWifiServiceMessenger;
- final ArgumentCaptor<Messenger> mMessengerCaptor = ArgumentCaptor.forClass(Messenger.class);
+ private WifiNetworkSuggestion mWifiNetworkSuggestion;
+ private ScanResultsCallback mScanResultsCallback;
+ private WifiActivityEnergyInfo mWifiActivityEnergyInfo;
+
+ /**
+ * Util function to check public field which used for softap in WifiConfiguration
+ * same as the value in SoftApConfiguration.
+ *
+ */
+ private boolean compareWifiAndSoftApConfiguration(
+ SoftApConfiguration softApConfig, WifiConfiguration wifiConfig) {
+ if (!Objects.equals(wifiConfig.SSID, softApConfig.getSsid())) {
+ return false;
+ }
+ if (!Objects.equals(wifiConfig.BSSID, softApConfig.getBssid())) {
+ return false;
+ }
+ if (!Objects.equals(wifiConfig.preSharedKey, softApConfig.getPassphrase())) {
+ return false;
+ }
+
+ if (wifiConfig.hiddenSSID != softApConfig.isHiddenSsid()) {
+ return false;
+ }
+ switch (softApConfig.getSecurityType()) {
+ case SoftApConfiguration.SECURITY_TYPE_OPEN:
+ if (wifiConfig.getAuthType() != WifiConfiguration.KeyMgmt.NONE) {
+ return false;
+ }
+ break;
+ case SoftApConfiguration.SECURITY_TYPE_WPA2_PSK:
+ if (wifiConfig.getAuthType() != WifiConfiguration.KeyMgmt.WPA2_PSK) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ private SoftApConfiguration generatorTestSoftApConfig() {
+ return new SoftApConfiguration.Builder()
+ .setSsid("TestSSID")
+ .setPassphrase("TestPassphrase", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .build();
+ }
@Before
public void setUp() throws Exception {
@@ -126,10 +201,16 @@ public class WifiManagerTest {
mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
when(mContext.getOpPackageName()).thenReturn(TEST_PACKAGE_NAME);
-
- mWifiServiceMessenger = new Messenger(mHandler);
mWifiManager = new WifiManager(mContext, mWifiService, mLooper.getLooper());
verify(mWifiService).getVerboseLoggingLevel();
+ mWifiNetworkSuggestion = new WifiNetworkSuggestion();
+ mScanResultsCallback = new ScanResultsCallback() {
+ @Override
+ public void onScanResultsAvailable() {
+ mRunnable.run();
+ }
+ };
+ mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
}
/**
@@ -171,19 +252,50 @@ public class WifiManagerTest {
}
/**
+ * Check the call to startSoftAp calls WifiService to startSoftAp with the provided
+ * WifiConfiguration. Verify that the return value is propagated to the caller.
+ */
+ @Test
+ public void testStartTetheredHotspotCallsServiceWithSoftApConfig() throws Exception {
+ SoftApConfiguration softApConfig = generatorTestSoftApConfig();
+ when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(true);
+ assertTrue(mWifiManager.startTetheredHotspot(softApConfig));
+
+ when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(false);
+ assertFalse(mWifiManager.startTetheredHotspot(softApConfig));
+ }
+
+ /**
+ * Check the call to startSoftAp calls WifiService to startSoftAp with a null config. Verify
+ * that the return value is propagated to the caller.
+ */
+ @Test
+ public void testStartTetheredHotspotCallsServiceWithNullConfig() throws Exception {
+ when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(true);
+ assertTrue(mWifiManager.startTetheredHotspot(null));
+
+ when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(false);
+ assertFalse(mWifiManager.startTetheredHotspot(null));
+ }
+
+ /**
* Test creation of a LocalOnlyHotspotReservation and verify that close properly calls
* WifiService.stopLocalOnlyHotspot.
*/
@Test
public void testCreationAndCloseOfLocalOnlyHotspotReservation() throws Exception {
+ SoftApConfiguration softApConfig = generatorTestSoftApConfig();
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(REQUEST_REGISTERED);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
- callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(mApConfig));
+ callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(softApConfig));
+
+ assertEquals(softApConfig, callback.mRes.getSoftApConfiguration());
+ WifiConfiguration wifiConfig = callback.mRes.getWifiConfiguration();
+ assertTrue(compareWifiAndSoftApConfiguration(softApConfig, wifiConfig));
- assertEquals(mApConfig, callback.mRes.getWifiConfiguration());
callback.mRes.close();
verify(mWifiService).stopLocalOnlyHotspot();
}
@@ -194,15 +306,18 @@ public class WifiManagerTest {
@Test
public void testLocalOnlyHotspotReservationCallsStopProperlyInTryWithResources()
throws Exception {
+ SoftApConfiguration softApConfig = generatorTestSoftApConfig();
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(REQUEST_REGISTERED);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
- callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(mApConfig));
+ callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(softApConfig));
try (WifiManager.LocalOnlyHotspotReservation res = callback.mRes) {
- assertEquals(mApConfig, res.getWifiConfiguration());
+ assertEquals(softApConfig, res.getSoftApConfiguration());
+ WifiConfiguration wifiConfig = callback.mRes.getWifiConfiguration();
+ assertTrue(compareWifiAndSoftApConfiguration(softApConfig, wifiConfig));
}
verify(mWifiService).stopLocalOnlyHotspot();
@@ -252,6 +367,7 @@ public class WifiManagerTest {
*/
@Test
public void testLocalOnlyHotspotCallback() {
+ SoftApConfiguration softApConfig = generatorTestSoftApConfig();
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
assertFalse(callback.mOnStartedCalled);
assertFalse(callback.mOnStoppedCalled);
@@ -260,7 +376,7 @@ public class WifiManagerTest {
// test onStarted
WifiManager.LocalOnlyHotspotReservation res =
- mWifiManager.new LocalOnlyHotspotReservation(mApConfig);
+ mWifiManager.new LocalOnlyHotspotReservation(softApConfig);
callback.onStarted(res);
assertEquals(res, callback.mRes);
assertTrue(callback.mOnStartedCalled);
@@ -286,7 +402,7 @@ public class WifiManagerTest {
public boolean mOnRegistered = false;
public boolean mOnStartedCalled = false;
public boolean mOnStoppedCalled = false;
- public WifiConfiguration mConfig = null;
+ public SoftApConfiguration mConfig = null;
public LocalOnlyHotspotSubscription mSub = null;
public long mCallingThreadId = -1;
@@ -298,7 +414,7 @@ public class WifiManagerTest {
}
@Override
- public void onStarted(WifiConfiguration config) {
+ public void onStarted(SoftApConfiguration config) {
mOnStartedCalled = true;
mConfig = config;
mCallingThreadId = Thread.currentThread().getId();
@@ -317,6 +433,7 @@ public class WifiManagerTest {
@Test
public void testLocalOnlyHotspotObserver() {
TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
+ SoftApConfiguration softApConfig = generatorTestSoftApConfig();
assertFalse(observer.mOnRegistered);
assertFalse(observer.mOnStartedCalled);
assertFalse(observer.mOnStoppedCalled);
@@ -332,18 +449,18 @@ public class WifiManagerTest {
assertEquals(null, observer.mConfig);
assertEquals(sub, observer.mSub);
- observer.onStarted(mApConfig);
+ observer.onStarted(softApConfig);
assertTrue(observer.mOnRegistered);
assertTrue(observer.mOnStartedCalled);
assertFalse(observer.mOnStoppedCalled);
- assertEquals(mApConfig, observer.mConfig);
+ assertEquals(softApConfig, observer.mConfig);
assertEquals(sub, observer.mSub);
observer.onStopped();
assertTrue(observer.mOnRegistered);
assertTrue(observer.mOnStartedCalled);
assertTrue(observer.mOnStoppedCalled);
- assertEquals(mApConfig, observer.mConfig);
+ assertEquals(softApConfig, observer.mConfig);
assertEquals(sub, observer.mSub);
}
@@ -355,8 +472,8 @@ public class WifiManagerTest {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
- verify(mWifiService)
- .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString());
+ verify(mWifiService).startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
+ anyString(), nullable(String.class), eq(null));
}
/**
@@ -366,8 +483,9 @@ public class WifiManagerTest {
@Test(expected = SecurityException.class)
public void testStartLocalOnlyHotspotThrowsSecurityException() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- doThrow(new SecurityException()).when(mWifiService)
- .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString());
+ doThrow(new SecurityException()).when(mWifiService).startLocalOnlyHotspot(
+ any(ILocalOnlyHotspotCallback.class), anyString(), nullable(String.class),
+ eq(null));
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
}
@@ -378,8 +496,9 @@ public class WifiManagerTest {
@Test(expected = IllegalStateException.class)
public void testStartLocalOnlyHotspotThrowsIllegalStateException() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- doThrow(new IllegalStateException()).when(mWifiService)
- .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString());
+ doThrow(new IllegalStateException()).when(mWifiService).startLocalOnlyHotspot(
+ any(ILocalOnlyHotspotCallback.class), anyString(), nullable(String.class),
+ eq(null));
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
}
@@ -389,12 +508,13 @@ public class WifiManagerTest {
@Test
public void testCorrectLooperIsUsedForHandler() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mLooper.dispatchAll();
assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
verify(mContext, never()).getMainLooper();
+ verify(mContext, never()).getMainExecutor();
}
/**
@@ -405,15 +525,15 @@ public class WifiManagerTest {
public void testMainLooperIsUsedWhenHandlerNotProvided() throws Exception {
// record thread from looper.getThread and check ids.
TestLooper altLooper = new TestLooper();
- when(mContext.getMainLooper()).thenReturn(altLooper.getLooper());
+ when(mContext.getMainExecutor()).thenReturn(altLooper.getNewExecutor());
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
mWifiManager.startLocalOnlyHotspot(callback, null);
altLooper.dispatchAll();
assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
assertEquals(altLooper.getLooper().getThread().getId(), callback.mCallingThreadId);
- verify(mContext).getMainLooper();
+ verify(mContext).getMainExecutor();
}
/**
@@ -422,25 +542,58 @@ public class WifiManagerTest {
*/
@Test
public void testOnStartedIsCalledWithReservation() throws Exception {
+ SoftApConfiguration softApConfig = generatorTestSoftApConfig();
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
TestLooper callbackLooper = new TestLooper();
Handler callbackHandler = new Handler(callbackLooper.getLooper());
- when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(),
- any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED);
+ ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+ ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+ when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
callbackLooper.dispatchAll();
mLooper.dispatchAll();
assertFalse(callback.mOnStartedCalled);
assertEquals(null, callback.mRes);
// now trigger the callback
- Message msg = new Message();
- msg.what = HOTSPOT_STARTED;
- msg.obj = mApConfig;
- mMessengerCaptor.getValue().send(msg);
+ internalCallback.getValue().onHotspotStarted(softApConfig);
mLooper.dispatchAll();
callbackLooper.dispatchAll();
assertTrue(callback.mOnStartedCalled);
- assertEquals(mApConfig, callback.mRes.getWifiConfiguration());
+ assertEquals(softApConfig, callback.mRes.getSoftApConfiguration());
+ WifiConfiguration wifiConfig = callback.mRes.getWifiConfiguration();
+ assertTrue(compareWifiAndSoftApConfiguration(softApConfig, wifiConfig));
+ }
+
+ /**
+ * Verify the LOHS onStarted callback is triggered when WifiManager receives a HOTSPOT_STARTED
+ * message from WifiServiceImpl when softap enabled with SAE security type.
+ */
+ @Test
+ public void testOnStartedIsCalledWithReservationAndSaeSoftApConfig() throws Exception {
+ SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
+ .setSsid("TestSSID")
+ .setPassphrase("TestPassphrase", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)
+ .build();
+ TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
+ TestLooper callbackLooper = new TestLooper();
+ Handler callbackHandler = new Handler(callbackLooper.getLooper());
+ ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+ ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+ when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
+ mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
+ callbackLooper.dispatchAll();
+ mLooper.dispatchAll();
+ assertFalse(callback.mOnStartedCalled);
+ assertEquals(null, callback.mRes);
+ // now trigger the callback
+ internalCallback.getValue().onHotspotStarted(softApConfig);
+ mLooper.dispatchAll();
+ callbackLooper.dispatchAll();
+ assertTrue(callback.mOnStartedCalled);
+ assertEquals(softApConfig, callback.mRes.getSoftApConfiguration());
+ assertEquals(null, callback.mRes.getWifiConfiguration());
}
/**
@@ -452,17 +605,17 @@ public class WifiManagerTest {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
TestLooper callbackLooper = new TestLooper();
Handler callbackHandler = new Handler(callbackLooper.getLooper());
- when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(),
- any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED);
+ ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+ ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+ when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
callbackLooper.dispatchAll();
mLooper.dispatchAll();
assertFalse(callback.mOnStartedCalled);
assertEquals(null, callback.mRes);
// now trigger the callback
- Message msg = new Message();
- msg.what = HOTSPOT_STARTED;
- mMessengerCaptor.getValue().send(msg);
+ internalCallback.getValue().onHotspotStarted(null);
mLooper.dispatchAll();
callbackLooper.dispatchAll();
assertFalse(callback.mOnStartedCalled);
@@ -477,16 +630,16 @@ public class WifiManagerTest {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
TestLooper callbackLooper = new TestLooper();
Handler callbackHandler = new Handler(callbackLooper.getLooper());
- when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(),
- any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED);
+ ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+ ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+ when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
callbackLooper.dispatchAll();
mLooper.dispatchAll();
assertFalse(callback.mOnStoppedCalled);
// now trigger the callback
- Message msg = new Message();
- msg.what = HOTSPOT_STOPPED;
- mMessengerCaptor.getValue().send(msg);
+ internalCallback.getValue().onHotspotStopped();
mLooper.dispatchAll();
callbackLooper.dispatchAll();
assertTrue(callback.mOnStoppedCalled);
@@ -500,17 +653,16 @@ public class WifiManagerTest {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
TestLooper callbackLooper = new TestLooper();
Handler callbackHandler = new Handler(callbackLooper.getLooper());
- when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(),
- any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED);
+ ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+ ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+ when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
callbackLooper.dispatchAll();
mLooper.dispatchAll();
assertEquals(ERROR_NOT_SET, callback.mFailureReason);
// now trigger the callback
- Message msg = new Message();
- msg.what = HOTSPOT_FAILED;
- msg.arg1 = ERROR_NO_CHANNEL;
- mMessengerCaptor.getValue().send(msg);
+ internalCallback.getValue().onHotspotFailed(ERROR_NO_CHANNEL);
mLooper.dispatchAll();
callbackLooper.dispatchAll();
assertEquals(ERROR_NO_CHANNEL, callback.mFailureReason);
@@ -522,8 +674,8 @@ public class WifiManagerTest {
@Test
public void testLocalOnlyHotspotCallbackFullOnIncompatibleMode() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mLooper.dispatchAll();
assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -538,8 +690,8 @@ public class WifiManagerTest {
@Test
public void testLocalOnlyHotspotCallbackFullOnTetheringDisallowed() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(ERROR_TETHERING_DISALLOWED);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(ERROR_TETHERING_DISALLOWED);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mLooper.dispatchAll();
assertEquals(ERROR_TETHERING_DISALLOWED, callback.mFailureReason);
@@ -555,8 +707,9 @@ public class WifiManagerTest {
@Test(expected = SecurityException.class)
public void testLocalOnlyHotspotCallbackFullOnSecurityException() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- doThrow(new SecurityException()).when(mWifiService)
- .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString());
+ doThrow(new SecurityException()).when(mWifiService).startLocalOnlyHotspot(
+ any(ILocalOnlyHotspotCallback.class), anyString(), nullable(String.class),
+ eq(null));
try {
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
} catch (SecurityException e) {
@@ -576,8 +729,8 @@ public class WifiManagerTest {
@Test
public void testLocalOnlyHotspotCallbackFullOnNoChannelError() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(REQUEST_REGISTERED);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mLooper.dispatchAll();
//assertEquals(ERROR_NO_CHANNEL, callback.mFailureReason);
@@ -592,8 +745,8 @@ public class WifiManagerTest {
@Test
public void testCancelLocalOnlyHotspotRequestCallsStopOnWifiService() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(REQUEST_REGISTERED);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mWifiManager.cancelLocalOnlyHotspotRequest();
verify(mWifiService).stopLocalOnlyHotspot();
@@ -614,8 +767,8 @@ public class WifiManagerTest {
@Test
public void testCallbackAfterLocalOnlyHotspotWasCancelled() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(REQUEST_REGISTERED);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mWifiManager.cancelLocalOnlyHotspotRequest();
verify(mWifiService).stopLocalOnlyHotspot();
@@ -633,8 +786,8 @@ public class WifiManagerTest {
@Test
public void testCancelAfterLocalOnlyHotspotCallbackTriggered() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
- when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
- anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
+ when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+ nullable(String.class), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mLooper.dispatchAll();
assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -645,6 +798,17 @@ public class WifiManagerTest {
verify(mWifiService, never()).stopLocalOnlyHotspot();
}
+ @Test
+ public void testStartLocalOnlyHotspotForwardsCustomConfig() throws Exception {
+ SoftApConfiguration customConfig = new SoftApConfiguration.Builder()
+ .setSsid("customSsid")
+ .build();
+ TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
+ mWifiManager.startLocalOnlyHotspot(customConfig, mExecutor, callback);
+ verify(mWifiService).startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
+ anyString(), nullable(String.class), eq(customConfig));
+ }
+
/**
* Verify the watchLocalOnlyHotspot call goes to WifiServiceImpl.
*/
@@ -653,7 +817,7 @@ public class WifiManagerTest {
TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
mWifiManager.watchLocalOnlyHotspot(observer, mHandler);
- verify(mWifiService).startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class));
+ verify(mWifiService).startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class));
}
/**
@@ -664,7 +828,7 @@ public class WifiManagerTest {
public void testStartWatchLocalOnlyHotspotThrowsSecurityException() throws Exception {
TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
doThrow(new SecurityException()).when(mWifiService)
- .startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class));
+ .startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class));
mWifiManager.watchLocalOnlyHotspot(observer, mHandler);
}
@@ -676,7 +840,7 @@ public class WifiManagerTest {
public void testStartWatchLocalOnlyHotspotThrowsIllegalStateException() throws Exception {
TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
doThrow(new IllegalStateException()).when(mWifiService)
- .startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class));
+ .startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class));
mWifiManager.watchLocalOnlyHotspot(observer, mHandler);
}
@@ -773,11 +937,74 @@ public class WifiManagerTest {
verify(mSoftApCallback).onConnectedClientsChanged(testClients);
}
+
+ /*
+ * Verify client-provided callback is being called through callback proxy
+ */
+ @Test
+ public void softApCallbackProxyCallsOnSoftApInfoChanged() throws Exception {
+ SoftApInfo testSoftApInfo = new SoftApInfo();
+ testSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
+ testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
+ ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
+ verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
+ anyInt());
+
+ callbackCaptor.getValue().onInfoChanged(testSoftApInfo);
+ mLooper.dispatchAll();
+ verify(mSoftApCallback).onInfoChanged(testSoftApInfo);
+ }
+
+
+ /*
+ * Verify client-provided callback is being called through callback proxy
+ */
+ @Test
+ public void softApCallbackProxyCallsOnCapabilityChanged() throws Exception {
+ SoftApCapability testSoftApCapability = new SoftApCapability(0);
+ testSoftApCapability.setMaxSupportedClients(10);
+ ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
+ verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
+ anyInt());
+
+ callbackCaptor.getValue().onCapabilityChanged(testSoftApCapability);
+ mLooper.dispatchAll();
+ verify(mSoftApCallback).onCapabilityChanged(testSoftApCapability);
+ }
+
+ /*
+ * Verify client-provided callback is being called through callback proxy
+ */
+ @Test
+ public void softApCallbackProxyCallsOnBlockedClientConnecting() throws Exception {
+ WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77"));
+ ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
+ verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
+ anyInt());
+
+ callbackCaptor.getValue().onBlockedClientConnecting(testWifiClient,
+ WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS);
+ mLooper.dispatchAll();
+ verify(mSoftApCallback).onBlockedClientConnecting(testWifiClient,
+ WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS);
+ }
+
/*
* Verify client-provided callback is being called through callback proxy on multiple events
*/
@Test
public void softApCallbackProxyCallsOnMultipleUpdates() throws Exception {
+ SoftApInfo testSoftApInfo = new SoftApInfo();
+ testSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
+ testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
+ SoftApCapability testSoftApCapability = new SoftApCapability(0);
+ testSoftApCapability.setMaxSupportedClients(10);
ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
@@ -787,12 +1014,17 @@ public class WifiManagerTest {
final List<WifiClient> testClients = new ArrayList();
callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLING, 0);
callbackCaptor.getValue().onConnectedClientsChanged(testClients);
+ callbackCaptor.getValue().onInfoChanged(testSoftApInfo);
callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
+ callbackCaptor.getValue().onCapabilityChanged(testSoftApCapability);
+
mLooper.dispatchAll();
verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLING, 0);
verify(mSoftApCallback).onConnectedClientsChanged(testClients);
+ verify(mSoftApCallback).onInfoChanged(testSoftApInfo);
verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
+ verify(mSoftApCallback).onCapabilityChanged(testSoftApCapability);
}
/*
@@ -823,6 +1055,7 @@ public class WifiManagerTest {
verify(mWifiService).registerSoftApCallback(any(IBinder.class),
any(ISoftApCallback.Stub.class), anyInt());
verify(mContext, never()).getMainLooper();
+ verify(mContext, never()).getMainExecutor();
}
/**
@@ -835,6 +1068,7 @@ public class WifiManagerTest {
mLooper.dispatchAll();
assertTrue(observer.mOnRegistered);
verify(mContext, never()).getMainLooper();
+ verify(mContext, never()).getMainExecutor();
}
/**
@@ -845,13 +1079,13 @@ public class WifiManagerTest {
public void testMainLooperIsUsedWhenHandlerNotProvidedForObserver() throws Exception {
// record thread from looper.getThread and check ids.
TestLooper altLooper = new TestLooper();
- when(mContext.getMainLooper()).thenReturn(altLooper.getLooper());
+ when(mContext.getMainExecutor()).thenReturn(altLooper.getNewExecutor());
TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
mWifiManager.watchLocalOnlyHotspot(observer, null);
altLooper.dispatchAll();
assertTrue(observer.mOnRegistered);
assertEquals(altLooper.getLooper().getThread().getId(), observer.mCallingThreadId);
- verify(mContext).getMainLooper();
+ verify(mContext).getMainExecutor();
}
/**
@@ -866,8 +1100,7 @@ public class WifiManagerTest {
assertFalse(observer.mOnRegistered);
assertEquals(null, observer.mSub);
mWifiManager.watchLocalOnlyHotspot(observer, observerHandler);
- verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(),
- any(IBinder.class));
+ verify(mWifiService).startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class));
// now trigger the callback
observerLooper.dispatchAll();
mLooper.dispatchAll();
@@ -881,24 +1114,23 @@ public class WifiManagerTest {
*/
@Test
public void testObserverOnStartedIsCalledWithWifiConfig() throws Exception {
+ SoftApConfiguration softApConfig = generatorTestSoftApConfig();
TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
TestLooper observerLooper = new TestLooper();
Handler observerHandler = new Handler(observerLooper.getLooper());
mWifiManager.watchLocalOnlyHotspot(observer, observerHandler);
- verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(),
- any(IBinder.class));
+ ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+ ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+ verify(mWifiService).startWatchLocalOnlyHotspot(internalCallback.capture());
observerLooper.dispatchAll();
mLooper.dispatchAll();
assertFalse(observer.mOnStartedCalled);
// now trigger the callback
- Message msg = new Message();
- msg.what = HOTSPOT_STARTED;
- msg.obj = mApConfig;
- mMessengerCaptor.getValue().send(msg);
+ internalCallback.getValue().onHotspotStarted(softApConfig);
mLooper.dispatchAll();
observerLooper.dispatchAll();
assertTrue(observer.mOnStartedCalled);
- assertEquals(mApConfig, observer.mConfig);
+ assertEquals(softApConfig, observer.mConfig);
}
/**
@@ -911,15 +1143,14 @@ public class WifiManagerTest {
TestLooper observerLooper = new TestLooper();
Handler observerHandler = new Handler(observerLooper.getLooper());
mWifiManager.watchLocalOnlyHotspot(observer, observerHandler);
- verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(),
- any(IBinder.class));
+ ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+ ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+ verify(mWifiService).startWatchLocalOnlyHotspot(internalCallback.capture());
observerLooper.dispatchAll();
mLooper.dispatchAll();
assertFalse(observer.mOnStartedCalled);
// now trigger the callback
- Message msg = new Message();
- msg.what = HOTSPOT_STARTED;
- mMessengerCaptor.getValue().send(msg);
+ internalCallback.getValue().onHotspotStarted(null);
mLooper.dispatchAll();
observerLooper.dispatchAll();
assertFalse(observer.mOnStartedCalled);
@@ -937,15 +1168,14 @@ public class WifiManagerTest {
TestLooper observerLooper = new TestLooper();
Handler observerHandler = new Handler(observerLooper.getLooper());
mWifiManager.watchLocalOnlyHotspot(observer, observerHandler);
- verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(),
- any(IBinder.class));
+ ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+ ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+ verify(mWifiService).startWatchLocalOnlyHotspot(internalCallback.capture());
observerLooper.dispatchAll();
mLooper.dispatchAll();
assertFalse(observer.mOnStoppedCalled);
// now trigger the callback
- Message msg = new Message();
- msg.what = HOTSPOT_STOPPED;
- mMessengerCaptor.getValue().send(msg);
+ internalCallback.getValue().onHotspotStopped();
mLooper.dispatchAll();
observerLooper.dispatchAll();
assertTrue(observer.mOnStoppedCalled);
@@ -974,25 +1204,6 @@ public class WifiManagerTest {
}
/**
- * Verify that calls WifiServiceImpl to set country code when no exception happens.
- */
- @Test
- public void testSetWifiCountryCode() throws Exception {
- mWifiManager.setCountryCode(TEST_COUNTRY_CODE);
- verify(mWifiService).setCountryCode(TEST_COUNTRY_CODE);
- }
-
- /**
- * Verify that WifiManager.setCountryCode() rethrows exceptions if caller does not
- * have necessary permissions.
- */
- @Test(expected = SecurityException.class)
- public void testSetWifiCountryCodeFailedOnSecurityException() throws Exception {
- doThrow(new SecurityException()).when(mWifiService).setCountryCode(anyString());
- mWifiManager.setCountryCode(TEST_COUNTRY_CODE);
- }
-
- /**
* Test that calls to get the current WPS config token return null and do not have any
* interactions with WifiServiceImpl.
*/
@@ -1003,7 +1214,7 @@ public class WifiManagerTest {
}
- class WpsCallbackTester extends WifiManager.WpsCallback {
+ class WpsCallbackTester extends WpsCallback {
public boolean mStarted = false;
public boolean mSucceeded = false;
public boolean mFailed = false;
@@ -1035,7 +1246,7 @@ public class WifiManagerTest {
WpsCallbackTester wpsCallback = new WpsCallbackTester();
mWifiManager.startWps(null, wpsCallback);
assertTrue(wpsCallback.mFailed);
- assertEquals(WifiManager.ERROR, wpsCallback.mFailureCode);
+ assertEquals(ERROR, wpsCallback.mFailureCode);
assertFalse(wpsCallback.mStarted);
assertFalse(wpsCallback.mSucceeded);
verifyNoMoreInteractions(mWifiService);
@@ -1058,7 +1269,7 @@ public class WifiManagerTest {
WpsCallbackTester wpsCallback = new WpsCallbackTester();
mWifiManager.cancelWps(wpsCallback);
assertTrue(wpsCallback.mFailed);
- assertEquals(WifiManager.ERROR, wpsCallback.mFailureCode);
+ assertEquals(ERROR, wpsCallback.mFailureCode);
assertFalse(wpsCallback.mStarted);
assertFalse(wpsCallback.mSucceeded);
verifyNoMoreInteractions(mWifiService);
@@ -1111,14 +1322,53 @@ public class WifiManagerTest {
}
/**
+ * Verify that a successful call properly returns true.
+ */
+ @Test
+ public void testSetSoftApConfigurationSuccessReturnsTrue() throws Exception {
+ SoftApConfiguration apConfig = generatorTestSoftApConfig();
+
+ when(mWifiService.setSoftApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+ .thenReturn(true);
+ assertTrue(mWifiManager.setSoftApConfiguration(apConfig));
+ }
+
+ /**
+ * Verify that a failed call properly returns false.
+ */
+ @Test
+ public void testSetSoftApConfigurationFailureReturnsFalse() throws Exception {
+ SoftApConfiguration apConfig = generatorTestSoftApConfig();
+
+ when(mWifiService.setSoftApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+ .thenReturn(false);
+ assertFalse(mWifiManager.setSoftApConfiguration(apConfig));
+ }
+
+ /**
+ * Verify Exceptions are rethrown when underlying calls to WifiService throw exceptions.
+ */
+ @Test
+ public void testSetSoftApConfigurationRethrowsException() throws Exception {
+ doThrow(new SecurityException()).when(mWifiService).setSoftApConfiguration(any(), any());
+
+ try {
+ mWifiManager.setSoftApConfiguration(generatorTestSoftApConfig());
+ fail("setWifiApConfiguration should rethrow Exceptions from WifiService");
+ } catch (SecurityException e) { }
+ }
+
+ /**
* Check the call to startScan calls WifiService.
*/
@Test
public void testStartScan() throws Exception {
- when(mWifiService.startScan(TEST_PACKAGE_NAME)).thenReturn(true);
+ when(mWifiService.startScan(eq(TEST_PACKAGE_NAME), nullable(String.class))).thenReturn(
+ true);
assertTrue(mWifiManager.startScan());
- when(mWifiService.startScan(TEST_PACKAGE_NAME)).thenReturn(false);
+ when(mWifiService.startScan(eq(TEST_PACKAGE_NAME), nullable(String.class))).thenReturn(
+ false);
assertFalse(mWifiManager.startScan());
}
@@ -1128,10 +1378,10 @@ public class WifiManagerTest {
@Test
public void registerTrafficStateCallbackUsesMainLooperOnNullArgumentForHandler()
throws Exception {
- when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
ArgumentCaptor<ITrafficStateCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(ITrafficStateCallback.Stub.class);
- mWifiManager.registerTrafficStateCallback(mTrafficStateCallback, null);
+ mWifiManager.registerTrafficStateCallback(
+ new HandlerExecutor(new Handler(mLooper.getLooper())), mTrafficStateCallback);
verify(mWifiService).registerTrafficStateCallback(
any(IBinder.class), callbackCaptor.capture(), anyInt());
@@ -1147,7 +1397,8 @@ public class WifiManagerTest {
@Test
public void unregisterTrafficStateCallbackCallGoesToWifiServiceImpl() throws Exception {
ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class);
- mWifiManager.registerTrafficStateCallback(mTrafficStateCallback, mHandler);
+ mWifiManager.registerTrafficStateCallback(new HandlerExecutor(mHandler),
+ mTrafficStateCallback);
verify(mWifiService).registerTrafficStateCallback(any(IBinder.class),
any(ITrafficStateCallback.Stub.class), callbackIdentifier.capture());
@@ -1163,7 +1414,8 @@ public class WifiManagerTest {
public void trafficStateCallbackProxyCallsOnMultipleUpdates() throws Exception {
ArgumentCaptor<ITrafficStateCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(ITrafficStateCallback.Stub.class);
- mWifiManager.registerTrafficStateCallback(mTrafficStateCallback, mHandler);
+ mWifiManager.registerTrafficStateCallback(new HandlerExecutor(mHandler),
+ mTrafficStateCallback);
verify(mWifiService).registerTrafficStateCallback(
any(IBinder.class), callbackCaptor.capture(), anyInt());
@@ -1182,7 +1434,7 @@ public class WifiManagerTest {
TrafficStateCallback.DATA_ACTIVITY_OUT);
}
- /*
+ /**
* Verify client-provided callback is being called on the correct thread
*/
@Test
@@ -1191,8 +1443,10 @@ public class WifiManagerTest {
ArgumentCaptor.forClass(ITrafficStateCallback.Stub.class);
TestLooper altLooper = new TestLooper();
Handler altHandler = new Handler(altLooper.getLooper());
- mWifiManager.registerTrafficStateCallback(mTrafficStateCallback, altHandler);
+ mWifiManager.registerTrafficStateCallback(new HandlerExecutor(altHandler),
+ mTrafficStateCallback);
verify(mContext, never()).getMainLooper();
+ verify(mContext, never()).getMainExecutor();
verify(mWifiService).registerTrafficStateCallback(
any(IBinder.class), callbackCaptor.capture(), anyInt());
@@ -1208,10 +1462,11 @@ public class WifiManagerTest {
@Test
public void registerNetworkRequestMatchCallbackCallGoesToWifiServiceImpl()
throws Exception {
- when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
- mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+ mWifiManager.registerNetworkRequestMatchCallback(
+ new HandlerExecutor(new Handler(mLooper.getLooper())),
+ mNetworkRequestMatchCallback);
verify(mWifiService).registerNetworkRequestMatchCallback(
any(IBinder.class), callbackCaptor.capture(), anyInt());
@@ -1245,7 +1500,8 @@ public class WifiManagerTest {
@Test
public void unregisterNetworkRequestMatchCallbackCallGoesToWifiServiceImpl() throws Exception {
ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class);
- mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, mHandler);
+ mWifiManager.registerNetworkRequestMatchCallback(new HandlerExecutor(mHandler),
+ mNetworkRequestMatchCallback);
verify(mWifiService).registerNetworkRequestMatchCallback(
any(IBinder.class), any(INetworkRequestMatchCallback.class),
callbackIdentifier.capture());
@@ -1262,10 +1518,11 @@ public class WifiManagerTest {
@Test
public void networkRequestUserSelectionCallbackCallGoesToWifiServiceImpl()
throws Exception {
- when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
- mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+ mWifiManager.registerNetworkRequestMatchCallback(
+ new HandlerExecutor(new Handler(mLooper.getLooper())),
+ mNetworkRequestMatchCallback);
verify(mWifiService).registerNetworkRequestMatchCallback(
any(IBinder.class), callbackCaptor.capture(), anyInt());
@@ -1293,14 +1550,15 @@ public class WifiManagerTest {
*/
@Test
public void testGetAllMatchingWifiConfigs() throws Exception {
- Map<String, List<ScanResult>> fqdns = new HashMap<>();
- fqdns.put("www.test.com", new ArrayList<>());
- when(mWifiService.getAllMatchingFqdnsForScanResults(any(List.class))).thenReturn(fqdns);
+ Map<String, List<ScanResult>> passpointProfiles = new HashMap<>();
+ passpointProfiles.put("www.test.com_987a69bca26", new ArrayList<>());
+ when(mWifiService.getAllMatchingPasspointProfilesForScanResults(
+ any(List.class))).thenReturn(passpointProfiles);
InOrder inOrder = inOrder(mWifiService);
mWifiManager.getAllMatchingWifiConfigs(new ArrayList<>());
- inOrder.verify(mWifiService).getAllMatchingFqdnsForScanResults(any(List.class));
+ inOrder.verify(mWifiService).getAllMatchingPasspointProfilesForScanResults(any(List.class));
inOrder.verify(mWifiService).getWifiConfigsForPasspointProfiles(any(List.class));
}
@@ -1316,21 +1574,29 @@ public class WifiManagerTest {
}
/**
- * Verify calls to {@link WifiManager#addNetworkSuggestions(List)} and
+ * Verify calls to {@link WifiManager#addNetworkSuggestions(List)},
+ * {@link WifiManager#getNetworkSuggestions()} and
* {@link WifiManager#removeNetworkSuggestions(List)}.
*/
@Test
- public void addRemoveNetworkSuggestions() throws Exception {
- when(mWifiService.addNetworkSuggestions(any(List.class), anyString()))
- .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
- when(mWifiService.removeNetworkSuggestions(any(List.class), anyString()))
- .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
+ public void addGetRemoveNetworkSuggestions() throws Exception {
+ List<WifiNetworkSuggestion> testList = new ArrayList<>();
+ when(mWifiService.addNetworkSuggestions(any(List.class), anyString(),
+ nullable(String.class))).thenReturn(STATUS_NETWORK_SUGGESTIONS_SUCCESS);
+ when(mWifiService.removeNetworkSuggestions(any(List.class), anyString())).thenReturn(
+ STATUS_NETWORK_SUGGESTIONS_SUCCESS);
+ when(mWifiService.getNetworkSuggestions(anyString()))
+ .thenReturn(testList);
+
+ assertEquals(STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+ mWifiManager.addNetworkSuggestions(testList));
+ verify(mWifiService).addNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME),
+ nullable(String.class));
- assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
- mWifiManager.addNetworkSuggestions(new ArrayList<>()));
- verify(mWifiService).addNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME));
+ assertEquals(testList, mWifiManager.getNetworkSuggestions());
+ verify(mWifiService).getNetworkSuggestions(eq(TEST_PACKAGE_NAME));
- assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+ assertEquals(STATUS_NETWORK_SUGGESTIONS_SUCCESS,
mWifiManager.removeNetworkSuggestions(new ArrayList<>()));
verify(mWifiService).removeNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME));
}
@@ -1340,8 +1606,15 @@ public class WifiManagerTest {
*/
@Test
public void getMaxNumberOfNetworkSuggestionsPerApp() {
- assertEquals(WifiManager.NETWORK_SUGGESTIONS_MAX_PER_APP,
- mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp());
+ when(mContext.getSystemServiceName(ActivityManager.class))
+ .thenReturn(Context.ACTIVITY_SERVICE);
+ when(mContext.getSystemService(Context.ACTIVITY_SERVICE))
+ .thenReturn(mActivityManager);
+ when(mActivityManager.isLowRamDevice()).thenReturn(true);
+ assertEquals(256, mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp());
+
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ assertEquals(1024, mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp());
}
/**
@@ -1382,24 +1655,15 @@ public class WifiManagerTest {
}
/**
- * Defined for testing purpose.
- */
- class SynchronousExecutor implements Executor {
- public void execute(Runnable r) {
- r.run();
- }
- }
-
- /**
* Test behavior of isEnhancedOpenSupported
*/
@Test
public void testIsEnhancedOpenSupported() throws Exception {
when(mWifiService.getSupportedFeatures())
- .thenReturn(new Long(WifiManager.WIFI_FEATURE_OWE));
+ .thenReturn(new Long(WIFI_FEATURE_OWE));
assertTrue(mWifiManager.isEnhancedOpenSupported());
when(mWifiService.getSupportedFeatures())
- .thenReturn(new Long(~WifiManager.WIFI_FEATURE_OWE));
+ .thenReturn(new Long(~WIFI_FEATURE_OWE));
assertFalse(mWifiManager.isEnhancedOpenSupported());
}
@@ -1409,10 +1673,10 @@ public class WifiManagerTest {
@Test
public void testIsWpa3SaeSupported() throws Exception {
when(mWifiService.getSupportedFeatures())
- .thenReturn(new Long(WifiManager.WIFI_FEATURE_WPA3_SAE));
+ .thenReturn(new Long(WIFI_FEATURE_WPA3_SAE));
assertTrue(mWifiManager.isWpa3SaeSupported());
when(mWifiService.getSupportedFeatures())
- .thenReturn(new Long(~WifiManager.WIFI_FEATURE_WPA3_SAE));
+ .thenReturn(new Long(~WIFI_FEATURE_WPA3_SAE));
assertFalse(mWifiManager.isWpa3SaeSupported());
}
@@ -1422,10 +1686,10 @@ public class WifiManagerTest {
@Test
public void testIsWpa3SuiteBSupported() throws Exception {
when(mWifiService.getSupportedFeatures())
- .thenReturn(new Long(WifiManager.WIFI_FEATURE_WPA3_SUITE_B));
+ .thenReturn(new Long(WIFI_FEATURE_WPA3_SUITE_B));
assertTrue(mWifiManager.isWpa3SuiteBSupported());
when(mWifiService.getSupportedFeatures())
- .thenReturn(new Long(~WifiManager.WIFI_FEATURE_WPA3_SUITE_B));
+ .thenReturn(new Long(~WIFI_FEATURE_WPA3_SUITE_B));
assertFalse(mWifiManager.isWpa3SuiteBSupported());
}
@@ -1435,10 +1699,10 @@ public class WifiManagerTest {
@Test
public void testIsEasyConnectSupported() throws Exception {
when(mWifiService.getSupportedFeatures())
- .thenReturn(new Long(WifiManager.WIFI_FEATURE_DPP));
+ .thenReturn(new Long(WIFI_FEATURE_DPP));
assertTrue(mWifiManager.isEasyConnectSupported());
when(mWifiService.getSupportedFeatures())
- .thenReturn(new Long(~WifiManager.WIFI_FEATURE_DPP));
+ .thenReturn(new Long(~WIFI_FEATURE_DPP));
assertFalse(mWifiManager.isEasyConnectSupported());
}
@@ -1502,6 +1766,49 @@ public class WifiManagerTest {
}
/**
+ * Test behavior of {@link WifiManager#allowAutojoin(int, boolean)}
+ * @throws Exception
+ */
+ @Test
+ public void testAllowAutojoin() throws Exception {
+ mWifiManager.allowAutojoin(1, true);
+ verify(mWifiService).allowAutojoin(1, true);
+ }
+
+ /**
+ * Test behavior of {@link WifiManager#allowAutojoinPasspoint(String, boolean)}
+ * @throws Exception
+ */
+ @Test
+ public void testAllowAutojoinPasspoint() throws Exception {
+ final String fqdn = "FullyQualifiedDomainName";
+ mWifiManager.allowAutojoinPasspoint(fqdn, true);
+ verify(mWifiService).allowAutojoinPasspoint(fqdn, true);
+ }
+
+ /**
+ * Test behavior of
+ * {@link WifiManager#setMacRandomizationSettingPasspointEnabled(String, boolean)}
+ */
+ @Test
+ public void testSetMacRandomizationSettingPasspointEnabled() throws Exception {
+ final String fqdn = "FullyQualifiedDomainName";
+ mWifiManager.setMacRandomizationSettingPasspointEnabled(fqdn, true);
+ verify(mWifiService).setMacRandomizationSettingPasspointEnabled(fqdn, true);
+ }
+
+ /**
+ * Test behavior of
+ * {@link WifiManager#setMacRandomizationSettingPasspointEnabled(String, boolean)}
+ */
+ @Test
+ public void testSetPasspointMeteredOverride() throws Exception {
+ final String fqdn = "FullyQualifiedDomainName";
+ mWifiManager.setPasspointMeteredOverride(fqdn, METERED_OVERRIDE_METERED);
+ verify(mWifiService).setPasspointMeteredOverride(fqdn, METERED_OVERRIDE_METERED);
+ }
+
+ /**
* Test behavior of {@link WifiManager#disconnect()}
*/
@Test
@@ -1537,9 +1844,9 @@ public class WifiManagerTest {
@Test
public void testGetSupportedFeatures() throws Exception {
long supportedFeatures =
- WifiManager.WIFI_FEATURE_SCANNER
- | WifiManager.WIFI_FEATURE_PASSPOINT
- | WifiManager.WIFI_FEATURE_P2P;
+ WIFI_FEATURE_SCANNER
+ | WIFI_FEATURE_PASSPOINT
+ | WIFI_FEATURE_P2P;
when(mWifiService.getSupportedFeatures())
.thenReturn(Long.valueOf(supportedFeatures));
@@ -1547,7 +1854,6 @@ public class WifiManagerTest {
assertTrue(mWifiManager.isPasspointSupported());
assertTrue(mWifiManager.isP2pSupported());
assertFalse(mWifiManager.isPortableHotspotSupported());
- assertFalse(mWifiManager.is5GHzBandSupported());
assertFalse(mWifiManager.isDeviceToDeviceRttSupported());
assertFalse(mWifiManager.isDeviceToApRttSupported());
assertFalse(mWifiManager.isPreferredNetworkOffloadSupported());
@@ -1558,15 +1864,55 @@ public class WifiManagerTest {
}
/**
- * Test behavior of {@link WifiManager#getControllerActivityEnergyInfo()}
+ * Tests that passing a null Executor to {@link WifiManager#getWifiActivityEnergyInfoAsync}
+ * throws an exception.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testGetWifiActivityInfoNullExecutor() throws Exception {
+ mWifiManager.getWifiActivityEnergyInfoAsync(null, mOnWifiActivityEnergyInfoListener);
+ }
+
+ /**
+ * Tests that passing a null listener to {@link WifiManager#getWifiActivityEnergyInfoAsync}
+ * throws an exception.
*/
+ @Test(expected = NullPointerException.class)
+ public void testGetWifiActivityInfoNullListener() throws Exception {
+ mWifiManager.getWifiActivityEnergyInfoAsync(mExecutor, null);
+ }
+
+ /** Tests that the listener runs on the correct Executor. */
+ @Test
+ public void testGetWifiActivityInfoRunsOnCorrectExecutor() throws Exception {
+ mWifiManager.getWifiActivityEnergyInfoAsync(mExecutor, mOnWifiActivityEnergyInfoListener);
+ ArgumentCaptor<IOnWifiActivityEnergyInfoListener> listenerCaptor =
+ ArgumentCaptor.forClass(IOnWifiActivityEnergyInfoListener.class);
+ verify(mWifiService).getWifiActivityEnergyInfoAsync(listenerCaptor.capture());
+ IOnWifiActivityEnergyInfoListener listener = listenerCaptor.getValue();
+ listener.onWifiActivityEnergyInfo(mWifiActivityEnergyInfo);
+ verify(mExecutor).execute(any());
+
+ // ensure that the executor is only triggered once
+ listener.onWifiActivityEnergyInfo(mWifiActivityEnergyInfo);
+ verify(mExecutor).execute(any());
+ }
+
+ /** Tests that the correct listener runs. */
@Test
- public void testGetControllerActivityEnergyInfo() throws Exception {
- WifiActivityEnergyInfo activityEnergyInfo =
- new WifiActivityEnergyInfo(5, 3, 3, new long[]{5L, 5L, 5L}, 5, 5, 5, 5);
- when(mWifiService.reportActivityInfo()).thenReturn(activityEnergyInfo);
+ public void testGetWifiActivityInfoRunsCorrectListener() throws Exception {
+ int[] flag = {0};
+ mWifiManager.getWifiActivityEnergyInfoAsync(
+ new SynchronousExecutor(), info -> flag[0]++);
+ ArgumentCaptor<IOnWifiActivityEnergyInfoListener> listenerCaptor =
+ ArgumentCaptor.forClass(IOnWifiActivityEnergyInfoListener.class);
+ verify(mWifiService).getWifiActivityEnergyInfoAsync(listenerCaptor.capture());
+ IOnWifiActivityEnergyInfoListener listener = listenerCaptor.getValue();
+ listener.onWifiActivityEnergyInfo(mWifiActivityEnergyInfo);
+ assertEquals(1, flag[0]);
- assertEquals(activityEnergyInfo, mWifiManager.getControllerActivityEnergyInfo());
+ // ensure that the listener is only triggered once
+ listener.onWifiActivityEnergyInfo(mWifiActivityEnergyInfo);
+ assertEquals(1, flag[0]);
}
/**
@@ -1575,29 +1921,41 @@ public class WifiManagerTest {
@Test
public void testGetConnectionInfo() throws Exception {
WifiInfo wifiInfo = new WifiInfo();
- when(mWifiService.getConnectionInfo(anyString())).thenReturn(wifiInfo);
+ when(mWifiService.getConnectionInfo(anyString(), nullable(String.class))).thenReturn(
+ wifiInfo);
assertEquals(wifiInfo, mWifiManager.getConnectionInfo());
}
/**
- * Test behavior of {@link WifiManager#isDualModeSupported()} ()}
+ * Test behavior of {@link WifiManager#is5GHzBandSupported()}
*/
@Test
- public void testIsDualModeSupported() throws Exception {
- when(mWifiService.needs5GHzToAnyApBandConversion()).thenReturn(true);
- assertTrue(mWifiManager.isDualModeSupported());
- verify(mWifiService).needs5GHzToAnyApBandConversion();
+ public void testIs5GHzBandSupported() throws Exception {
+ when(mWifiService.is5GHzBandSupported()).thenReturn(true);
+ assertTrue(mWifiManager.is5GHzBandSupported());
+ verify(mWifiService).is5GHzBandSupported();
}
/**
- * Test behavior of {@link WifiManager#isDualBandSupported()}
+ * Test behavior of {@link WifiManager#is6GHzBandSupported()}
*/
@Test
- public void testIsDualBandSupported() throws Exception {
- when(mWifiService.isDualBandSupported()).thenReturn(true);
- assertTrue(mWifiManager.isDualBandSupported());
- verify(mWifiService).isDualBandSupported();
+ public void testIs6GHzBandSupported() throws Exception {
+ when(mWifiService.is6GHzBandSupported()).thenReturn(true);
+ assertTrue(mWifiManager.is6GHzBandSupported());
+ verify(mWifiService).is6GHzBandSupported();
+ }
+
+ /**
+ * Test behavior of {@link WifiManager#isWifiStandardSupported()}
+ */
+ @Test
+ public void testIsWifiStandardSupported() throws Exception {
+ int standard = ScanResult.WIFI_STANDARD_11AX;
+ when(mWifiService.isWifiStandardSupported(standard)).thenReturn(true);
+ assertTrue(mWifiManager.isWifiStandardSupported(standard));
+ verify(mWifiService).isWifiStandardSupported(standard);
}
/**
@@ -1623,4 +1981,409 @@ public class WifiManagerTest {
assertTrue(mWifiManager.setWifiEnabled(false));
verify(mWifiService).setWifiEnabled(mContext.getOpPackageName(), false);
}
+
+ /**
+ * Test behavior of {@link WifiManager#connect(int, ActionListener)}
+ */
+ @Test
+ public void testConnectWithListener() throws Exception {
+ ActionListener externalListener = mock(ActionListener.class);
+ mWifiManager.connect(TEST_NETWORK_ID, externalListener);
+
+ ArgumentCaptor<IActionListener> binderListenerCaptor =
+ ArgumentCaptor.forClass(IActionListener.class);
+ verify(mWifiService).connect(eq(null), eq(TEST_NETWORK_ID), any(Binder.class),
+ binderListenerCaptor.capture(), anyInt());
+ assertNotNull(binderListenerCaptor.getValue());
+
+ // Trigger on success.
+ binderListenerCaptor.getValue().onSuccess();
+ mLooper.dispatchAll();
+ verify(externalListener).onSuccess();
+
+ // Trigger on failure.
+ binderListenerCaptor.getValue().onFailure(BUSY);
+ mLooper.dispatchAll();
+ verify(externalListener).onFailure(BUSY);
+ }
+
+ /**
+ * Test behavior of {@link WifiManager#connect(int, ActionListener)}
+ */
+ @Test
+ public void testConnectWithListenerHandleSecurityException() throws Exception {
+ doThrow(new SecurityException()).when(mWifiService)
+ .connect(eq(null), anyInt(), any(IBinder.class),
+ any(IActionListener.class), anyInt());
+ ActionListener externalListener = mock(ActionListener.class);
+ mWifiManager.connect(TEST_NETWORK_ID, externalListener);
+
+ mLooper.dispatchAll();
+ verify(externalListener).onFailure(NOT_AUTHORIZED);
+ }
+
+ /**
+ * Test behavior of {@link WifiManager#connect(int, ActionListener)}
+ */
+ @Test
+ public void testConnectWithListenerHandleRemoteException() throws Exception {
+ doThrow(new RemoteException()).when(mWifiService)
+ .connect(eq(null), anyInt(), any(IBinder.class),
+ any(IActionListener.class), anyInt());
+ ActionListener externalListener = mock(ActionListener.class);
+ mWifiManager.connect(TEST_NETWORK_ID, externalListener);
+
+ mLooper.dispatchAll();
+ verify(externalListener).onFailure(ERROR);
+ }
+
+ /**
+ * Test behavior of {@link WifiManager#connect(int, ActionListener)}
+ */
+ @Test
+ public void testConnectWithoutListener() throws Exception {
+ WifiConfiguration configuration = new WifiConfiguration();
+ mWifiManager.connect(configuration, null);
+
+ verify(mWifiService).connect(configuration, WifiConfiguration.INVALID_NETWORK_ID, null,
+ null, 0);
+ }
+
+ /**
+ * Verify an IllegalArgumentException is thrown if callback is not provided.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testRegisterScanResultsCallbackWithNullCallback() throws Exception {
+ mWifiManager.registerScanResultsCallback(mExecutor, null);
+ }
+
+ /**
+ * Verify an IllegalArgumentException is thrown if executor is not provided.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testRegisterCallbackWithNullExecutor() throws Exception {
+ mWifiManager.registerScanResultsCallback(null, mScanResultsCallback);
+ }
+
+ /**
+ * Verify client provided callback is being called to the right callback.
+ */
+ @Test
+ public void testAddScanResultsCallbackAndReceiveEvent() throws Exception {
+ ArgumentCaptor<IScanResultsCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(IScanResultsCallback.Stub.class);
+ mWifiManager.registerScanResultsCallback(new SynchronousExecutor(), mScanResultsCallback);
+ verify(mWifiService).registerScanResultsCallback(callbackCaptor.capture());
+ callbackCaptor.getValue().onScanResultsAvailable();
+ verify(mRunnable).run();
+ }
+
+ /**
+ * Verify client provided callback is being called to the right executor.
+ */
+ @Test
+ public void testRegisterScanResultsCallbackWithTheTargetExecutor() throws Exception {
+ ArgumentCaptor<IScanResultsCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(IScanResultsCallback.Stub.class);
+ mWifiManager.registerScanResultsCallback(mExecutor, mScanResultsCallback);
+ verify(mWifiService).registerScanResultsCallback(callbackCaptor.capture());
+ mWifiManager.registerScanResultsCallback(mAnotherExecutor, mScanResultsCallback);
+ callbackCaptor.getValue().onScanResultsAvailable();
+ verify(mExecutor, never()).execute(any(Runnable.class));
+ verify(mAnotherExecutor).execute(any(Runnable.class));
+ }
+
+ /**
+ * Verify client register unregister then register again, to ensure callback still works.
+ */
+ @Test
+ public void testRegisterUnregisterThenRegisterAgainWithScanResultCallback() throws Exception {
+ ArgumentCaptor<IScanResultsCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(IScanResultsCallback.Stub.class);
+ mWifiManager.registerScanResultsCallback(new SynchronousExecutor(), mScanResultsCallback);
+ verify(mWifiService).registerScanResultsCallback(callbackCaptor.capture());
+ mWifiManager.unregisterScanResultsCallback(mScanResultsCallback);
+ callbackCaptor.getValue().onScanResultsAvailable();
+ verify(mRunnable, never()).run();
+ mWifiManager.registerScanResultsCallback(new SynchronousExecutor(), mScanResultsCallback);
+ callbackCaptor.getValue().onScanResultsAvailable();
+ verify(mRunnable).run();
+ }
+
+ /**
+ * Verify client unregisterScanResultsCallback.
+ */
+ @Test
+ public void testUnregisterScanResultsCallback() throws Exception {
+ mWifiManager.unregisterScanResultsCallback(mScanResultsCallback);
+ verify(mWifiService).unregisterScanResultsCallback(any());
+ }
+
+ /**
+ * Verify client unregisterScanResultsCallback with null callback will cause an exception.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testUnregisterScanResultsCallbackWithNullCallback() throws Exception {
+ mWifiManager.unregisterScanResultsCallback(null);
+ }
+
+ /**
+ * Verify an IllegalArgumentException is thrown if executor not provided.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddSuggestionConnectionStatusListenerWithNullExecutor() {
+ mWifiManager.addSuggestionConnectionStatusListener(null, mListener);
+ }
+
+ /**
+ * Verify an IllegalArgumentException is thrown if listener is not provided.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddSuggestionConnectionStatusListenerWithNullListener() {
+ mWifiManager.addSuggestionConnectionStatusListener(mExecutor, null);
+ }
+
+ /**
+ * Verify client provided listener is being called to the right listener.
+ */
+ @Test
+ public void testAddSuggestionConnectionStatusListenerAndReceiveEvent() throws Exception {
+ int errorCode = STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION;
+ ArgumentCaptor<ISuggestionConnectionStatusListener.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(ISuggestionConnectionStatusListener.Stub.class);
+ Executor executor = new SynchronousExecutor();
+ mWifiManager.addSuggestionConnectionStatusListener(executor, mListener);
+ verify(mWifiService).registerSuggestionConnectionStatusListener(any(IBinder.class),
+ callbackCaptor.capture(), anyInt(), anyString(), nullable(String.class));
+ callbackCaptor.getValue().onConnectionStatus(mWifiNetworkSuggestion, errorCode);
+ verify(mListener).onConnectionStatus(any(WifiNetworkSuggestion.class), eq(errorCode));
+ }
+
+ /**
+ * Verify client provided listener is being called to the right executor.
+ */
+ @Test
+ public void testAddSuggestionConnectionStatusListenerWithTheTargetExecutor() throws Exception {
+ int errorCode = STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION;
+ ArgumentCaptor<ISuggestionConnectionStatusListener.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(ISuggestionConnectionStatusListener.Stub.class);
+ mWifiManager.addSuggestionConnectionStatusListener(mExecutor, mListener);
+ verify(mWifiService).registerSuggestionConnectionStatusListener(any(IBinder.class),
+ callbackCaptor.capture(), anyInt(), anyString(), nullable(String.class));
+ callbackCaptor.getValue().onConnectionStatus(any(WifiNetworkSuggestion.class), errorCode);
+ verify(mExecutor).execute(any(Runnable.class));
+ }
+
+ /**
+ * Verify an IllegalArgumentException is thrown if listener is not provided.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testRemoveSuggestionConnectionListenerWithNullListener() {
+ mWifiManager.removeSuggestionConnectionStatusListener(null);
+ }
+
+ /**
+ * Verify removeSuggestionConnectionListener.
+ */
+ @Test
+ public void testRemoveSuggestionConnectionListener() throws Exception {
+ mWifiManager.removeSuggestionConnectionStatusListener(mListener);
+ verify(mWifiService).unregisterSuggestionConnectionStatusListener(anyInt(), anyString());
+ }
+
+ /** Test {@link WifiManager#calculateSignalLevel(int)} */
+ @Test
+ public void testCalculateSignalLevel() throws Exception {
+ when(mWifiService.calculateSignalLevel(anyInt())).thenReturn(3);
+ int actual = mWifiManager.calculateSignalLevel(-60);
+ verify(mWifiService).calculateSignalLevel(-60);
+ assertEquals(3, actual);
+ }
+
+ /** Test {@link WifiManager#getMaxSignalLevel()} */
+ @Test
+ public void testGetMaxSignalLevel() throws Exception {
+ when(mWifiService.calculateSignalLevel(anyInt())).thenReturn(4);
+ int actual = mWifiManager.getMaxSignalLevel();
+ verify(mWifiService).calculateSignalLevel(Integer.MAX_VALUE);
+ assertEquals(4, actual);
+ }
+
+ /*
+ * Test behavior of isWapiSupported
+ * @throws Exception
+ */
+ @Test
+ public void testIsWapiSupported() throws Exception {
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(WifiManager.WIFI_FEATURE_WAPI));
+ assertTrue(mWifiManager.isWapiSupported());
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(~WifiManager.WIFI_FEATURE_WAPI));
+ assertFalse(mWifiManager.isWapiSupported());
+ }
+
+ /*
+ * Test that DPP channel list is parsed correctly
+ */
+ @Test
+ public void testparseDppChannelList() throws Exception {
+ String channelList = "81/1,2,3,4,5,6,7,8,9,10,11,115/36,40,44,48";
+ SparseArray<int[]> expectedResult = new SparseArray<>();
+ expectedResult.append(81, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11});
+ expectedResult.append(115, new int[]{36, 40, 44, 48});
+
+ SparseArray<int[]> result = WifiManager.parseDppChannelList(channelList);
+ assertEquals(expectedResult.size(), result.size());
+
+ int index = 0;
+ int key;
+
+ // Compare the two primitive int arrays
+ do {
+ try {
+ key = result.keyAt(index);
+ } catch (java.lang.ArrayIndexOutOfBoundsException e) {
+ break;
+ }
+ int[] expected = expectedResult.get(key);
+ int[] output = result.get(key);
+ assertEquals(expected.length, output.length);
+ for (int i = 0; i < output.length; i++) {
+ assertEquals(expected[i], output[i]);
+ }
+ index++;
+ } while (true);
+ }
+
+ /*
+ * Test that DPP channel list parser gracefully fails for invalid input
+ */
+ @Test
+ public void testparseDppChannelListWithInvalidFormats() throws Exception {
+ String channelList = "1,2,3,4,5,6,7,8,9,10,11,36,40,44,48";
+ SparseArray<int[]> result = WifiManager.parseDppChannelList(channelList);
+ assertEquals(result.size(), 0);
+
+ channelList = "ajgalskgjalskjg3-09683dh";
+ result = WifiManager.parseDppChannelList(channelList);
+ assertEquals(result.size(), 0);
+
+ channelList = "13/abc,46////";
+ result = WifiManager.parseDppChannelList(channelList);
+ assertEquals(result.size(), 0);
+
+ channelList = "11/4,5,13/";
+ result = WifiManager.parseDppChannelList(channelList);
+ assertEquals(result.size(), 0);
+
+ channelList = "/24,6";
+ result = WifiManager.parseDppChannelList(channelList);
+ assertEquals(result.size(), 0);
+ }
+
+ /**
+ * Test getWifiConfigsForMatchedNetworkSuggestions for given scanResults.
+ */
+ @Test
+ public void testGetWifiConfigsForMatchedNetworkSuggestions() throws Exception {
+ List<WifiConfiguration> testResults = new ArrayList<>();
+ testResults.add(new WifiConfiguration());
+
+ when(mWifiService.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(any(List.class)))
+ .thenReturn(testResults);
+ assertEquals(testResults, mWifiManager
+ .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(new ArrayList<>()));
+ }
+
+ /**
+ * Verify the call to setWifiConnectedNetworkScorer goes to WifiServiceImpl.
+ */
+ @Test
+ public void setWifiConnectedNetworkScorerGoesToWifiServiceImpl() throws Exception {
+ mExecutor = new SynchronousExecutor();
+ mWifiManager.setWifiConnectedNetworkScorer(mExecutor, mWifiConnectedNetworkScorer);
+ verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
+ any(IWifiConnectedNetworkScorer.Stub.class));
+ }
+
+ /**
+ * Verify the call to clearWifiConnectedNetworkScorer goes to WifiServiceImpl.
+ */
+ @Test
+ public void clearWifiConnectedNetworkScorerGoesToWifiServiceImpl() throws Exception {
+ mExecutor = new SynchronousExecutor();
+ mWifiManager.setWifiConnectedNetworkScorer(mExecutor, mWifiConnectedNetworkScorer);
+ verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
+ any(IWifiConnectedNetworkScorer.Stub.class));
+
+ mWifiManager.clearWifiConnectedNetworkScorer();
+ verify(mWifiService).clearWifiConnectedNetworkScorer();
+ }
+
+ /**
+ * Verify that Wi-Fi connected scorer receives score update observer after registeration.
+ */
+ @Test
+ public void verifyScorerReceiveScoreUpdateObserverAfterRegistration() throws Exception {
+ mExecutor = new SynchronousExecutor();
+ mWifiManager.setWifiConnectedNetworkScorer(mExecutor, mWifiConnectedNetworkScorer);
+ ArgumentCaptor<IWifiConnectedNetworkScorer.Stub> scorerCaptor =
+ ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
+ verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
+ scorerCaptor.capture());
+ scorerCaptor.getValue().onSetScoreUpdateObserver(any());
+ mLooper.dispatchAll();
+ verify(mWifiConnectedNetworkScorer).onSetScoreUpdateObserver(any());
+ }
+
+ /**
+ * Verify that Wi-Fi connected scorer receives session ID when onStart/onStop methods
+ * are called.
+ */
+ @Test
+ public void verifyScorerReceiveSessionIdWhenStartStopIsCalled() throws Exception {
+ mExecutor = new SynchronousExecutor();
+ mWifiManager.setWifiConnectedNetworkScorer(mExecutor, mWifiConnectedNetworkScorer);
+ ArgumentCaptor<IWifiConnectedNetworkScorer.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
+ verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
+ callbackCaptor.capture());
+ callbackCaptor.getValue().onStart(0);
+ callbackCaptor.getValue().onStop(10);
+ mLooper.dispatchAll();
+ verify(mWifiConnectedNetworkScorer).onStart(0);
+ verify(mWifiConnectedNetworkScorer).onStop(10);
+ }
+
+ @Test
+ public void testScanThrottle() throws Exception {
+ mWifiManager.setScanThrottleEnabled(true);
+ verify(mWifiService).setScanThrottleEnabled(true);
+
+ when(mWifiService.isScanThrottleEnabled()).thenReturn(false);
+ assertFalse(mWifiManager.isScanThrottleEnabled());
+ verify(mWifiService).isScanThrottleEnabled();
+ }
+
+ @Test
+ public void testAutoWakeup() throws Exception {
+ mWifiManager.setAutoWakeupEnabled(true);
+ verify(mWifiService).setAutoWakeupEnabled(true);
+
+ when(mWifiService.isAutoWakeupEnabled()).thenReturn(false);
+ assertFalse(mWifiManager.isAutoWakeupEnabled());
+ verify(mWifiService).isAutoWakeupEnabled();
+ }
+
+
+ @Test
+ public void testScanAvailable() throws Exception {
+ mWifiManager.setScanAlwaysAvailable(true);
+ verify(mWifiService).setScanAlwaysAvailable(true);
+
+ when(mWifiService.isScanAlwaysAvailable()).thenReturn(false);
+ assertFalse(mWifiManager.isScanAlwaysAvailable());
+ verify(mWifiService).isScanAlwaysAvailable();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
index b58b3215e5ea..d479aacdd296 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -35,10 +35,6 @@ import org.junit.Test;
*/
@SmallTest
public class WifiNetworkAgentSpecifierTest {
- private static final int TEST_UID = 5;
- private static final int TEST_UID_1 = 8;
- private static final String TEST_PACKAGE = "com.test";
- private static final String TEST_PACKAGE_1 = "com.test.1";
private static final String TEST_SSID = "Test123";
private static final String TEST_SSID_PATTERN = "Test";
private static final String TEST_SSID_1 = "456test";
@@ -94,15 +90,13 @@ public class WifiNetworkAgentSpecifierTest {
WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
WifiNetworkAgentSpecifier specifier1 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration1,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration1);
WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkAgentSpecifier specifier2 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration2,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration2);
assertFalse(specifier2.equals(specifier1));
}
@@ -118,15 +112,13 @@ public class WifiNetworkAgentSpecifierTest {
WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
WifiNetworkAgentSpecifier specifier1 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration1,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration1);
WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
wifiConfiguration2.SSID = TEST_SSID_1;
WifiNetworkAgentSpecifier specifier2 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration2,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration2);
assertFalse(specifier2.equals(specifier1));
}
@@ -142,15 +134,13 @@ public class WifiNetworkAgentSpecifierTest {
WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
WifiNetworkAgentSpecifier specifier1 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration1,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration1);
WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
wifiConfiguration2.BSSID = TEST_BSSID_1;
WifiNetworkAgentSpecifier specifier2 =
new WifiNetworkAgentSpecifier(
- wifiConfiguration2,
- TEST_UID, TEST_PACKAGE);
+ wifiConfiguration2);
assertFalse(specifier2.equals(specifier1));
}
@@ -197,15 +187,14 @@ public class WifiNetworkAgentSpecifierTest {
PatternMatcher ssidPattern =
new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
Pair<MacAddress, MacAddress> bssidPattern =
- Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS);
WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
wificonfigurationNetworkSpecifier.allowedKeyManagement
.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertTrue(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
assertTrue(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
@@ -233,8 +222,7 @@ public class WifiNetworkAgentSpecifierTest {
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertTrue(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
assertTrue(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
@@ -262,8 +250,7 @@ public class WifiNetworkAgentSpecifierTest {
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertTrue(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
assertTrue(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
@@ -282,21 +269,19 @@ public class WifiNetworkAgentSpecifierTest {
wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID_1 + "\"";
WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
new WifiNetworkAgentSpecifier(
- wifiConfigurationNetworkAgent,
- TEST_UID, TEST_PACKAGE);
+ wifiConfigurationNetworkAgent);
PatternMatcher ssidPattern =
new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
Pair<MacAddress, MacAddress> bssidPattern =
- Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS);
WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
wificonfigurationNetworkSpecifier.allowedKeyManagement
.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
@@ -315,8 +300,7 @@ public class WifiNetworkAgentSpecifierTest {
wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
new WifiNetworkAgentSpecifier(
- wifiConfigurationNetworkAgent,
- TEST_UID, TEST_PACKAGE);
+ wifiConfigurationNetworkAgent);
PatternMatcher ssidPattern =
new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
@@ -329,8 +313,7 @@ public class WifiNetworkAgentSpecifierTest {
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
@@ -349,8 +332,7 @@ public class WifiNetworkAgentSpecifierTest {
wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
new WifiNetworkAgentSpecifier(
- wifiConfigurationNetworkAgent,
- TEST_UID, TEST_PACKAGE);
+ wifiConfigurationNetworkAgent);
PatternMatcher ssidPattern =
new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
@@ -363,8 +345,7 @@ public class WifiNetworkAgentSpecifierTest {
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
@@ -391,41 +372,12 @@ public class WifiNetworkAgentSpecifierTest {
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
ssidPattern,
bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID, TEST_PACKAGE);
+ wificonfigurationNetworkSpecifier);
assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
}
- /**
- * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
- * a) Create network agent specifier for WPA_PSK network
- * b) Create network specifier with matching SSID and BSSID pattern, but different UID.
- * c) Ensure that the agent specifier is not satisfied by specifier.
- */
- @Test
- public void
- testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentUid() {
- WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
-
- PatternMatcher ssidPattern =
- new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
- Pair<MacAddress, MacAddress> bssidPattern =
- Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
- MacAddress.fromString(TEST_BSSID_OUI_MASK));
- WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
- wificonfigurationNetworkSpecifier.allowedKeyManagement
- .set(WifiConfiguration.KeyMgmt.WPA_PSK);
- WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
- ssidPattern,
- bssidPattern,
- wificonfigurationNetworkSpecifier,
- TEST_UID_1, TEST_PACKAGE_1);
-
- assertFalse(wifiNetworkSpecifier.canBeSatisfiedBy(wifiNetworkAgentSpecifier));
- assertFalse(wifiNetworkAgentSpecifier.canBeSatisfiedBy(wifiNetworkSpecifier));
- }
private WifiConfiguration createDefaultWifiConfiguration() {
WifiConfiguration wifiConfiguration = new WifiConfiguration();
@@ -437,8 +389,7 @@ public class WifiNetworkAgentSpecifierTest {
}
private WifiNetworkAgentSpecifier createDefaultNetworkAgentSpecifier() {
- return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(), TEST_UID,
- TEST_PACKAGE);
+ return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration());
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index 5261e7ac83e4..fc0ef469ad80 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -29,7 +29,6 @@ import android.net.MatchAllNetworkSpecifier;
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.PatternMatcher;
-import android.os.Process;
import android.util.Pair;
import androidx.test.filters.SmallTest;
@@ -41,8 +40,6 @@ import org.junit.Test;
*/
@SmallTest
public class WifiNetworkSpecifierTest {
- private static final int TEST_UID = 5;
- private static final String TEST_PACKAGE_NAME = "com.test";
private static final String TEST_SSID = "Test123";
private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
@@ -62,11 +59,12 @@ public class WifiNetworkSpecifierTest {
assertTrue(specifier instanceof WifiNetworkSpecifier);
WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
- assertEquals(Process.myUid(), wifiNetworkSpecifier.requestorUid);
assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
assertEquals(PATTERN_PREFIX, wifiNetworkSpecifier.ssidPatternMatcher.getType());
- assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.first);
- assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertEquals(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+ wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+ wifiNetworkSpecifier.bssidPatternMatcher.second);
assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.NONE));
}
@@ -210,7 +208,8 @@ public class WifiNetworkSpecifierTest {
@Test(expected = IllegalStateException.class)
public void testWifiNetworkSpecifierBuilderWithMatchAllBssidPattern() {
new WifiNetworkSpecifier.Builder()
- .setBssidPattern(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS)
+ .setBssidPattern(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+ WifiManager.ALL_ZEROS_MAC_ADDRESS)
.build();
}
@@ -265,7 +264,7 @@ public class WifiNetworkSpecifierTest {
@Test(expected = IllegalStateException.class)
public void testWifiNetworkSpecifierBuilderWithMatchNoneBssidPattern3() {
new WifiNetworkSpecifier.Builder()
- .setBssid(MacAddress.ALL_ZEROS_ADDRESS)
+ .setBssid(WifiManager.ALL_ZEROS_MAC_ADDRESS)
.build();
}
@@ -364,8 +363,7 @@ public class WifiNetworkSpecifierTest {
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
Parcel parcelW = Parcel.obtain();
specifier.writeToParcel(parcelW, 0);
@@ -384,11 +382,11 @@ public class WifiNetworkSpecifierTest {
/**
* Validate NetworkSpecifier matching.
* a) Create a network specifier for WPA_PSK network
- * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier}
+ * b) Ensure that the specifier does not match {@code null} and {@link MatchAllNetworkSpecifier}
* specifiers.
*/
@Test
- public void testWifiNetworkSpecifierSatisfiesNullAndAllMatch() {
+ public void testWifiNetworkSpecifierDoesNotSatisfyNullAndAllMatch() {
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
@@ -396,11 +394,10 @@ public class WifiNetworkSpecifierTest {
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
- assertTrue(specifier.canBeSatisfiedBy(null));
- assertTrue(specifier.canBeSatisfiedBy(new MatchAllNetworkSpecifier()));
+ assertFalse(specifier.canBeSatisfiedBy(null));
+ assertFalse(specifier.canBeSatisfiedBy(new MatchAllNetworkSpecifier()));
}
/**
@@ -419,15 +416,13 @@ public class WifiNetworkSpecifierTest {
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
WifiNetworkSpecifier specifier2 =
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
assertTrue(specifier2.canBeSatisfiedBy(specifier1));
}
@@ -448,8 +443,7 @@ public class WifiNetworkSpecifierTest {
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration1,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration1);
WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
@@ -457,8 +451,7 @@ public class WifiNetworkSpecifierTest {
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration2,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration2);
assertFalse(specifier2.canBeSatisfiedBy(specifier1));
}
@@ -479,15 +472,13 @@ public class WifiNetworkSpecifierTest {
new WifiNetworkSpecifier(new PatternMatcher("", PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
WifiNetworkSpecifier specifier2 =
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
assertFalse(specifier2.canBeSatisfiedBy(specifier1));
}
@@ -508,43 +499,13 @@ public class WifiNetworkSpecifierTest {
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
+ wifiConfiguration);
WifiNetworkSpecifier specifier2 =
new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
- Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
-
- assertFalse(specifier2.canBeSatisfiedBy(specifier1));
- }
-
- /**
- * Validate NetworkSpecifier matching.
- * a) Create network specifier 1 for WPA_PSK network
- * b) Create network specifier 2 with different package name .
- * c) Ensure that the specifier 2 is not satisfied by specifier 1.
- */
- @Test
- public void testWifiNetworkSpecifierDoesNotSatisfyWhenPackageNameDifferent() {
- WifiConfiguration wifiConfiguration = new WifiConfiguration();
- wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
- wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
-
- WifiNetworkSpecifier specifier1 =
- new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
- Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
- MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME);
-
- WifiNetworkSpecifier specifier2 =
- new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
- Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
- MacAddress.fromString(TEST_BSSID_OUI_MASK)),
- wifiConfiguration,
- TEST_UID, TEST_PACKAGE_NAME + "blah");
+ Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+ WifiManager.ALL_ZEROS_MAC_ADDRESS),
+ wifiConfiguration);
assertFalse(specifier2.canBeSatisfiedBy(specifier1));
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 4dfa96b8c606..16b4ad08a830 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -19,8 +19,9 @@ package android.net.wifi;
import static org.junit.Assert.*;
import android.net.MacAddress;
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.PasspointTestUtils;
import android.os.Parcel;
-import android.os.Process;
import androidx.test.filters.SmallTest;
@@ -31,14 +32,13 @@ import org.junit.Test;
*/
@SmallTest
public class WifiNetworkSuggestionTest {
- private static final int TEST_UID = 45677;
- private static final int TEST_UID_OTHER = 45673;
- private static final String TEST_PACKAGE_NAME = "com.test.packagename";
- private static final String TEST_PACKAGE_NAME_OTHER = "com.test.packagenameother";
private static final String TEST_SSID = "\"Test123\"";
private static final String TEST_BSSID = "12:12:12:12:12:12";
private static final String TEST_SSID_1 = "\"Test1234\"";
private static final String TEST_PRESHARED_KEY = "Test123";
+ private static final String TEST_FQDN = "fqdn";
+ private static final String TEST_WAPI_CERT_SUITE = "suite";
+ private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
/**
* Validate correctness of WifiNetworkSuggestion object created by
@@ -52,7 +52,6 @@ public class WifiNetworkSuggestionTest {
.setIsAppInteractionRequired(true)
.build();
- assertEquals(Process.myUid(), suggestion.suggestorUid);
assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.NONE));
@@ -61,12 +60,14 @@ public class WifiNetworkSuggestionTest {
assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(-1, suggestion.wifiConfiguration.priority);
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
* Validate correctness of WifiNetworkSuggestion object created by
* {@link WifiNetworkSuggestion.Builder#build()} for WPA_EAP network which requires
- * app interaction and has a priority of zero set.
+ * app interaction, not share credential and has a priority of zero set.
*/
@Test
public void
@@ -75,6 +76,7 @@ public class WifiNetworkSuggestionTest {
.setSsid(TEST_SSID)
.setWpa2Passphrase(TEST_PRESHARED_KEY)
.setIsAppInteractionRequired(true)
+ .setCredentialSharedWithUser(false)
.setPriority(0)
.build();
@@ -88,6 +90,8 @@ public class WifiNetworkSuggestionTest {
assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(0, suggestion.wifiConfiguration.priority);
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -102,6 +106,7 @@ public class WifiNetworkSuggestionTest {
.setSsid(TEST_SSID)
.setWpa2Passphrase(TEST_PRESHARED_KEY)
.setIsUserInteractionRequired(true)
+ .setIsInitialAutojoinEnabled(false)
.setIsMetered(true)
.build();
@@ -115,6 +120,38 @@ public class WifiNetworkSuggestionTest {
assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(-1, suggestion.wifiConfiguration.priority);
+ assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isInitialAutoJoinEnabled);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkSuggestion.Builder#build()} for WPA_PSK network which requires
+ * user interaction and is not metered.
+ */
+ @Test
+ public void
+ testWifiNetworkSuggestionBuilderForWpa2PskNetworkWithNotMeteredAndReqUserInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setIsUserInteractionRequired(true)
+ .setIsInitialAutojoinEnabled(false)
+ .setIsMetered(false)
+ .build();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ suggestion.wifiConfiguration.preSharedKey);
+ assertFalse(suggestion.isAppInteractionRequired);
+ assertTrue(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_NOT_METERED,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(-1, suggestion.wifiConfiguration.priority);
+ assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -134,7 +171,9 @@ public class WifiNetworkSuggestionTest {
assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.OWE));
assertNull(suggestion.wifiConfiguration.preSharedKey);
- assertTrue(suggestion.wifiConfiguration.requirePMF);
+ assertTrue(suggestion.wifiConfiguration.requirePmf);
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -146,6 +185,8 @@ public class WifiNetworkSuggestionTest {
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
.setSsid(TEST_SSID)
.setWpa3Passphrase(TEST_PRESHARED_KEY)
+ .setCredentialSharedWithUser(true)
+ .setIsInitialAutojoinEnabled(false)
.build();
assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
@@ -153,7 +194,9 @@ public class WifiNetworkSuggestionTest {
.get(WifiConfiguration.KeyMgmt.SAE));
assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
suggestion.wifiConfiguration.preSharedKey);
- assertTrue(suggestion.wifiConfiguration.requirePMF);
+ assertTrue(suggestion.wifiConfiguration.requirePmf);
+ assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isInitialAutoJoinEnabled);
}
@@ -166,6 +209,8 @@ public class WifiNetworkSuggestionTest {
WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+ enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+ enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
.setSsid(TEST_SSID)
@@ -179,10 +224,149 @@ public class WifiNetworkSuggestionTest {
.get(WifiConfiguration.GroupCipher.GCMP_256));
assertTrue(suggestion.wifiConfiguration.allowedGroupManagementCiphers
.get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
- assertTrue(suggestion.wifiConfiguration.requirePMF);
+ assertTrue(suggestion.wifiConfiguration.requirePmf);
assertNull(suggestion.wifiConfiguration.preSharedKey);
// allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
// here.
+ assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
+ }
+
+ /**
+ * Ensure create enterprise suggestion requires CA, when CA certificate is missing, will throw
+ * an exception.
+ */
+ @Test (expected = IllegalArgumentException.class)
+ public void testWifiNetworkSuggestionBuilderForEapNetworkWithoutCa() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+ enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+ enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2EnterpriseConfig(enterpriseConfig)
+ .build();
+ }
+
+ /**
+ * Ensure create enterprise suggestion requires CA, when both domain suffix and alt subject
+ * match are missing, will throw an exception.
+ */
+ @Test (expected = IllegalArgumentException.class)
+ public void testWifiNetworkSuggestionBuilderForEapNetworkWithoutMatch() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+ enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+ enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa3EnterpriseConfig(enterpriseConfig)
+ .build();
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkSuggestion.Builder#build()} for WAPI-PSK network.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWapiPskNetwork() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWapiPassphrase(TEST_PRESHARED_KEY)
+ .build();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WAPI_PSK));
+ assertTrue(suggestion.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.SMS4));
+ assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.SMS4));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ suggestion.wifiConfiguration.preSharedKey);
+ }
+
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkSuggestion.Builder#build()} for WAPI-CERT network.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWapiCertNetwork() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.WAPI_CERT);
+ enterpriseConfig.setWapiCertSuite(TEST_WAPI_CERT_SUITE);
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWapiEnterpriseConfig(enterpriseConfig)
+ .build();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WAPI_CERT));
+ assertTrue(suggestion.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.SMS4));
+ assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.SMS4));
+ assertNull(suggestion.wifiConfiguration.preSharedKey);
+ assertNotNull(suggestion.wifiConfiguration.enterpriseConfig);
+ assertEquals(WifiEnterpriseConfig.Eap.WAPI_CERT,
+ suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
+ assertEquals(TEST_WAPI_CERT_SUITE,
+ suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkSuggestion.Builder#build()} for WAPI-CERT network
+ * which selects the certificate suite automatically.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWapiCertAutoNetwork() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.WAPI_CERT);
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWapiEnterpriseConfig(enterpriseConfig)
+ .build();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WAPI_CERT));
+ assertTrue(suggestion.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.SMS4));
+ assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.SMS4));
+ assertNull(suggestion.wifiConfiguration.preSharedKey);
+ assertNotNull(suggestion.wifiConfiguration.enterpriseConfig);
+ assertEquals(WifiEnterpriseConfig.Eap.WAPI_CERT,
+ suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
+ assertEquals("",
+ suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkSuggestion.Builder#build()} for Passpoint network which requires
+ * app interaction and metered.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForPasspointNetworkWithReqAppInteractionMetered() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration)
+ .setIsAppInteractionRequired(true)
+ .setIsMetered(true)
+ .build();
+ assertEquals(TEST_FQDN, suggestion.wifiConfiguration.FQDN);
+ assertTrue(suggestion.isAppInteractionRequired);
+ assertEquals(suggestion.wifiConfiguration.meteredOverride,
+ WifiConfiguration.METERED_OVERRIDE_METERED);
+ assertEquals(suggestion.getPasspointConfig().getMeteredOverride(),
+ WifiConfiguration.METERED_OVERRIDE_METERED);
+ assertTrue(suggestion.isUserAllowedToManuallyConnect);
}
/**
@@ -209,6 +393,18 @@ public class WifiNetworkSuggestionTest {
}
/**
+ * Ensure {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)}}
+ * throws an exception when the PasspointConfiguration is not valid.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testWifiNetworkSuggestionBuilderSetPasspointConfigWithNonValid() {
+ PasspointConfiguration passpointConfiguration = new PasspointConfiguration();
+ new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+ }
+
+ /**
* Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
* when {@link WifiNetworkSuggestion.Builder#setSsid(String)} is not set.
*/
@@ -251,7 +447,7 @@ public class WifiNetworkSuggestionTest {
public void testWifiNetworkSuggestionBuilderWithInvalidAllZeroBssid() {
new WifiNetworkSuggestion.Builder()
.setSsid(TEST_SSID)
- .setBssid(MacAddress.ALL_ZEROS_ADDRESS)
+ .setBssid(WifiManager.ALL_ZEROS_MAC_ADDRESS)
.build();
}
@@ -311,6 +507,91 @@ public class WifiNetworkSuggestionTest {
}
/**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when both {@link WifiNetworkSuggestion.Builder#setSsid(String)} and
+ * {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBothSsidAndPasspointConfig() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when both {@link WifiNetworkSuggestion.Builder#setWpa2Passphrase(String)} and
+ * {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBothWpa2PassphraseAndPasspointConfig() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ new WifiNetworkSuggestion.Builder()
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when both {@link WifiNetworkSuggestion.Builder#setWpa3Passphrase(String)} and
+ * {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBothWpa3PassphraseAndPasspointConfig() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ new WifiNetworkSuggestion.Builder()
+ .setWpa3Passphrase(TEST_PRESHARED_KEY)
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when both {@link WifiNetworkSuggestion.Builder#setWpa3EnterpriseConfig(WifiEnterpriseConfig)}
+ * and {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} are
+ * invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBothEnterpriseAndPasspointConfig() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ new WifiNetworkSuggestion.Builder()
+ .setWpa3EnterpriseConfig(new WifiEnterpriseConfig())
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when both {@link WifiNetworkSuggestion.Builder#setIsEnhancedOpen(boolean)} and
+ * {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBothEnhancedOpenAndPasspointConfig() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ new WifiNetworkSuggestion.Builder()
+ .setIsEnhancedOpen(true)
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when both {@link WifiNetworkSuggestion.Builder#setIsHiddenSsid(boolean)} and
+ * {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBothHiddenSsidAndPasspointConfig() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ new WifiNetworkSuggestion.Builder()
+ .setIsHiddenSsid(true)
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+ }
+
+ /**
* Check that parcel marshalling/unmarshalling works
*/
@Test
@@ -319,8 +600,8 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
- WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, false, true, TEST_UID, TEST_PACKAGE_NAME);
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
+ configuration, null, false, true, true, true);
Parcel parcelW = Parcel.obtain();
suggestion.writeToParcel(parcelW, 0);
@@ -337,10 +618,47 @@ public class WifiNetworkSuggestionTest {
// SSID + keyMgmt + same UID). |isAppInteractionRequired| & |isUserInteractionRequired| are
// not considered for equality and hence needs to be checked for explicitly below.
assertEquals(suggestion, parcelSuggestion);
+ assertEquals(suggestion.hashCode(), parcelSuggestion.hashCode());
assertEquals(suggestion.isAppInteractionRequired,
parcelSuggestion.isAppInteractionRequired);
assertEquals(suggestion.isUserInteractionRequired,
parcelSuggestion.isUserInteractionRequired);
+ assertEquals(suggestion.isInitialAutoJoinEnabled,
+ parcelSuggestion.isInitialAutoJoinEnabled);
+ }
+
+ /**
+ * Check that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testPasspointNetworkSuggestionParcel() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+
+ Parcel parcelW = Parcel.obtain();
+ suggestion.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkSuggestion parcelSuggestion =
+ WifiNetworkSuggestion.CREATOR.createFromParcel(parcelR);
+
+ // Two suggestion objects are considered equal if they point to the same network (i.e same
+ // SSID + keyMgmt + same UID). |isAppInteractionRequired| & |isUserInteractionRequired| are
+ // not considered for equality and hence needs to be checked for explicitly below.
+ assertEquals(suggestion, parcelSuggestion);
+ assertEquals(suggestion.hashCode(), parcelSuggestion.hashCode());
+ assertEquals(suggestion.isAppInteractionRequired,
+ parcelSuggestion.isAppInteractionRequired);
+ assertEquals(suggestion.isUserInteractionRequired,
+ parcelSuggestion.isUserInteractionRequired);
+ assertEquals(suggestion.isInitialAutoJoinEnabled,
+ parcelSuggestion.isInitialAutoJoinEnabled);
}
/**
@@ -354,18 +672,17 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, true, false, TEST_UID,
- TEST_PACKAGE_NAME);
+ new WifiNetworkSuggestion(configuration, null, true, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.BSSID = TEST_BSSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, false, true, TEST_UID,
- TEST_PACKAGE_NAME);
+ new WifiNetworkSuggestion(configuration1, null, false, true, true, true);
assertEquals(suggestion, suggestion1);
+ assertEquals(suggestion.hashCode(), suggestion1.hashCode());
}
/**
@@ -378,15 +695,13 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
- TEST_PACKAGE_NAME);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID_1;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, false, false, TEST_UID,
- TEST_PACKAGE_NAME);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
assertNotEquals(suggestion, suggestion1);
}
@@ -402,15 +717,13 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
- TEST_PACKAGE_NAME);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, false, false, TEST_UID,
- TEST_PACKAGE_NAME);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
assertNotEquals(suggestion, suggestion1);
}
@@ -425,55 +738,156 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
- TEST_PACKAGE_NAME);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, false, false, TEST_UID,
- TEST_PACKAGE_NAME);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
assertNotEquals(suggestion, suggestion1);
}
/**
- * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
- * SSID, BSSID and key mgmt, but different UID.
+ * Check NetworkSuggestion equals returns {@code true} for 2 Passpoint network suggestions with
+ * same FQDN.
*/
@Test
- public void testWifiNetworkSuggestionEqualsFailsWhenUidIsDifferent() {
- WifiConfiguration configuration = new WifiConfiguration();
- configuration.SSID = TEST_SSID;
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
- WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
- TEST_PACKAGE_NAME);
+ public void testPasspointNetworkSuggestionEqualsSameWithSameFQDN() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ PasspointConfiguration passpointConfiguration1 = PasspointTestUtils.createConfig();
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+ WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration1)
+ .build();
+ assertEquals(suggestion, suggestion1);
+ assertEquals(suggestion.hashCode(), suggestion1.hashCode());
+ }
- WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration, false, false, TEST_UID_OTHER,
- TEST_PACKAGE_NAME);
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 Passpoint network suggestions with
+ * different FQDN.
+ */
+ @Test
+ public void testPasspointNetworkSuggestionNotEqualsSameWithDifferentFQDN() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ PasspointConfiguration passpointConfiguration1 = PasspointTestUtils.createConfig();
+ passpointConfiguration1.getHomeSp().setFqdn(TEST_FQDN + 1);
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration)
+ .build();
+ WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration1)
+ .build();
assertNotEquals(suggestion, suggestion1);
}
/**
- * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
- * SSID, BSSID and key mgmt, but different package name.
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to
+ * true on a open network suggestion.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetCredentialSharedWithUserWithOpenNetwork() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setCredentialSharedWithUser(true)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when {@link WifiNetworkSuggestion.Builder#setIsInitialAutojoinEnabled(boolean)} to
+ * false on a open network suggestion.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetIsAutoJoinDisabledWithOpenNetwork() {
+ new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setIsInitialAutojoinEnabled(false)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when set both {@link WifiNetworkSuggestion.Builder#setIsInitialAutojoinEnabled(boolean)}
+ * and {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} (boolean)}
+ * to false on a network suggestion.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetIsAutoJoinDisabledWithSecureNetworkNotSharedWithUser() {
+ new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setCredentialSharedWithUser(false)
+ .setIsInitialAutojoinEnabled(false)
+ .build();
+ }
+
+ /**
+ * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the
+ * correct value to the WifiConfiguration.
*/
@Test
- public void testWifiNetworkSuggestionEqualsFailsWhenPackageNameIsDifferent() {
- WifiConfiguration configuration = new WifiConfiguration();
- configuration.SSID = TEST_SSID;
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
- WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, false, false, TEST_UID, TEST_PACKAGE_NAME);
+ public void testSetIsNetworkAsUntrusted() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setUntrusted(true)
+ .build();
+ assertTrue(suggestion.isUntrusted());
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ }
- WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
- TEST_PACKAGE_NAME_OTHER);
+ /**
+ * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the
+ * correct value to the WifiConfiguration.
+ * Also the {@link WifiNetworkSuggestion#isUserAllowedToManuallyConnect} should be false;
+ */
+ @Test
+ public void testSetIsNetworkAsUntrustedOnPasspointNetwork() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration)
+ .setUntrusted(true)
+ .build();
+ assertTrue(suggestion.isUntrusted());
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ }
- assertNotEquals(suggestion, suggestion1);
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when set {@link WifiNetworkSuggestion.Builder#setUntrusted(boolean)} to true and
+ * set {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to true
+ * together.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetCredentialSharedWithUserWithSetIsNetworkAsUntrusted() {
+ new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setCredentialSharedWithUser(true)
+ .setUntrusted(true)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when set both {@link WifiNetworkSuggestion.Builder#setIsInitialAutojoinEnabled(boolean)}
+ * and {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} (boolean)}
+ * to false on a passpoint suggestion.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetIsAutoJoinDisabledWithSecureNetworkNotSharedWithUserForPasspoint() {
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration)
+ .setCredentialSharedWithUser(false)
+ .setIsInitialAutojoinEnabled(false)
+ .build();
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index dd05b47fbd4f..b68616f560f3 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -22,8 +22,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.validateMockitoUsage;
@@ -34,6 +35,7 @@ import android.content.Context;
import android.net.wifi.WifiScanner.PnoSettings;
import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork;
import android.net.wifi.WifiScanner.ScanData;
+import android.net.wifi.WifiScanner.ScanListener;
import android.net.wifi.WifiScanner.ScanSettings;
import android.os.Bundle;
import android.os.Handler;
@@ -52,8 +54,10 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import java.util.Arrays;
+import java.util.concurrent.Executor;
/**
* Unit tests for {@link android.net.wifi.WifiScanner}.
@@ -64,19 +68,23 @@ public class WifiScannerTest {
private Context mContext;
@Mock
private IWifiScanner mService;
+ @Spy
+ private Executor mExecutor = new SynchronousExecutor();
+ @Mock
+ private ScanListener mScanListener;
+ @Mock
+ private WifiScanner.ParcelableScanData mParcelableScanData;
+ private ScanData[] mScanData = {};
private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false;
private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60;
private static final int TEST_PNOSETTINGS_MIN_2GHZ_RSSI = -70;
- private static final int TEST_PNOSETTINGS_INITIAL_SCORE_MAX = 50;
- private static final int TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS = 10;
- private static final int TEST_PNOSETTINGS_SAME_NETWORK_BONUS = 11;
- private static final int TEST_PNOSETTINGS_SECURE_BONUS = 12;
- private static final int TEST_PNOSETTINGS_BAND_5GHZ_BONUS = 13;
+ private static final int TEST_PNOSETTINGS_MIN_6GHZ_RSSI = -55;
private static final String TEST_SSID_1 = "TEST1";
private static final String TEST_SSID_2 = "TEST2";
private static final int[] TEST_FREQUENCIES_1 = {};
- private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+ private static final int[] TEST_FREQUENCIES_2 = {2500, 5124, 6245};
+ private static final String DESCRIPTION_NOT_AUTHORIZED = "Not authorized";
private WifiScanner mWifiScanner;
private TestLooper mLooper;
@@ -96,6 +104,7 @@ public class WifiScannerTest {
when(mService.getMessenger()).thenReturn(mBidirectionalAsyncChannelServer.getMessenger());
mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
mLooper.dispatchAll();
+ when(mParcelableScanData.getResults()).thenReturn(mScanData);
}
/**
@@ -112,7 +121,7 @@ public class WifiScannerTest {
@Test
public void verifyScanSettingsParcelWithBand() throws Exception {
ScanSettings writeSettings = new ScanSettings();
- writeSettings.type = WifiScanner.TYPE_LOW_POWER;
+ writeSettings.type = WifiScanner.SCAN_TYPE_LOW_POWER;
writeSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
ScanSettings readSettings = parcelWriteRead(writeSettings);
@@ -127,7 +136,7 @@ public class WifiScannerTest {
@Test
public void verifyScanSettingsParcelWithChannels() throws Exception {
ScanSettings writeSettings = new ScanSettings();
- writeSettings.type = WifiScanner.TYPE_HIGH_ACCURACY;
+ writeSettings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY;
writeSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
writeSettings.channels = new WifiScanner.ChannelSpec[] {
new WifiScanner.ChannelSpec(5),
@@ -170,11 +179,7 @@ public class WifiScannerTest {
pnoSettings.isConnected = TEST_PNOSETTINGS_IS_CONNECTED;
pnoSettings.min5GHzRssi = TEST_PNOSETTINGS_MIN_5GHZ_RSSI;
pnoSettings.min24GHzRssi = TEST_PNOSETTINGS_MIN_2GHZ_RSSI;
- pnoSettings.initialScoreMax = TEST_PNOSETTINGS_INITIAL_SCORE_MAX;
- pnoSettings.currentConnectionBonus = TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS;
- pnoSettings.sameNetworkBonus = TEST_PNOSETTINGS_SAME_NETWORK_BONUS;
- pnoSettings.secureBonus = TEST_PNOSETTINGS_SECURE_BONUS;
- pnoSettings.band5GHzBonus = TEST_PNOSETTINGS_BAND_5GHZ_BONUS;
+ pnoSettings.min6GHzRssi = TEST_PNOSETTINGS_MIN_6GHZ_RSSI;
Parcel parcel = Parcel.obtain();
pnoSettings.writeToParcel(parcel, 0);
@@ -187,13 +192,7 @@ public class WifiScannerTest {
assertEquals(TEST_PNOSETTINGS_IS_CONNECTED, pnoSettingsDeserialized.isConnected);
assertEquals(TEST_PNOSETTINGS_MIN_5GHZ_RSSI, pnoSettingsDeserialized.min5GHzRssi);
assertEquals(TEST_PNOSETTINGS_MIN_2GHZ_RSSI, pnoSettingsDeserialized.min24GHzRssi);
- assertEquals(TEST_PNOSETTINGS_INITIAL_SCORE_MAX, pnoSettingsDeserialized.initialScoreMax);
- assertEquals(TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS,
- pnoSettingsDeserialized.currentConnectionBonus);
- assertEquals(TEST_PNOSETTINGS_SAME_NETWORK_BONUS,
- pnoSettingsDeserialized.sameNetworkBonus);
- assertEquals(TEST_PNOSETTINGS_SECURE_BONUS, pnoSettingsDeserialized.secureBonus);
- assertEquals(TEST_PNOSETTINGS_BAND_5GHZ_BONUS, pnoSettingsDeserialized.band5GHzBonus);
+ assertEquals(TEST_PNOSETTINGS_MIN_6GHZ_RSSI, pnoSettingsDeserialized.min6GHzRssi);
// Test parsing of PnoNetwork
assertEquals(pnoSettings.networkList.length, pnoSettingsDeserialized.networkList.length);
@@ -244,13 +243,13 @@ public class WifiScannerTest {
/**
- * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
+ * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
* @throws Exception
*/
@Test
public void testStartScan() throws Exception {
ScanSettings scanSettings = new ScanSettings();
- WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+ ScanListener scanListener = mock(ScanListener.class);
mWifiScanner.startScan(scanSettings, scanListener);
mLooper.dispatchAll();
@@ -268,17 +267,19 @@ public class WifiScannerTest {
assertNull(messageBundle.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY));
assertEquals(mContext.getOpPackageName(),
messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
+ assertEquals(mContext.getAttributionTag(),
+ messageBundle.getParcelable(WifiScanner.REQUEST_FEATURE_ID_KEY));
}
/**
- * Test behavior of {@link WifiScanner#stopScan(WifiScanner.ScanListener)}
+ * Test behavior of {@link WifiScanner#stopScan(ScanListener)}
* @throws Exception
*/
@Test
public void testStopScan() throws Exception {
ScanSettings scanSettings = new ScanSettings();
- WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+ ScanListener scanListener = mock(ScanListener.class);
mWifiScanner.startScan(scanSettings, scanListener);
mLooper.dispatchAll();
@@ -296,17 +297,18 @@ public class WifiScannerTest {
Bundle messageBundle = (Bundle) message.obj;
assertEquals(mContext.getOpPackageName(),
messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
-
+ assertEquals(mContext.getAttributionTag(),
+ messageBundle.getParcelable(WifiScanner.REQUEST_FEATURE_ID_KEY));
}
/**
- * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
+ * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
* @throws Exception
*/
@Test
public void testStartScanListenerOnSuccess() throws Exception {
ScanSettings scanSettings = new ScanSettings();
- WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+ ScanListener scanListener = mock(ScanListener.class);
mWifiScanner.startScan(scanSettings, scanListener);
mLooper.dispatchAll();
@@ -330,13 +332,13 @@ public class WifiScannerTest {
}
/**
- * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
+ * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
* @throws Exception
*/
@Test
public void testStartScanListenerOnResults() throws Exception {
ScanSettings scanSettings = new ScanSettings();
- WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+ ScanListener scanListener = mock(ScanListener.class);
mWifiScanner.startScan(scanSettings, scanListener);
mLooper.dispatchAll();
@@ -364,7 +366,7 @@ public class WifiScannerTest {
/**
* Test behavior of {@link WifiScanner#startDisconnectedPnoScan(ScanSettings, PnoSettings,
- * WifiScanner.PnoScanListener)}
+ * Executor, WifiScanner.PnoScanListener)}
* @throws Exception
*/
@Test
@@ -373,7 +375,8 @@ public class WifiScannerTest {
PnoSettings pnoSettings = new PnoSettings();
WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class);
- mWifiScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, pnoScanListener);
+ mWifiScanner.startDisconnectedPnoScan(
+ scanSettings, pnoSettings, mock(Executor.class), pnoScanListener);
mLooper.dispatchAll();
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
@@ -394,7 +397,7 @@ public class WifiScannerTest {
/**
* Test behavior of {@link WifiScanner#startConnectedPnoScan(ScanSettings, PnoSettings,
- * WifiScanner.PnoScanListener)}
+ * Executor, WifiScanner.PnoScanListener)}
* @throws Exception
*/
@Test
@@ -403,7 +406,8 @@ public class WifiScannerTest {
PnoSettings pnoSettings = new PnoSettings();
WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class);
- mWifiScanner.startConnectedPnoScan(scanSettings, pnoSettings, pnoScanListener);
+ mWifiScanner.startConnectedPnoScan(
+ scanSettings, pnoSettings, mock(Executor.class), pnoScanListener);
mLooper.dispatchAll();
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
@@ -423,8 +427,8 @@ public class WifiScannerTest {
}
/**
- * Test behavior of {@link WifiScanner#stopPnoScan(WifiScanner.ScanListener)}
- * WifiScanner.PnoScanListener)}
+ * Test behavior of {@link WifiScanner#stopPnoScan(ScanListener)}
+ * Executor, WifiScanner.PnoScanListener)}
* @throws Exception
*/
@Test
@@ -433,7 +437,8 @@ public class WifiScannerTest {
PnoSettings pnoSettings = new PnoSettings();
WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class);
- mWifiScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, pnoScanListener);
+ mWifiScanner.startDisconnectedPnoScan(
+ scanSettings, pnoSettings, mock(Executor.class), pnoScanListener);
mLooper.dispatchAll();
mWifiScanner.stopPnoScan(pnoScanListener);
mLooper.dispatchAll();
@@ -445,4 +450,185 @@ public class WifiScannerTest {
assertEquals(WifiScanner.CMD_STOP_PNO_SCAN, message.what);
}
+
+ @Test
+ public void testScanDataAddResults() throws Exception {
+ ScanResult scanResult1 = new ScanResult();
+ scanResult1.SSID = TEST_SSID_1;
+ ScanData scanData = new ScanData(0, 0, new ScanResult[]{scanResult1});
+
+ ScanResult scanResult2 = new ScanResult();
+ scanResult2.SSID = TEST_SSID_2;
+ scanData.addResults(new ScanResult[]{scanResult2});
+
+ ScanResult[] consolidatedScanResults = scanData.getResults();
+ assertEquals(2, consolidatedScanResults.length);
+ assertEquals(TEST_SSID_1, consolidatedScanResults[0].SSID);
+ assertEquals(TEST_SSID_2, consolidatedScanResults[1].SSID);
+ }
+
+ @Test
+ public void testScanDataParcel() throws Exception {
+ ScanResult scanResult1 = new ScanResult();
+ scanResult1.SSID = TEST_SSID_1;
+ ScanData scanData = new ScanData(5, 4, new ScanResult[]{scanResult1});
+
+ Parcel parcel = Parcel.obtain();
+ scanData.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ ScanData readScanData = ScanData.CREATOR.createFromParcel(parcel);
+
+ assertEquals(scanData.getId(), readScanData.getId());
+ assertEquals(scanData.getFlags(), readScanData.getFlags());
+ assertEquals(scanData.getResults().length, readScanData.getResults().length);
+ assertEquals(scanData.getResults()[0].SSID, readScanData.getResults()[0].SSID);
+ }
+
+ /** Tests that upon registration success, {@link ScanListener#onSuccess()} is called. */
+ @Test
+ public void testRegisterScanListenerSuccess() throws Exception {
+ mWifiScanner.registerScanListener(mExecutor, mScanListener);
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mHandler).handleMessage(messageArgumentCaptor.capture());
+ Message sentMessage = messageArgumentCaptor.getValue();
+ assertNotNull(sentMessage);
+
+ assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+ Messenger scannerMessenger =
+ mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_OP_SUCCEEDED;
+ responseMessage.arg2 = sentMessage.arg2;
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+
+ verify(mExecutor).execute(any());
+ verify(mScanListener).onSuccess();
+ }
+
+ /**
+ * Tests that upon registration failed, {@link ScanListener#onFailure(int, String)} is called.
+ */
+ @Test
+ public void testRegisterScanListenerFailed() throws Exception {
+ mWifiScanner.registerScanListener(mExecutor, mScanListener);
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mHandler).handleMessage(messageArgumentCaptor.capture());
+ Message sentMessage = messageArgumentCaptor.getValue();
+ assertNotNull(sentMessage);
+
+ assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+ Messenger scannerMessenger =
+ mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+ {
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_OP_FAILED;
+ responseMessage.arg2 = sentMessage.arg2;
+ responseMessage.obj = new WifiScanner.OperationResult(
+ WifiScanner.REASON_NOT_AUTHORIZED, DESCRIPTION_NOT_AUTHORIZED);
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+ }
+
+ verify(mExecutor).execute(any());
+ verify(mScanListener).onFailure(
+ WifiScanner.REASON_NOT_AUTHORIZED, DESCRIPTION_NOT_AUTHORIZED);
+
+ // CMD_OP_FAILED should have caused the removal of the listener, verify this
+ {
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
+ responseMessage.arg2 = sentMessage.arg2;
+ responseMessage.obj = mParcelableScanData;
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+ }
+ // execute() called once before, not called again
+ verify(mExecutor, times(1)).execute(any());
+ // onResults() never triggered
+ verify(mScanListener, never()).onResults(any());
+ }
+
+ /**
+ * Tests that when the ScanListener is triggered, {@link ScanListener#onResults(ScanData[])}
+ * is called.
+ */
+ @Test
+ public void testRegisterScanListenerReceiveScanResults() throws Exception {
+ mWifiScanner.registerScanListener(mExecutor, mScanListener);
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mHandler).handleMessage(messageArgumentCaptor.capture());
+ Message sentMessage = messageArgumentCaptor.getValue();
+ assertNotNull(sentMessage);
+
+ assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+ Messenger scannerMessenger =
+ mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
+ responseMessage.arg2 = sentMessage.arg2;
+ responseMessage.obj = mParcelableScanData;
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+
+ verify(mExecutor).execute(any());
+ verify(mScanListener).onResults(mScanData);
+ }
+
+ /**
+ * Tests that after unregistering a scan listener, {@link ScanListener#onResults(ScanData[])}
+ * is not called.
+ */
+ @Test
+ public void testUnregisterScanListener() throws Exception {
+ mWifiScanner.registerScanListener(mExecutor, mScanListener);
+ mWifiScanner.unregisterScanListener(mScanListener);
+ mLooper.dispatchAll();
+
+ assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+ Messenger scannerMessenger =
+ mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mHandler, times(2)).handleMessage(messageArgumentCaptor.capture());
+ Message sentMessage = messageArgumentCaptor.getValue();
+ assertNotNull(sentMessage);
+
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
+ responseMessage.obj = mParcelableScanData;
+ responseMessage.arg2 = sentMessage.arg2;
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+
+ verify(mExecutor, never()).execute(any());
+ verify(mScanListener, never()).onResults(mScanData);
+ }
+
+ /**
+ * Tests isFullBandScan() method with and without DFS check
+ */
+ @Test
+ public void testIsFullBandScan() throws Exception {
+ assertFalse(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_24_GHZ, true));
+ assertFalse(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_5_GHZ, true));
+ assertFalse(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_6_GHZ, true));
+ assertFalse(WifiScanner.isFullBandScan(
+ WifiScanner.WIFI_BAND_6_GHZ | WifiScanner.WIFI_BAND_5_GHZ, true));
+ assertTrue(WifiScanner.isFullBandScan(
+ WifiScanner.WIFI_BAND_24_GHZ | WifiScanner.WIFI_BAND_5_GHZ, true));
+ assertFalse(WifiScanner.isFullBandScan(
+ WifiScanner.WIFI_BAND_24_GHZ | WifiScanner.WIFI_BAND_5_GHZ, false));
+ assertTrue(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, true));
+ assertTrue(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, false));
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
index 1b48a67e9f55..b65de6b9789d 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
@@ -171,6 +171,6 @@ public class WifiAwareAgentNetworkSpecifierTest {
WifiAwareNetworkSpecifier getMockNetworkSpecifier(int clientId) {
return new WifiAwareNetworkSpecifier(WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, clientId, 0, 0, new byte[6],
- null, null, 10, 5, 0);
+ null, null, 10, 5);
}
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 7bc5f6260816..43d728bf593e 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -36,6 +36,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.MacAddress;
import android.net.wifi.RttManager;
+import android.net.wifi.util.HexEncoding;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -44,8 +45,6 @@ import android.os.test.TestLooper;
import androidx.test.filters.SmallTest;
-import libcore.util.HexEncoding;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -168,7 +167,7 @@ public class WifiAwareManagerTest {
// (1) connect + success
mDut.attach(mockCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).connect(binder.capture(), any(),
+ inOrder.verify(mockAwareService).connect(binder.capture(), any(), any(),
clientProxyCallback.capture(), isNull(), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -178,7 +177,8 @@ public class WifiAwareManagerTest {
// (2) publish - should succeed
PublishConfig publishConfig = new PublishConfig.Builder().build();
session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig), any());
+ inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
+ any());
// (3) disconnect
session.close();
@@ -190,7 +190,7 @@ public class WifiAwareManagerTest {
// (5) connect
mDut.attach(mockCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).connect(binder.capture(), any(), any(), isNull(),
+ inOrder.verify(mockAwareService).connect(binder.capture(), any(), any(), any(), isNull(),
eq(false));
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
@@ -212,7 +212,7 @@ public class WifiAwareManagerTest {
// (1) connect + failure
mDut.attach(mockCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
isNull(), eq(false));
clientProxyCallback.getValue().onConnectFail(reason);
mMockLooper.dispatchAll();
@@ -220,7 +220,7 @@ public class WifiAwareManagerTest {
// (2) connect + success
mDut.attach(mockCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
isNull(), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -230,7 +230,8 @@ public class WifiAwareManagerTest {
// (4) subscribe: should succeed
SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig), any());
+ inOrder.verify(mockAwareService).subscribe(any(), any(), eq(clientId), eq(subscribeConfig),
+ any());
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
}
@@ -249,7 +250,7 @@ public class WifiAwareManagerTest {
// (1) connect + success
mDut.attach(mockCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
isNull(), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -257,7 +258,7 @@ public class WifiAwareManagerTest {
// (2) connect + success
mDut.attach(mockCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
isNull(), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId + 1);
mMockLooper.dispatchAll();
@@ -304,7 +305,7 @@ public class WifiAwareManagerTest {
// (0) connect + success
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -313,7 +314,7 @@ public class WifiAwareManagerTest {
// (1) publish
session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+ inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
sessionProxyCallback.capture());
// (2) publish session created
@@ -396,7 +397,7 @@ public class WifiAwareManagerTest {
// (1) connect successfully
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -405,7 +406,7 @@ public class WifiAwareManagerTest {
// (2) publish: successfully - then terminated
session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+ inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
sessionProxyCallback.capture());
sessionProxyCallback.getValue().onSessionStarted(sessionId);
sessionProxyCallback.getValue().onSessionTerminated(0);
@@ -453,7 +454,7 @@ public class WifiAwareManagerTest {
// (0) connect + success
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -462,7 +463,7 @@ public class WifiAwareManagerTest {
// (1) subscribe
session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig),
+ inOrder.verify(mockAwareService).subscribe(any(), any(), eq(clientId), eq(subscribeConfig),
sessionProxyCallback.capture());
// (2) subscribe session created
@@ -538,7 +539,7 @@ public class WifiAwareManagerTest {
// (1) connect successfully
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -547,7 +548,7 @@ public class WifiAwareManagerTest {
// (2) subscribe: successfully - then terminated
session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig),
+ inOrder.verify(mockAwareService).subscribe(any(), any(), eq(clientId), eq(subscribeConfig),
sessionProxyCallback.capture());
sessionProxyCallback.getValue().onSessionStarted(sessionId);
sessionProxyCallback.getValue().onSessionTerminated(0);
@@ -577,12 +578,15 @@ public class WifiAwareManagerTest {
collector.checkThat("mMasterPreference", 0,
equalTo(configRequest.mMasterPreference));
collector.checkThat("mSupport5gBand", true, equalTo(configRequest.mSupport5gBand));
- collector.checkThat("mDiscoveryWindowInterval.length", 2,
+ collector.checkThat("mSupport6gBand", false, equalTo(configRequest.mSupport6gBand));
+ collector.checkThat("mDiscoveryWindowInterval.length", 3,
equalTo(configRequest.mDiscoveryWindowInterval.length));
collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
collector.checkThat("mDiscoveryWindowInterval[5Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
+ collector.checkThat("mDiscoveryWindowInterval[6Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_6GHZ]));
}
@Test
@@ -591,12 +595,16 @@ public class WifiAwareManagerTest {
final int clusterLow = 5;
final int masterPreference = 55;
final boolean supportBand5g = true;
+ final boolean supportBand6g = true;
final int dwWindow5GHz = 3;
+ final int dwWindow6GHz = 4;
ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
.setClusterLow(clusterLow).setMasterPreference(masterPreference)
.setSupport5gBand(supportBand5g)
+ .setSupport6gBand(supportBand6g)
.setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz)
.build();
collector.checkThat("mClusterHigh", clusterHigh, equalTo(configRequest.mClusterHigh));
@@ -604,12 +612,15 @@ public class WifiAwareManagerTest {
collector.checkThat("mMasterPreference", masterPreference,
equalTo(configRequest.mMasterPreference));
collector.checkThat("mSupport5gBand", supportBand5g, equalTo(configRequest.mSupport5gBand));
- collector.checkThat("mDiscoveryWindowInterval.length", 2,
+ collector.checkThat("mSupport6gBand", supportBand6g, equalTo(configRequest.mSupport6gBand));
+ collector.checkThat("mDiscoveryWindowInterval.length", 3,
equalTo(configRequest.mDiscoveryWindowInterval.length));
collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
collector.checkThat("mDiscoveryWindowInterval[5GHz]", dwWindow5GHz,
equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
+ collector.checkThat("mDiscoveryWindowInterval[6GHz]", dwWindow6GHz,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_6GHZ]));
}
@Test(expected = IllegalArgumentException.class)
@@ -688,14 +699,18 @@ public class WifiAwareManagerTest {
final int clusterLow = 25;
final int masterPreference = 177;
final boolean supportBand5g = true;
+ final boolean supportBand6g = false;
final int dwWindow24GHz = 1;
final int dwWindow5GHz = 5;
+ final int dwWindow6GHz = 4;
ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
.setClusterLow(clusterLow).setMasterPreference(masterPreference)
.setSupport5gBand(supportBand5g)
+ .setSupport6gBand(supportBand6g)
.setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwWindow24GHz)
.setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz)
.build();
Parcel parcelW = Parcel.obtain();
@@ -942,7 +957,7 @@ public class WifiAwareManagerTest {
// (1) connect successfully
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -951,7 +966,7 @@ public class WifiAwareManagerTest {
// (2) publish successfully
session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+ inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
sessionProxyCallback.capture());
sessionProxyCallback.getValue().onSessionStarted(sessionId);
mMockLooper.dispatchAll();
@@ -1055,7 +1070,7 @@ public class WifiAwareManagerTest {
// (1) connect successfully
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -1239,7 +1254,7 @@ public class WifiAwareManagerTest {
// (1) connect successfully
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -1248,7 +1263,7 @@ public class WifiAwareManagerTest {
// (2) publish successfully
session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+ inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
sessionProxyCallback.capture());
sessionProxyCallback.getValue().onSessionStarted(sessionId);
mMockLooper.dispatchAll();
@@ -1474,7 +1489,7 @@ public class WifiAwareManagerTest {
// (1) connect successfully
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -1514,7 +1529,7 @@ public class WifiAwareManagerTest {
// (1) connect successfully
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+ inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
eq(configRequest), eq(false));
clientProxyCallback.getValue().onConnectSuccess(clientId);
mMockLooper.dispatchAll();
@@ -1524,7 +1539,7 @@ public class WifiAwareManagerTest {
if (isPublish) {
// (2) publish successfully
session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+ inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
sessionProxyCallback.capture());
sessionProxyCallback.getValue().onSessionStarted(sessionId);
mMockLooper.dispatchAll();
@@ -1533,8 +1548,8 @@ public class WifiAwareManagerTest {
} else {
// (2) subscribe successfully
session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig),
- sessionProxyCallback.capture());
+ inOrder.verify(mockAwareService).subscribe(any(), any(), eq(clientId),
+ eq(subscribeConfig), sessionProxyCallback.capture());
sessionProxyCallback.getValue().onSessionStarted(sessionId);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onSubscribeStarted(subscribeSession.capture());
@@ -1549,7 +1564,7 @@ public class WifiAwareManagerTest {
WifiAwareNetworkSpecifier ns = new WifiAwareNetworkSpecifier(NETWORK_SPECIFIER_TYPE_IB,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, 5, 568, 334,
HexEncoding.decode("000102030405".toCharArray(), false),
- "01234567890123456789012345678901".getBytes(), "blah blah", 666, 4, 10001);
+ "01234567890123456789012345678901".getBytes(), "blah blah", 666, 4);
Parcel parcelW = Parcel.obtain();
ns.writeToParcel(parcelW, 0);
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
index d9a1d9afff61..439e67259cb9 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
@@ -54,6 +54,8 @@ public class ConfigParserTest {
"assets/hsr1/HSR1ProfileWithInvalidContentType.base64";
private static final String PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE =
"assets/hsr1/HSR1ProfileWithoutProfile.base64";
+ private static final String PASSPOINT_INSTALLATION_FILE_WITH_UPDATE_ID =
+ "assets/hsr1/HSR1ProfileWithUpdateIdentifier.base64";
/**
* Read the content of the given resource file into a String.
@@ -85,17 +87,17 @@ public class ConfigParserTest {
// HomeSP configuration.
HomeSp homeSp = new HomeSp();
- homeSp.setFriendlyName("Century House");
- homeSp.setFqdn("mi6.co.uk");
+ homeSp.setFriendlyName("Example Network");
+ homeSp.setFqdn("hotspot.example.net");
homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
config.setHomeSp(homeSp);
// Credential configuration.
Credential credential = new Credential();
- credential.setRealm("shaken.stirred.com");
+ credential.setRealm("example.com");
Credential.UserCredential userCredential = new Credential.UserCredential();
- userCredential.setUsername("james");
- userCredential.setPassword("Ym9uZDAwNw==");
+ userCredential.setUsername("user");
+ userCredential.setPassword("cGFzc3dvcmQ=");
userCredential.setEapType(21);
userCredential.setNonEapInnerMethod("MS-CHAP-V2");
credential.setUserCredential(userCredential);
@@ -106,8 +108,8 @@ public class ConfigParserTest {
certCredential.setCertSha256Fingerprint(certSha256Fingerprint);
credential.setCertCredential(certCredential);
Credential.SimCredential simCredential = new Credential.SimCredential();
- simCredential.setImsi("imsi");
- simCredential.setEapType(24);
+ simCredential.setImsi("123456*");
+ simCredential.setEapType(23);
credential.setSimCredential(simCredential);
credential.setCaCertificate(FakeKeys.CA_CERT0);
config.setCredential(credential);
@@ -201,4 +203,21 @@ public class ConfigParserTest {
assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
+
+ /**
+ * Verify a valid installation file is parsed successfully with the matching contents, and that
+ * Update identifier is cleared.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseConfigFileWithUpdateIdentifier() throws Exception {
+ String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_UPDATE_ID);
+ PasspointConfiguration expectedConfig = generateConfigurationFromProfile();
+ PasspointConfiguration actualConfig =
+ ConfigParser.parsePasspointConfig(
+ "application/x-wifi-config", configStr.getBytes());
+ // Expected configuration does not contain an update identifier
+ assertTrue(actualConfig.equals(expectedConfig));
+ }
} \ No newline at end of file
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
index c7e009ee9864..2ded849331d7 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
@@ -19,7 +19,6 @@ package android.net.wifi.hotspot2;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.wifi.WifiSsid;
import android.os.Parcel;
@@ -56,7 +55,6 @@ public class OsuProviderTest {
private static final String TEST_NAI = "test.access.com";
private static final List<Integer> TEST_METHOD_LIST =
Arrays.asList(OsuProvider.METHOD_SOAP_XML_SPP);
- private static final Icon TEST_ICON = Icon.createWithData(new byte[10], 0, 10);
/**
* Verify parcel write and read consistency for the given {@link OsuProvider}.
@@ -82,7 +80,7 @@ public class OsuProviderTest {
*/
@Test
public void verifyParcelWithEmptyProviderInfo() throws Exception {
- verifyParcel(new OsuProvider(null, null, null, null, null, null, null));
+ verifyParcel(new OsuProvider((WifiSsid) null, null, null, null, null, null));
}
/**
@@ -93,7 +91,7 @@ public class OsuProviderTest {
@Test
public void verifyParcelWithFullProviderInfo() throws Exception {
verifyParcel(new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
- TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON));
+ TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST));
}
/**
@@ -102,7 +100,7 @@ public class OsuProviderTest {
*/
@Test
public void verifyCopyConstructorWithNullSource() throws Exception {
- OsuProvider expected = new OsuProvider(null, null, null, null, null, null, null);
+ OsuProvider expected = new OsuProvider((WifiSsid) null, null, null, null, null, null);
assertEquals(expected, new OsuProvider(null));
}
@@ -114,7 +112,7 @@ public class OsuProviderTest {
@Test
public void verifyCopyConstructorWithValidSource() throws Exception {
OsuProvider source = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
- TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+ TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST);
assertEquals(source, new OsuProvider(source));
}
@@ -126,7 +124,7 @@ public class OsuProviderTest {
@Test
public void verifyGetters() throws Exception {
OsuProvider provider = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
- TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+ TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST);
assertTrue(TEST_SSID.equals(provider.getOsuSsid()));
assertTrue(TEST_FRIENDLY_NAME.equals(provider.getFriendlyName()));
@@ -135,6 +133,5 @@ public class OsuProviderTest {
assertTrue(TEST_SERVER_URI.equals(provider.getServerUri()));
assertTrue(TEST_NAI.equals(provider.getNetworkAccessIdentifier()));
assertTrue(TEST_METHOD_LIST.equals(provider.getMethodList()));
- assertTrue(TEST_ICON.sameAs(provider.getIcon()));
}
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index fc03e7eb6176..638efb9f14ee 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -16,26 +16,24 @@
package android.net.wifi.hotspot2;
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
+
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-import android.net.wifi.EAPConstants;
import android.net.wifi.hotspot2.pps.Credential;
import android.net.wifi.hotspot2.pps.HomeSp;
-import android.net.wifi.hotspot2.pps.Policy;
-import android.net.wifi.hotspot2.pps.UpdateParameter;
import android.os.Parcel;
-import android.util.Base64;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -47,134 +45,6 @@ public class PasspointConfigurationTest {
private static final int CERTIFICATE_FINGERPRINT_BYTES = 32;
/**
- * Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}.
- *
- * @return {@link android.net.wifi.hotspot2.pps.HomeSP}
- */
- private static HomeSp createHomeSp() {
- HomeSp homeSp = new HomeSp();
- homeSp.setFqdn("fqdn");
- homeSp.setFriendlyName("friendly name");
- homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
- return homeSp;
- }
-
- /**
- * Utility function for creating a {@link android.net.wifi.hotspot2.pps.Credential}.
- *
- * @return {@link android.net.wifi.hotspot2.pps.Credential}
- */
- private static Credential createCredential() {
- Credential cred = new Credential();
- cred.setRealm("realm");
- cred.setUserCredential(null);
- cred.setCertCredential(null);
- cred.setSimCredential(new Credential.SimCredential());
- cred.getSimCredential().setImsi("1234*");
- cred.getSimCredential().setEapType(EAPConstants.EAP_SIM);
- cred.setCaCertificate(null);
- cred.setClientCertificateChain(null);
- cred.setClientPrivateKey(null);
- return cred;
- }
-
- /**
- * Helper function for creating a {@link Policy} for testing.
- *
- * @return {@link Policy}
- */
- private static Policy createPolicy() {
- Policy policy = new Policy();
- policy.setMinHomeDownlinkBandwidth(123);
- policy.setMinHomeUplinkBandwidth(345);
- policy.setMinRoamingDownlinkBandwidth(567);
- policy.setMinRoamingUplinkBandwidth(789);
- policy.setMaximumBssLoadValue(12);
- policy.setExcludedSsidList(new String[] {"ssid1", "ssid2"});
- HashMap<Integer, String> requiredProtoPortMap = new HashMap<>();
- requiredProtoPortMap.put(12, "23,342,123");
- requiredProtoPortMap.put(23, "789,372,1235");
- policy.setRequiredProtoPortMap(requiredProtoPortMap);
-
- List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
- Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
- partner1.setFqdn("partner1.com");
- partner1.setFqdnExactMatch(true);
- partner1.setPriority(12);
- partner1.setCountries("us,jp");
- Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
- partner2.setFqdn("partner2.com");
- partner2.setFqdnExactMatch(false);
- partner2.setPriority(42);
- partner2.setCountries("ca,fr");
- preferredRoamingPartnerList.add(partner1);
- preferredRoamingPartnerList.add(partner2);
- policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
-
- UpdateParameter policyUpdate = new UpdateParameter();
- policyUpdate.setUpdateIntervalInMinutes(1712);
- policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
- policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
- policyUpdate.setServerUri("policy.update.com");
- policyUpdate.setUsername("username");
- policyUpdate.setBase64EncodedPassword(
- Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
- policyUpdate.setTrustRootCertUrl("trust.cert.com");
- policyUpdate.setTrustRootCertSha256Fingerprint(
- new byte[CERTIFICATE_FINGERPRINT_BYTES]);
- policy.setPolicyUpdate(policyUpdate);
-
- return policy;
- }
-
- private static UpdateParameter createSubscriptionUpdate() {
- UpdateParameter subUpdate = new UpdateParameter();
- subUpdate.setUpdateIntervalInMinutes(9021);
- subUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
- subUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
- subUpdate.setServerUri("subscription.update.com");
- subUpdate.setUsername("subUsername");
- subUpdate.setBase64EncodedPassword(
- Base64.encodeToString("subPassword".getBytes(), Base64.DEFAULT));
- subUpdate.setTrustRootCertUrl("subscription.trust.cert.com");
- subUpdate.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_FINGERPRINT_BYTES]);
- return subUpdate;
- }
- /**
- * Helper function for creating a {@link PasspointConfiguration} for testing.
- *
- * @return {@link PasspointConfiguration}
- */
- private static PasspointConfiguration createConfig() {
- PasspointConfiguration config = new PasspointConfiguration();
- config.setUpdateIdentifier(1234);
- config.setHomeSp(createHomeSp());
- config.setCredential(createCredential());
- config.setPolicy(createPolicy());
- config.setSubscriptionUpdate(createSubscriptionUpdate());
- Map<String, byte[]> trustRootCertList = new HashMap<>();
- trustRootCertList.put("trustRoot.cert1.com",
- new byte[CERTIFICATE_FINGERPRINT_BYTES]);
- trustRootCertList.put("trustRoot.cert2.com",
- new byte[CERTIFICATE_FINGERPRINT_BYTES]);
- config.setTrustRootCertList(trustRootCertList);
- config.setUpdateIdentifier(1);
- config.setCredentialPriority(120);
- config.setSubscriptionCreationTimeInMillis(231200);
- config.setSubscriptionExpirationTimeInMillis(2134232);
- config.setSubscriptionType("Gold");
- config.setUsageLimitUsageTimePeriodInMinutes(3600);
- config.setUsageLimitStartTimeInMillis(124214213);
- config.setUsageLimitDataLimit(14121);
- config.setUsageLimitTimeLimitInMinutes(78912);
- Map<String, String> friendlyNames = new HashMap<>();
- friendlyNames.put("en", "ServiceName1");
- friendlyNames.put("kr", "ServiceName2");
- config.setServiceFriendlyNames(friendlyNames);
- return config;
- }
-
- /**
* Verify parcel write and read consistency for the given configuration.
*
* @param writeConfig The configuration to verify
@@ -207,7 +77,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void verifyParcelWithFullConfiguration() throws Exception {
- verifyParcel(createConfig());
+ verifyParcel(PasspointTestUtils.createConfig());
}
/**
@@ -217,7 +87,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void verifyParcelWithoutServiceNames() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setServiceFriendlyNames(null);
verifyParcel(config);
}
@@ -229,7 +99,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void verifyParcelWithoutHomeSP() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setHomeSp(null);
verifyParcel(config);
}
@@ -241,7 +111,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void verifyParcelWithoutCredential() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setCredential(null);
verifyParcel(config);
}
@@ -253,7 +123,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void verifyParcelWithoutPolicy() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setPolicy(null);
verifyParcel(config);
}
@@ -265,7 +135,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void verifyParcelWithoutSubscriptionUpdate() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setSubscriptionUpdate(null);
verifyParcel(config);
}
@@ -278,12 +148,25 @@ public class PasspointConfigurationTest {
*/
@Test
public void verifyParcelWithoutTrustRootCertList() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setTrustRootCertList(null);
verifyParcel(config);
}
/**
+ * Verify parcel read/write for a configuration that doesn't contain AAA server trusted names
+ * list.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutAaaServerTrustedNames() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ config.setAaaServerTrustedNames(null);
+ verifyParcel(config);
+ }
+
+ /**
* Verify that a default/empty configuration is invalid.
*
* @throws Exception
@@ -294,6 +177,9 @@ public class PasspointConfigurationTest {
assertFalse(config.validate());
assertFalse(config.validateForR2());
+ assertTrue(config.isAutojoinEnabled());
+ assertTrue(config.isMacRandomizationEnabled());
+ assertTrue(config.getMeteredOverride() == METERED_OVERRIDE_NONE);
}
/**
@@ -303,10 +189,10 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateFullConfig() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
assertTrue(config.validate());
- assertTrue(config.validateForR2());
+ assertFalse(config.isOsuProvisioned());
}
/**
@@ -317,7 +203,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateFullConfigWithoutUpdateIdentifier() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setUpdateIdentifier(Integer.MIN_VALUE);
assertTrue(config.validate());
@@ -331,7 +217,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateConfigWithoutCredential() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setCredential(null);
assertFalse(config.validate());
@@ -345,7 +231,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateConfigWithoutHomeSp() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setHomeSp(null);
assertFalse(config.validate());
@@ -360,11 +246,10 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateConfigWithoutPolicy() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setPolicy(null);
assertTrue(config.validate());
- assertTrue(config.validateForR2());
}
/**
@@ -375,7 +260,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateConfigWithoutSubscriptionUpdate() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
config.setSubscriptionUpdate(null);
assertTrue(config.validate());
@@ -383,6 +268,20 @@ public class PasspointConfigurationTest {
}
/**
+ * Verify that a configuration without AAA server trusted names is valid for R1 and R2,
+ * since AAA server trusted names are optional for R1 and R2.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateConfigWithoutAaaServerTrustedNames() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ config.setAaaServerTrustedNames(null);
+
+ assertTrue(config.validate());
+ }
+
+ /**
* Verify that a configuration with a trust root certificate URL exceeding the max size
* is invalid.
*
@@ -390,7 +289,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateConfigWithInvalidTrustRootCertUrl() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
byte[] rawUrlBytes = new byte[MAX_URL_BYTES + 1];
Map<String, byte[]> trustRootCertList = new HashMap<>();
Arrays.fill(rawUrlBytes, (byte) 'a');
@@ -415,7 +314,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateConfigWithInvalidTrustRootCertFingerprint() throws Exception {
- PasspointConfiguration config = createConfig();
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
Map<String, byte[]> trustRootCertList = new HashMap<>();
trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES + 1]);
config.setTrustRootCertList(trustRootCertList);
@@ -452,8 +351,98 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateCopyConstructorWithValidSource() throws Exception {
- PasspointConfiguration sourceConfig = createConfig();
+ PasspointConfiguration sourceConfig = PasspointTestUtils.createConfig();
PasspointConfiguration copyConfig = new PasspointConfiguration(sourceConfig);
assertTrue(copyConfig.equals(sourceConfig));
}
+
+ /**
+ * Verify that a configuration containing all fields is valid for R2.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateFullR2Config() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createR2Config();
+ assertTrue(config.validate());
+ assertTrue(config.validateForR2());
+ assertTrue(config.isOsuProvisioned());
+ }
+
+ /**
+ * Verify that the unique identifier generated is identical for two instances
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueId() throws Exception {
+ PasspointConfiguration config1 = PasspointTestUtils.createConfig();
+ PasspointConfiguration config2 = PasspointTestUtils.createConfig();
+
+ assertEquals(config1.getUniqueId(), config2.getUniqueId());
+ }
+
+ /**
+ * Verify that the unique identifier generated is different for two instances with different
+ * HomeSp node
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueIdDifferentHomeSp() throws Exception {
+ PasspointConfiguration config1 = PasspointTestUtils.createConfig();
+
+ // Modify config2's RCOIs to a different set of values
+ PasspointConfiguration config2 = PasspointTestUtils.createConfig();
+ HomeSp homeSp = config2.getHomeSp();
+ homeSp.setRoamingConsortiumOis(new long[] {0xaa, 0xbb});
+ config2.setHomeSp(homeSp);
+
+ assertNotEquals(config1.getUniqueId(), config2.getUniqueId());
+ }
+
+ /**
+ * Verify that the unique identifier generated is different for two instances with different
+ * Credential node
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueIdDifferentCredential() throws Exception {
+ PasspointConfiguration config1 = PasspointTestUtils.createConfig();
+
+ // Modify config2's RCOIs to a different set of values
+ PasspointConfiguration config2 = PasspointTestUtils.createConfig();
+ Credential credential = config2.getCredential();
+ credential.setRealm("realm2.example.com");
+ credential.getSimCredential().setImsi("350460*");
+ config2.setCredential(credential);
+
+ assertNotEquals(config1.getUniqueId(), config2.getUniqueId());
+ }
+
+ /**
+ * Verify that the unique identifier API generates an exception if HomeSP is not initialized.
+ *
+ * @throws Exception
+ */
+ @Test (expected = IllegalStateException.class)
+ public void validateUniqueIdExceptionWithEmptyHomeSp() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ config.setHomeSp(null);
+ String uniqueId = config.getUniqueId();
+ }
+
+ /**
+ * Verify that the unique identifier API generates an exception if Credential is not
+ * initialized.
+ *
+ * @throws Exception
+ */
+ @Test (expected = IllegalStateException.class)
+ public void validateUniqueIdExceptionWithEmptyCredential() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ config.setCredential(null);
+ String uniqueId = config.getUniqueId();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
new file mode 100644
index 000000000000..8d55acb87f15
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2;
+
+import android.net.wifi.EAPConstants;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.net.wifi.hotspot2.pps.Policy;
+import android.net.wifi.hotspot2.pps.UpdateParameter;
+import android.util.Base64;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class PasspointTestUtils {
+ private static final int CERTIFICATE_FINGERPRINT_BYTES = 32;
+
+ /**
+ * Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}.
+ *
+ * @return {@link android.net.wifi.hotspot2.pps.HomeSP}
+ */
+ private static HomeSp createHomeSp() {
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn("fqdn");
+ homeSp.setFriendlyName("friendly name");
+ homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
+ return homeSp;
+ }
+
+ /**
+ * Utility function for creating a {@link android.net.wifi.hotspot2.pps.Credential}.
+ *
+ * @return {@link android.net.wifi.hotspot2.pps.Credential}
+ */
+ private static Credential createCredential() {
+ Credential cred = new Credential();
+ cred.setRealm("realm");
+ cred.setUserCredential(null);
+ cred.setCertCredential(null);
+ cred.setSimCredential(new Credential.SimCredential());
+ cred.getSimCredential().setImsi("1234*");
+ cred.getSimCredential().setEapType(EAPConstants.EAP_SIM);
+ cred.setCaCertificate(null);
+ cred.setClientCertificateChain(null);
+ cred.setClientPrivateKey(null);
+ return cred;
+ }
+
+ /**
+ * Helper function for creating a {@link Policy} for testing.
+ *
+ * @return {@link Policy}
+ */
+ private static Policy createPolicy() {
+ Policy policy = new Policy();
+ policy.setMinHomeDownlinkBandwidth(123);
+ policy.setMinHomeUplinkBandwidth(345);
+ policy.setMinRoamingDownlinkBandwidth(567);
+ policy.setMinRoamingUplinkBandwidth(789);
+ policy.setMaximumBssLoadValue(12);
+ policy.setExcludedSsidList(new String[] {"ssid1", "ssid2"});
+ HashMap<Integer, String> requiredProtoPortMap = new HashMap<>();
+ requiredProtoPortMap.put(12, "23,342,123");
+ requiredProtoPortMap.put(23, "789,372,1235");
+ policy.setRequiredProtoPortMap(requiredProtoPortMap);
+
+ List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
+ Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
+ partner1.setFqdn("partner1.com");
+ partner1.setFqdnExactMatch(true);
+ partner1.setPriority(12);
+ partner1.setCountries("us,jp");
+ Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
+ partner2.setFqdn("partner2.com");
+ partner2.setFqdnExactMatch(false);
+ partner2.setPriority(42);
+ partner2.setCountries("ca,fr");
+ preferredRoamingPartnerList.add(partner1);
+ preferredRoamingPartnerList.add(partner2);
+ policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
+
+ UpdateParameter policyUpdate = new UpdateParameter();
+ policyUpdate.setUpdateIntervalInMinutes(1712);
+ policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+ policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+ policyUpdate.setServerUri("policy.update.com");
+ policyUpdate.setUsername("username");
+ policyUpdate.setBase64EncodedPassword(
+ Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+ policyUpdate.setTrustRootCertUrl("trust.cert.com");
+ policyUpdate.setTrustRootCertSha256Fingerprint(
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ policy.setPolicyUpdate(policyUpdate);
+
+ return policy;
+ }
+
+ private static UpdateParameter createSubscriptionUpdate() {
+ UpdateParameter subUpdate = new UpdateParameter();
+ subUpdate.setUpdateIntervalInMinutes(9021);
+ subUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
+ subUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
+ subUpdate.setServerUri("subscription.update.com");
+ subUpdate.setUsername("subUsername");
+ subUpdate.setBase64EncodedPassword(
+ Base64.encodeToString("subPassword".getBytes(), Base64.DEFAULT));
+ subUpdate.setTrustRootCertUrl("subscription.trust.cert.com");
+ subUpdate.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ return subUpdate;
+ }
+ /**
+ * Helper function for creating a {@link PasspointConfiguration} for testing.
+ *
+ * @return {@link PasspointConfiguration}
+ */
+ public static PasspointConfiguration createConfig() {
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.setHomeSp(createHomeSp());
+ config.setAaaServerTrustedNames(
+ new String[] {"trusted.fqdn.com", "another-trusted.fqdn.com"});
+ config.setCredential(createCredential());
+ config.setPolicy(createPolicy());
+ config.setSubscriptionUpdate(createSubscriptionUpdate());
+ Map<String, byte[]> trustRootCertList = new HashMap<>();
+ trustRootCertList.put("trustRoot.cert1.com",
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ trustRootCertList.put("trustRoot.cert2.com",
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ config.setTrustRootCertList(trustRootCertList);
+ config.setCredentialPriority(120);
+ config.setSubscriptionCreationTimeInMillis(231200);
+ config.setSubscriptionExpirationTimeInMillis(2134232);
+ config.setSubscriptionType("Gold");
+ config.setUsageLimitUsageTimePeriodInMinutes(3600);
+ config.setUsageLimitStartTimeInMillis(124214213);
+ config.setUsageLimitDataLimit(14121);
+ config.setUsageLimitTimeLimitInMinutes(78912);
+ Map<String, String> friendlyNames = new HashMap<>();
+ friendlyNames.put("en", "ServiceName1");
+ friendlyNames.put("kr", "ServiceName2");
+ config.setServiceFriendlyNames(friendlyNames);
+ return config;
+ }
+
+ /**
+ * Helper function for creating an R2 {@link PasspointConfiguration} for testing.
+ *
+ * @return {@link PasspointConfiguration}
+ */
+ public static PasspointConfiguration createR2Config() {
+ PasspointConfiguration config = createConfig();
+ config.setUpdateIdentifier(1234);
+ return config;
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
index 66c595f92861..1ac9cb87c0e1 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
@@ -135,6 +135,9 @@ public class PpsMoParserTest {
homeSp.setOtherHomePartners(new String[] {"other.fqdn.com"});
config.setHomeSp(homeSp);
+ config.setAaaServerTrustedNames(
+ new String[] {"trusted.fqdn.com", "another-trusted.fqdn.com"});
+
// Credential configuration.
Credential credential = new Credential();
credential.setCreationTimeInMillis(format.parse("2016-01-01T10:00:00Z").getTime());
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index 0a3e989d18f0..829d8f0a9a3a 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -18,6 +18,7 @@ package android.net.wifi.hotspot2.pps;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import android.net.wifi.EAPConstants;
@@ -158,7 +159,7 @@ public class CredentialTest {
}
/**
- * Verify parcel read/write for an user credential.
+ * Verify parcel read/write for a user credential.
*
* @throws Exception
*/
@@ -176,14 +177,14 @@ public class CredentialTest {
Credential cred = createCredentialWithUserCredential();
// For R1 validation
- assertTrue(cred.validate(true));
+ assertTrue(cred.validate());
// For R2 validation
- assertTrue(cred.validate(false));
+ assertTrue(cred.validate());
}
/**
- * Verify that an user credential without CA Certificate is invalid.
+ * Verify that a user credential without CA Certificate is valid.
*
* @throws Exception
*/
@@ -192,15 +193,12 @@ public class CredentialTest {
Credential cred = createCredentialWithUserCredential();
cred.setCaCertificate(null);
- // For R1 validation
- assertFalse(cred.validate(true));
-
- // For R2 validation
- assertTrue(cred.validate(false));
+ // Accept a configuration with no CA certificate, the system will use the default cert store
+ assertTrue(cred.validate());
}
/**
- * Verify that an user credential with EAP type other than EAP-TTLS is invalid.
+ * Verify that a user credential with EAP type other than EAP-TTLS is invalid.
*
* @throws Exception
*/
@@ -210,15 +208,15 @@ public class CredentialTest {
cred.getUserCredential().setEapType(EAPConstants.EAP_TLS);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
- * Verify that an user credential without realm is invalid.
+ * Verify that a user credential without realm is invalid.
*
* @throws Exception
*/
@@ -228,14 +226,14 @@ public class CredentialTest {
cred.setRealm(null);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
- * Verify that an user credential without username is invalid.
+ * Verify that a user credential without username is invalid.
*
* @throws Exception
*/
@@ -245,14 +243,14 @@ public class CredentialTest {
cred.getUserCredential().setUsername(null);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
- * Verify that an user credential without password is invalid.
+ * Verify that a user credential without password is invalid.
*
* @throws Exception
*/
@@ -262,14 +260,14 @@ public class CredentialTest {
cred.getUserCredential().setPassword(null);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
- * Verify that an user credential without auth methoh (non-EAP inner method) is invalid.
+ * Verify that a user credential without auth methoh (non-EAP inner method) is invalid.
*
* @throws Exception
*/
@@ -279,10 +277,10 @@ public class CredentialTest {
cred.getUserCredential().setNonEapInnerMethod(null);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
@@ -297,10 +295,10 @@ public class CredentialTest {
Credential cred = createCredentialWithCertificateCredential();
// For R1 validation
- assertTrue(cred.validate(true));
+ assertTrue(cred.validate());
// For R2 validation
- assertTrue(cred.validate(true));
+ assertTrue(cred.validate());
}
/**
@@ -313,11 +311,8 @@ public class CredentialTest {
Credential cred = createCredentialWithCertificateCredential();
cred.setCaCertificate(null);
- // For R1 validation
- assertFalse(cred.validate(true));
-
- // For R2 validation
- assertTrue(cred.validate(false));
+ // Accept a configuration with no CA certificate, the system will use the default cert store
+ assertTrue(cred.validate());
}
/**
@@ -331,10 +326,10 @@ public class CredentialTest {
cred.setClientCertificateChain(null);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
@@ -348,10 +343,10 @@ public class CredentialTest {
cred.setClientPrivateKey(null);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
@@ -366,10 +361,10 @@ public class CredentialTest {
cred.getCertCredential().setCertSha256Fingerprint(new byte[32]);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
@@ -382,10 +377,10 @@ public class CredentialTest {
Credential cred = createCredentialWithSimCredential();
// For R1 validation
- assertTrue(cred.validate(true));
+ assertTrue(cred.validate());
// For R2 validation
- assertTrue(cred.validate(false));
+ assertTrue(cred.validate());
}
/**
@@ -399,10 +394,10 @@ public class CredentialTest {
cred.getSimCredential().setEapType(EAPConstants.EAP_AKA);
// For R1 validation
- assertTrue(cred.validate(true));
+ assertTrue(cred.validate());
// For R2 validation
- assertTrue(cred.validate(false));
+ assertTrue(cred.validate());
}
/**
@@ -416,10 +411,10 @@ public class CredentialTest {
cred.getSimCredential().setEapType(EAPConstants.EAP_AKA_PRIME);
// For R1 validation
- assertTrue(cred.validate(true));
+ assertTrue(cred.validate());
// For R2 validation
- assertTrue(cred.validate(false));
+ assertTrue(cred.validate());
}
/**
@@ -433,10 +428,10 @@ public class CredentialTest {
cred.getSimCredential().setImsi(null);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
@@ -450,10 +445,10 @@ public class CredentialTest {
cred.getSimCredential().setImsi("dummy");
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
@@ -467,14 +462,14 @@ public class CredentialTest {
cred.getSimCredential().setEapType(EAPConstants.EAP_TLS);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
- * Verify that a credential contained both an user and a SIM credential is invalid.
+ * Verify that a credential contained both a user and a SIM credential is invalid.
*
* @throws Exception
*/
@@ -488,10 +483,10 @@ public class CredentialTest {
cred.setSimCredential(simCredential);
// For R1 validation
- assertFalse(cred.validate(true));
+ assertFalse(cred.validate());
// For R2 validation
- assertFalse(cred.validate(false));
+ assertFalse(cred.validate());
}
/**
@@ -557,4 +552,68 @@ public class CredentialTest {
public void validateTwoCertificateDifferent() {
assertFalse(Credential.isX509CertificateEquals(FakeKeys.CA_CERT0, FakeKeys.CA_CERT1));
}
+
+ /**
+ * Verify that unique identifiers are the same for objects with the same credentials
+ */
+ @Test
+ public void testUniqueIdSameCredentialTypes() throws Exception {
+ assertEquals(createCredentialWithSimCredential().getUniqueId(),
+ createCredentialWithSimCredential().getUniqueId());
+ assertEquals(createCredentialWithCertificateCredential().getUniqueId(),
+ createCredentialWithCertificateCredential().getUniqueId());
+ assertEquals(createCredentialWithUserCredential().getUniqueId(),
+ createCredentialWithUserCredential().getUniqueId());
+ }
+
+ /**
+ * Verify that unique identifiers are different for each credential
+ */
+ @Test
+ public void testUniqueIdDifferentForDifferentCredentialTypes() throws Exception {
+ Credential simCred = createCredentialWithSimCredential();
+ Credential certCred = createCredentialWithCertificateCredential();
+ Credential userCred = createCredentialWithUserCredential();
+
+ assertNotEquals(simCred.getUniqueId(), userCred.getUniqueId());
+ assertNotEquals(simCred.getUniqueId(), certCred.getUniqueId());
+ assertNotEquals(certCred.getUniqueId(), userCred.getUniqueId());
+ }
+
+ /**
+ * Verify that unique identifiers are different for a credential with different values
+ */
+ @Test
+ public void testUniqueIdDifferentForSimCredentialsWithDifferentValues() throws Exception {
+ Credential simCred1 = createCredentialWithSimCredential();
+ Credential simCred2 = createCredentialWithSimCredential();
+ simCred2.getSimCredential().setImsi("567890*");
+
+ assertNotEquals(simCred1.getUniqueId(), simCred2.getUniqueId());
+ }
+
+ /**
+ * Verify that unique identifiers are different for a credential with different values
+ */
+ @Test
+ public void testUniqueIdDifferentForUserCredentialsWithDifferentValues() throws Exception {
+ Credential userCred1 = createCredentialWithUserCredential();
+ Credential userCred2 = createCredentialWithUserCredential();
+ userCred2.getUserCredential().setUsername("anotheruser");
+
+ assertNotEquals(userCred1.getUniqueId(), userCred2.getUniqueId());
+ }
+
+ /**
+ * Verify that unique identifiers are different for a credential with different values
+ */
+ @Test
+ public void testUniqueIdDifferentForCertCredentialsWithDifferentValues() throws Exception {
+ Credential certCred1 = createCredentialWithCertificateCredential();
+ Credential certCred2 = createCredentialWithCertificateCredential();
+ certCred2.getCertCredential().setCertSha256Fingerprint(
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CA_CERT0.getEncoded()));
+
+ assertNotEquals(certCred1.getUniqueId(), certCred2.getUniqueId());
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java b/wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java
new file mode 100644
index 000000000000..7b900fec70a8
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.wifi.ScanResult;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.nl80211.DeviceWiphyCapabilities}.
+ */
+@SmallTest
+public class DeviceWiphyCapabilitiesTest {
+ @Before
+ public void setUp() {}
+
+ /**
+ * DeviceWiphyCapabilities object can be serialized and deserialized, while keeping the
+ * values unchanged.
+ */
+ @Test
+ public void canSerializeAndDeserialize() {
+ DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities();
+
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true);
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true);
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false);
+ capa.setChannelWidthSupported(ScanResult.CHANNEL_WIDTH_160MHZ, true);
+ capa.setChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ, false);
+ capa.setMaxNumberTxSpatialStreams(2);
+ capa.setMaxNumberRxSpatialStreams(1);
+
+ Parcel parcel = Parcel.obtain();
+ capa.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ DeviceWiphyCapabilities capaDeserialized =
+ DeviceWiphyCapabilities.CREATOR.createFromParcel(parcel);
+
+ assertEquals(capa, capaDeserialized);
+ assertEquals(capa.hashCode(), capaDeserialized.hashCode());
+ }
+
+ /**
+ * Test mapping wifi standard support into channel width support
+ */
+ @Test
+ public void testMappingWifiStandardIntoChannelWidthSupport() {
+ DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities();
+
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, false);
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, false);
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false);
+ assertEquals(true, capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ));
+ assertEquals(false, capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ));
+ assertEquals(false, capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ));
+
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true);
+ assertEquals(true, capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ));
+ assertEquals(true, capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ));
+ assertEquals(false, capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ));
+
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true);
+ assertEquals(true, capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ));
+ assertEquals(true, capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ));
+ assertEquals(true, capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java b/wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java
new file mode 100644
index 000000000000..8ddd1899179a
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Unit tests for {@link android.net.wifi.nl80211.NativeScanResult}.
+ */
+@SmallTest
+public class NativeScanResultTest {
+
+ private static final byte[] TEST_SSID =
+ new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+ private static final byte[] TEST_BSSID =
+ new byte[] {(byte) 0x12, (byte) 0xef, (byte) 0xa1,
+ (byte) 0x2c, (byte) 0x97, (byte) 0x8b};
+ private static final byte[] TEST_INFO_ELEMENT =
+ new byte[] {(byte) 0x01, (byte) 0x03, (byte) 0x12, (byte) 0xbe, (byte) 0xff};
+ private static final int TEST_FREQUENCY = 2456;
+ private static final int TEST_SIGNAL_MBM = -45;
+ private static final long TEST_TSF = 34455441;
+ private static final int TEST_CAPABILITY = (0x1 << 2) | (0x1 << 5);
+ private static final boolean TEST_ASSOCIATED = true;
+ private static final int[] RADIO_CHAIN_IDS = { 0, 1 };
+ private static final int[] RADIO_CHAIN_LEVELS = { -56, -65 };
+
+ /**
+ * NativeScanResult object can be serialized and deserialized, while keeping the
+ * values unchanged.
+ */
+ @Test
+ public void canSerializeAndDeserialize() {
+ NativeScanResult scanResult = new NativeScanResult();
+ scanResult.ssid = TEST_SSID;
+ scanResult.bssid = TEST_BSSID;
+ scanResult.infoElement = TEST_INFO_ELEMENT;
+ scanResult.frequency = TEST_FREQUENCY;
+ scanResult.signalMbm = TEST_SIGNAL_MBM;
+ scanResult.tsf = TEST_TSF;
+ scanResult.capability = TEST_CAPABILITY;
+ scanResult.associated = TEST_ASSOCIATED;
+ scanResult.radioChainInfos = new ArrayList<>(Arrays.asList(
+ new RadioChainInfo(RADIO_CHAIN_IDS[0], RADIO_CHAIN_LEVELS[0]),
+ new RadioChainInfo(RADIO_CHAIN_IDS[1], RADIO_CHAIN_LEVELS[1])));
+ Parcel parcel = Parcel.obtain();
+ scanResult.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ NativeScanResult scanResultDeserialized = NativeScanResult.CREATOR.createFromParcel(parcel);
+
+ assertArrayEquals(scanResult.ssid, scanResultDeserialized.ssid);
+ assertArrayEquals(scanResult.bssid, scanResultDeserialized.bssid);
+ assertArrayEquals(scanResult.infoElement, scanResultDeserialized.infoElement);
+ assertEquals(scanResult.frequency, scanResultDeserialized.frequency);
+ assertEquals(scanResult.signalMbm, scanResultDeserialized.signalMbm);
+ assertEquals(scanResult.tsf, scanResultDeserialized.tsf);
+ assertEquals(scanResult.capability, scanResultDeserialized.capability);
+ assertEquals(scanResult.associated, scanResultDeserialized.associated);
+ assertTrue(scanResult.radioChainInfos.containsAll(scanResultDeserialized.radioChainInfos));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java b/wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java
new file mode 100644
index 000000000000..dec1db8d274e
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/**
+ * Unit tests for {@link android.net.wifi.nl80211.PnoSettings}.
+ */
+@SmallTest
+public class PnoSettingsTest {
+
+ private static final byte[] TEST_SSID_1 =
+ new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+ private static final byte[] TEST_SSID_2 =
+ new byte[] {'A', 'n', 'd', 'r', 'o', 'i', 'd', 'T', 'e', 's', 't'};
+ private static final int[] TEST_FREQUENCIES_1 = {};
+ private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+ private static final int TEST_INTERVAL_MS = 30000;
+ private static final int TEST_MIN_2G_RSSI = -60;
+ private static final int TEST_MIN_5G_RSSI = -65;
+ private static final int TEST_VALUE = 42;
+
+ private PnoNetwork mPnoNetwork1;
+ private PnoNetwork mPnoNetwork2;
+
+ @Before
+ public void setUp() {
+ mPnoNetwork1 = new PnoNetwork();
+ mPnoNetwork1.setSsid(TEST_SSID_1);
+ mPnoNetwork1.setHidden(true);
+ mPnoNetwork1.setFrequenciesMhz(TEST_FREQUENCIES_1);
+
+ mPnoNetwork2 = new PnoNetwork();
+ mPnoNetwork2.setSsid(TEST_SSID_2);
+ mPnoNetwork2.setHidden(false);
+ mPnoNetwork2.setFrequenciesMhz(TEST_FREQUENCIES_2);
+ }
+
+ /**
+ * PnoSettings object can be serialized and deserialized, while keeping the
+ * values unchanged.
+ */
+ @Test
+ public void canSerializeAndDeserialize() {
+ PnoSettings pnoSettings = new PnoSettings();
+ pnoSettings.setIntervalMillis(TEST_INTERVAL_MS);
+ pnoSettings.setMin2gRssiDbm(TEST_MIN_2G_RSSI);
+ pnoSettings.setMin5gRssiDbm(TEST_MIN_5G_RSSI);
+ pnoSettings.setPnoNetworks(new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2)));
+
+ Parcel parcel = Parcel.obtain();
+ pnoSettings.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ PnoSettings pnoSettingsDeserialized = PnoSettings.CREATOR.createFromParcel(parcel);
+
+ assertEquals(pnoSettings, pnoSettingsDeserialized);
+ assertEquals(pnoSettings.hashCode(), pnoSettingsDeserialized.hashCode());
+ }
+
+ /**
+ * Tests usage of {@link PnoSettings} as a HashMap key type.
+ */
+ @Test
+ public void testAsHashMapKey() {
+ PnoSettings pnoSettings1 = new PnoSettings();
+ pnoSettings1.setIntervalMillis(TEST_INTERVAL_MS);
+ pnoSettings1.setMin2gRssiDbm(TEST_MIN_2G_RSSI);
+ pnoSettings1.setMin5gRssiDbm(TEST_MIN_5G_RSSI);
+ pnoSettings1.setPnoNetworks(new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2)));
+
+ PnoSettings pnoSettings2 = new PnoSettings();
+ pnoSettings2.setIntervalMillis(TEST_INTERVAL_MS);
+ pnoSettings2.setMin2gRssiDbm(TEST_MIN_2G_RSSI);
+ pnoSettings2.setMin5gRssiDbm(TEST_MIN_5G_RSSI);
+ pnoSettings2.setPnoNetworks(new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2)));
+
+ assertEquals(pnoSettings1, pnoSettings2);
+ assertEquals(pnoSettings1.hashCode(), pnoSettings2.hashCode());
+
+ HashMap<PnoSettings, Integer> map = new HashMap<>();
+ map.put(pnoSettings1, TEST_VALUE);
+
+ assertEquals(TEST_VALUE, map.get(pnoSettings2).intValue());
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java b/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
new file mode 100644
index 000000000000..905920888012
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/**
+ * Unit tests for {@link android.net.wifi.nl80211.SingleScanSettingsResult}.
+ */
+@SmallTest
+public class SingleScanSettingsTest {
+
+ private static final byte[] TEST_SSID_1 =
+ new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+ private static final byte[] TEST_SSID_2 =
+ new byte[] {'A', 'n', 'd', 'r', 'o', 'i', 'd', 'T', 'e', 's', 't'};
+ private static final int TEST_FREQUENCY_1 = 2456;
+ private static final int TEST_FREQUENCY_2 = 5215;
+ private static final int TEST_VALUE = 42;
+
+ private ChannelSettings mChannelSettings1;
+ private ChannelSettings mChannelSettings2;
+ private HiddenNetwork mHiddenNetwork1;
+ private HiddenNetwork mHiddenNetwork2;
+
+ @Before
+ public void setUp() {
+ mChannelSettings1 = new ChannelSettings();
+ mChannelSettings1.frequency = TEST_FREQUENCY_1;
+ mChannelSettings2 = new ChannelSettings();
+ mChannelSettings2.frequency = TEST_FREQUENCY_2;
+
+ mHiddenNetwork1 = new HiddenNetwork();
+ mHiddenNetwork1.ssid = TEST_SSID_1;
+ mHiddenNetwork2 = new HiddenNetwork();
+ mHiddenNetwork2.ssid = TEST_SSID_2;
+ }
+
+ /**
+ * SingleScanSettings object can be serialized and deserialized, while keeping the
+ * values unchanged.
+ */
+ @Test
+ public void canSerializeAndDeserialize() {
+ SingleScanSettings scanSettings = new SingleScanSettings();
+ scanSettings.scanType = IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+
+ scanSettings.channelSettings =
+ new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
+ scanSettings.hiddenNetworks =
+ new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
+
+ Parcel parcel = Parcel.obtain();
+ scanSettings.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ SingleScanSettings scanSettingsDeserialized =
+ SingleScanSettings.CREATOR.createFromParcel(parcel);
+
+ assertEquals(scanSettings, scanSettingsDeserialized);
+ assertEquals(scanSettings.hashCode(), scanSettingsDeserialized.hashCode());
+ }
+
+ /**
+ * Tests usage of {@link SingleScanSettings} as a HashMap key type.
+ */
+ @Test
+ public void testAsHashMapKey() {
+ SingleScanSettings scanSettings1 = new SingleScanSettings();
+ scanSettings1.scanType = IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+ scanSettings1.channelSettings =
+ new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
+ scanSettings1.hiddenNetworks =
+ new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
+
+ SingleScanSettings scanSettings2 = new SingleScanSettings();
+ scanSettings2.scanType = IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+ scanSettings2.channelSettings =
+ new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
+ scanSettings2.hiddenNetworks =
+ new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
+
+ assertEquals(scanSettings1, scanSettings2);
+ assertEquals(scanSettings1.hashCode(), scanSettings2.hashCode());
+
+ HashMap<SingleScanSettings, Integer> map = new HashMap<>();
+ map.put(scanSettings1, TEST_VALUE);
+
+ assertEquals(TEST_VALUE, map.get(scanSettings2).intValue());
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
new file mode 100644
index 000000000000..9ee0acbfbaa2
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
@@ -0,0 +1,1265 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nl80211;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.app.test.TestAlarmManager;
+import android.content.Context;
+import android.net.MacAddress;
+import android.net.wifi.ScanResult;
+import android.net.wifi.SoftApInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiScanner;
+import android.net.wifi.util.HexEncoding;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.test.TestLooper;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.AdditionalMatchers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link android.net.wifi.nl80211.WifiNl80211Manager}.
+ */
+@SmallTest
+public class WifiNl80211ManagerTest {
+ @Mock
+ private IWificond mWificond;
+ @Mock
+ private IBinder mWifiCondBinder;
+ @Mock
+ private IClientInterface mClientInterface;
+ @Mock
+ private IWifiScannerImpl mWifiScannerImpl;
+ @Mock
+ private IApInterface mApInterface;
+ @Mock
+ private WifiNl80211Manager.SoftApCallback mSoftApListener;
+ @Mock
+ private WifiNl80211Manager.SendMgmtFrameCallback mSendMgmtFrameCallback;
+ @Mock
+ private WifiNl80211Manager.ScanEventCallback mNormalScanCallback;
+ @Mock
+ private WifiNl80211Manager.ScanEventCallback mPnoScanCallback;
+ @Mock
+ private WifiNl80211Manager.PnoScanRequestCallback mPnoScanRequestCallback;
+ @Mock
+ private Context mContext;
+ private TestLooper mLooper;
+ private TestAlarmManager mTestAlarmManager;
+ private AlarmManager mAlarmManager;
+ private WifiNl80211Manager mWificondControl;
+ private static final String TEST_INTERFACE_NAME = "test_wlan_if";
+ private static final String TEST_INTERFACE_NAME1 = "test_wlan_if1";
+ private static final String TEST_INVALID_INTERFACE_NAME = "asdf";
+ private static final byte[] TEST_SSID =
+ new byte[]{'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+ private static final byte[] TEST_PSK =
+ new byte[]{'T', 'e', 's', 't'};
+
+ private static final Set<Integer> SCAN_FREQ_SET =
+ new HashSet<Integer>() {{
+ add(2410);
+ add(2450);
+ add(5050);
+ add(5200);
+ }};
+ private static final String TEST_QUOTED_SSID_1 = "\"testSsid1\"";
+ private static final String TEST_QUOTED_SSID_2 = "\"testSsid2\"";
+ private static final int[] TEST_FREQUENCIES_1 = {};
+ private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+ private static final MacAddress TEST_RAW_MAC_BYTES = MacAddress.fromBytes(
+ new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05});
+
+ private static final List<byte[]> SCAN_HIDDEN_NETWORK_SSID_LIST =
+ new ArrayList<byte[]>() {{
+ add(LocalNativeUtil.byteArrayFromArrayList(
+ LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1)));
+ add(LocalNativeUtil.byteArrayFromArrayList(
+ LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2)));
+ }};
+
+ private static final PnoSettings TEST_PNO_SETTINGS = new PnoSettings();
+ static {
+ TEST_PNO_SETTINGS.setIntervalMillis(6000);
+ List<PnoNetwork> initPnoNetworks = new ArrayList<>();
+ PnoNetwork network = new PnoNetwork();
+ network.setSsid(LocalNativeUtil.byteArrayFromArrayList(
+ LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1)));
+ network.setHidden(true);
+ network.setFrequenciesMhz(TEST_FREQUENCIES_1);
+ initPnoNetworks.add(network);
+ network.setSsid(LocalNativeUtil.byteArrayFromArrayList(
+ LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2)));
+ network.setHidden(false);
+ network.setFrequenciesMhz(TEST_FREQUENCIES_2);
+ initPnoNetworks.add(network);
+ TEST_PNO_SETTINGS.setPnoNetworks(initPnoNetworks);
+ }
+
+ private static final int TEST_MCS_RATE = 5;
+ private static final int TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS = 100;
+ private static final byte[] TEST_PROBE_FRAME = {
+ 0x40, 0x00, 0x3c, 0x00, (byte) 0xa8, (byte) 0xbd, 0x27, 0x5b,
+ 0x33, 0x72, (byte) 0xf4, (byte) 0xf5, (byte) 0xe8, 0x51, (byte) 0x9e, 0x09,
+ (byte) 0xa8, (byte) 0xbd, 0x27, 0x5b, 0x33, 0x72, (byte) 0xb0, 0x66,
+ 0x00, 0x00
+ };
+
+ @Before
+ public void setUp() throws Exception {
+ // Setup mocks for successful WificondControl operation. Failure case mocks should be
+ // created in specific tests
+ MockitoAnnotations.initMocks(this);
+
+ mTestAlarmManager = new TestAlarmManager();
+ mAlarmManager = mTestAlarmManager.getAlarmManager();
+ when(mContext.getSystemServiceName(AlarmManager.class)).thenReturn(Context.ALARM_SERVICE);
+ when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
+
+ mLooper = new TestLooper();
+ when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+
+ when(mWificond.asBinder()).thenReturn(mWifiCondBinder);
+ when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
+ when(mWificond.createClientInterface(any())).thenReturn(mClientInterface);
+ when(mWificond.createApInterface(any())).thenReturn(mApInterface);
+ when(mWificond.tearDownClientInterface(any())).thenReturn(true);
+ when(mWificond.tearDownApInterface(any())).thenReturn(true);
+ when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
+ when(mClientInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ mWificondControl = new WifiNl80211Manager(mContext, mWificond);
+ assertEquals(true,
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
+ mNormalScanCallback, mPnoScanCallback));
+ }
+
+ /**
+ * Verifies that setupInterfaceForClientMode(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testSetupInterfaceForClientMode() throws Exception {
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+ verify(mWificond).createClientInterface(TEST_INTERFACE_NAME);
+ }
+
+ /**
+ * Verifies that setupInterfaceForClientMode(TEST_INTERFACE_NAME) calls subscribeScanEvents().
+ */
+ @Test
+ public void testSetupInterfaceForClientModeCallsScanEventSubscripiton() throws Exception {
+ verify(mWifiScannerImpl).subscribeScanEvents(any(IScanEvent.class));
+ }
+
+ /**
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testTeardownClientInterface() throws Exception {
+ when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME)).thenReturn(true);
+
+ assertTrue(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).unsubscribeScanEvents();
+ verify(mWifiScannerImpl).unsubscribePnoScanEvents();
+ verify(mWificond).tearDownClientInterface(TEST_INTERFACE_NAME);
+ }
+
+ /**
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testTeardownClientInterfaceOnInvalidIface() throws Exception {
+ when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME1)).thenReturn(true);
+
+ assertFalse(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME1));
+ verify(mWifiScannerImpl, never()).unsubscribeScanEvents();
+ verify(mWifiScannerImpl, never()).unsubscribePnoScanEvents();
+ verify(mWificond, never()).tearDownClientInterface(any());
+ }
+
+ /**
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testTeardownClientInterfaceFailDueToExceptionScannerUnsubscribe() throws Exception {
+ when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME)).thenReturn(true);
+ doThrow(new RemoteException()).when(mWifiScannerImpl).unsubscribeScanEvents();
+
+ assertFalse(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).unsubscribeScanEvents();
+ verify(mWifiScannerImpl, never()).unsubscribePnoScanEvents();
+ verify(mWificond, never()).tearDownClientInterface(TEST_INTERFACE_NAME);
+ }
+
+ /**
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testTeardownClientInterfaceErrorWhenWificondFailed() throws Exception {
+ when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME)).thenReturn(false);
+
+ assertFalse(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).unsubscribeScanEvents();
+ verify(mWifiScannerImpl).unsubscribePnoScanEvents();
+ verify(mWificond).tearDownClientInterface(TEST_INTERFACE_NAME);
+ }
+
+ /**
+ * Verifies that the client handles are cleared after teardown.
+ */
+ @Test
+ public void testTeardownClientInterfaceClearsHandles() throws Exception {
+ testTeardownClientInterface();
+
+ assertNull(mWificondControl.signalPoll(TEST_INTERFACE_NAME));
+ verify(mClientInterface, never()).signalPoll();
+
+ assertFalse(mWificondControl.startScan(
+ TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_LATENCY,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
+ verify(mWifiScannerImpl, never()).scan(any());
+ }
+
+ /**
+ * Verifies that setupInterfaceForSoftApMode(TEST_INTERFACE_NAME) calls wificond.
+ */
+ @Test
+ public void testSetupInterfaceForSoftApMode() throws Exception {
+ when(mWificond.createApInterface(TEST_INTERFACE_NAME)).thenReturn(mApInterface);
+
+ assertEquals(true, mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME));
+ verify(mWificond).createApInterface(TEST_INTERFACE_NAME);
+ }
+
+ /**
+ * Verifies that setupInterfaceForSoftAp() returns null when wificond is not started.
+ */
+ @Test
+ public void testSetupInterfaceForSoftApModeErrorWhenWificondIsNotStarted() throws Exception {
+ // Invoke wificond death handler to clear the handle.
+ mWificondControl.binderDied();
+ mLooper.dispatchAll();
+
+ assertEquals(false, mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME));
+ }
+
+ /**
+ * Verifies that setupInterfaceForSoftApMode(TEST_INTERFACE_NAME) returns null when wificond
+ * failed to setup AP interface.
+ */
+ @Test
+ public void testSetupInterfaceForSoftApModeErrorWhenWificondFailedToSetupInterface()
+ throws Exception {
+ when(mWificond.createApInterface(TEST_INTERFACE_NAME)).thenReturn(null);
+
+ assertEquals(false, mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME));
+ }
+
+ /**
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testTeardownSoftApInterface() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ when(mWificond.tearDownApInterface(TEST_INTERFACE_NAME)).thenReturn(true);
+
+ assertTrue(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME));
+ verify(mWificond).tearDownApInterface(TEST_INTERFACE_NAME);
+ }
+
+ /**
+ * Verifies that tearDownSoftapInterface(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testTeardownSoftApInterfaceOnInvalidIface() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ when(mWificond.tearDownApInterface(TEST_INTERFACE_NAME1)).thenReturn(true);
+
+ assertFalse(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME1));
+ verify(mWificond, never()).tearDownApInterface(any());
+ }
+
+ /**
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testTeardownSoftApInterfaceErrorWhenWificondFailed() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ when(mWificond.tearDownApInterface(TEST_INTERFACE_NAME)).thenReturn(false);
+
+ assertFalse(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME));
+ verify(mWificond).tearDownApInterface(TEST_INTERFACE_NAME);
+ }
+
+ /**
+ * Verifies that the SoftAp handles are cleared after teardown.
+ */
+ @Test
+ public void testTeardownSoftApInterfaceClearsHandles() throws Exception {
+ testTeardownSoftApInterface();
+
+ assertFalse(mWificondControl.registerApCallback(
+ TEST_INTERFACE_NAME, Runnable::run, mSoftApListener));
+ verify(mApInterface, never()).registerCallback(any());
+ }
+
+ /**
+ * Verifies that we can setup concurrent interfaces.
+ */
+ @Test
+ public void testSetupMultipleInterfaces() throws Exception {
+ when(mWificond.createApInterface(TEST_INTERFACE_NAME1)).thenReturn(mApInterface);
+
+ assertEquals(true, mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME1));
+
+ verify(mWificond).createClientInterface(TEST_INTERFACE_NAME);
+ verify(mWificond).createApInterface(TEST_INTERFACE_NAME1);
+ }
+
+ /**
+ * Verifies that we can setup concurrent interfaces.
+ */
+ @Test
+ public void testTeardownMultipleInterfaces() throws Exception {
+ testSetupMultipleInterfaces();
+ assertTrue(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+ assertTrue(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME1));
+
+ verify(mWificond).tearDownClientInterface(TEST_INTERFACE_NAME);
+ verify(mWificond).tearDownApInterface(TEST_INTERFACE_NAME1);
+ }
+
+ /**
+ * Verifies that tearDownInterfaces() calls wificond.
+ */
+ @Test
+ public void testTearDownInterfaces() throws Exception {
+ assertTrue(mWificondControl.tearDownInterfaces());
+ verify(mWificond).tearDownInterfaces();
+ }
+
+ /**
+ * Verifies that tearDownInterfaces() calls unsubscribeScanEvents() when there was
+ * a configured client interface.
+ */
+ @Test
+ public void testTearDownInterfacesRemovesScanEventSubscription() throws Exception {
+ assertTrue(mWificondControl.tearDownInterfaces());
+ verify(mWifiScannerImpl).unsubscribeScanEvents();
+ }
+
+ /**
+ * Verifies that tearDownInterfaces() returns false when wificond is not started.
+ */
+ @Test
+ public void testTearDownInterfacesErrorWhenWificondIsNotStarterd() throws Exception {
+ // Invoke wificond death handler to clear the handle.
+ mWificondControl.binderDied();
+ mLooper.dispatchAll();
+ assertFalse(mWificondControl.tearDownInterfaces());
+ }
+
+ /**
+ * Verifies that signalPoll() calls wificond.
+ */
+ @Test
+ public void testSignalPoll() throws Exception {
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
+ mNormalScanCallback, mPnoScanCallback);
+ mWificondControl.signalPoll(TEST_INTERFACE_NAME);
+ verify(mClientInterface).signalPoll();
+ }
+
+ /**
+ * Verifies that signalPoll() returns null when there is no configured client interface.
+ */
+ @Test
+ public void testSignalPollErrorWhenNoClientInterfaceConfigured() throws Exception {
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+ // Configure client interface.
+ assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
+ Runnable::run, mNormalScanCallback, mPnoScanCallback));
+
+ // Tear down interfaces.
+ assertTrue(mWificondControl.tearDownInterfaces());
+
+ // Signal poll should fail.
+ assertEquals(null, mWificondControl.signalPoll(TEST_INTERFACE_NAME));
+ }
+
+ /**
+ * Verifies that getTxPacketCounters() calls wificond.
+ */
+ @Test
+ public void testGetTxPacketCounters() throws Exception {
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
+ mNormalScanCallback, mPnoScanCallback);
+ mWificondControl.getTxPacketCounters(TEST_INTERFACE_NAME);
+ verify(mClientInterface).getPacketCounters();
+ }
+
+ /**
+ * Verifies that getTxPacketCounters() returns null when there is no configured client
+ * interface.
+ */
+ @Test
+ public void testGetTxPacketCountersErrorWhenNoClientInterfaceConfigured() throws Exception {
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+ // Configure client interface.
+ assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
+ Runnable::run, mNormalScanCallback, mPnoScanCallback));
+
+ // Tear down interfaces.
+ assertTrue(mWificondControl.tearDownInterfaces());
+
+ // Signal poll should fail.
+ assertEquals(null, mWificondControl.getTxPacketCounters(TEST_INTERFACE_NAME));
+ }
+
+ /**
+ * Verifies that getScanResults() returns null when there is no configured client
+ * interface.
+ */
+ @Test
+ public void testGetScanResultsErrorWhenNoClientInterfaceConfigured() throws Exception {
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+ // Configure client interface.
+ assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
+ Runnable::run, mNormalScanCallback, mPnoScanCallback));
+
+ // Tear down interfaces.
+ assertTrue(mWificondControl.tearDownInterfaces());
+
+ // getScanResults should fail.
+ assertEquals(0,
+ mWificondControl.getScanResults(TEST_INTERFACE_NAME,
+ WifiNl80211Manager.SCAN_TYPE_SINGLE_SCAN).size());
+ }
+
+ /**
+ * Verifies that Scan() can convert input parameters to SingleScanSettings correctly.
+ */
+ @Test
+ public void testScan() throws Exception {
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+ assertTrue(mWificondControl.startScan(
+ TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
+ verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
+ IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST)));
+ }
+
+ /**
+ * Verifies that Scan() removes duplicates hiddenSsids passed in from input.
+ */
+ @Test
+ public void testScanWithDuplicateHiddenSsids() throws Exception {
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+ // Create a list of hiddenSsid that has a duplicate element
+ List<byte[]> hiddenSsidWithDup = new ArrayList<>(SCAN_HIDDEN_NETWORK_SSID_LIST);
+ hiddenSsidWithDup.add(SCAN_HIDDEN_NETWORK_SSID_LIST.get(0));
+ assertEquals(hiddenSsidWithDup.get(0),
+ hiddenSsidWithDup.get(hiddenSsidWithDup.size() - 1));
+ // Pass the List with duplicate elements into scan()
+ assertTrue(mWificondControl.startScan(
+ TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, hiddenSsidWithDup));
+ // But the argument passed down should have the duplicate removed.
+ verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
+ IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST)));
+ }
+
+ /**
+ * Verifies that Scan() can handle null input parameters correctly.
+ */
+ @Test
+ public void testScanNullParameters() throws Exception {
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+ assertTrue(mWificondControl.startScan(
+ TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_HIGH_ACCURACY, null, null));
+ verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
+ IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY, null, null)));
+ }
+
+ /**
+ * Verifies that Scan() can handle wificond scan failure.
+ */
+ @Test
+ public void testScanFailure() throws Exception {
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(false);
+ assertFalse(mWificondControl.startScan(
+ TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_LATENCY,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
+ verify(mWifiScannerImpl).scan(any(SingleScanSettings.class));
+ }
+
+ /**
+ * Verifies that Scan() can handle invalid type.
+ */
+ @Test
+ public void testScanFailureDueToInvalidType() throws Exception {
+ assertFalse(mWificondControl.startScan(
+ TEST_INTERFACE_NAME, 100,
+ SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
+ verify(mWifiScannerImpl, never()).scan(any(SingleScanSettings.class));
+ }
+
+ /**
+ * Verifies that startPnoScan() can convert input parameters to PnoSettings correctly.
+ */
+ @Test
+ public void testStartPnoScan() throws Exception {
+ when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(true);
+ assertTrue(
+ mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS, Runnable::run,
+ mPnoScanRequestCallback));
+ verify(mWifiScannerImpl).startPnoScan(eq(TEST_PNO_SETTINGS));
+ verify(mPnoScanRequestCallback).onPnoRequestSucceeded();
+ }
+
+ /**
+ * Verifies that stopPnoScan() calls underlying wificond.
+ */
+ @Test
+ public void testStopPnoScan() throws Exception {
+ when(mWifiScannerImpl.stopPnoScan()).thenReturn(true);
+ assertTrue(mWificondControl.stopPnoScan(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).stopPnoScan();
+ }
+
+ /**
+ * Verifies that stopPnoScan() can handle wificond failure.
+ */
+ @Test
+ public void testStopPnoScanFailure() throws Exception {
+
+ when(mWifiScannerImpl.stopPnoScan()).thenReturn(false);
+ assertFalse(mWificondControl.stopPnoScan(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).stopPnoScan();
+ }
+
+ /**
+ * Verifies that WificondControl can invoke WifiMonitor broadcast methods upon scan
+ * result event.
+ */
+ @Test
+ public void testScanResultEvent() throws Exception {
+ ArgumentCaptor<IScanEvent> messageCaptor = ArgumentCaptor.forClass(IScanEvent.class);
+ verify(mWifiScannerImpl).subscribeScanEvents(messageCaptor.capture());
+ IScanEvent scanEvent = messageCaptor.getValue();
+ assertNotNull(scanEvent);
+ scanEvent.OnScanResultReady();
+
+ verify(mNormalScanCallback).onScanResultReady();
+ }
+
+ /**
+ * Verifies that WificondControl can invoke WifiMonitor broadcast methods upon scan
+ * failed event.
+ */
+ @Test
+ public void testScanFailedEvent() throws Exception {
+ ArgumentCaptor<IScanEvent> messageCaptor = ArgumentCaptor.forClass(IScanEvent.class);
+ verify(mWifiScannerImpl).subscribeScanEvents(messageCaptor.capture());
+ IScanEvent scanEvent = messageCaptor.getValue();
+ assertNotNull(scanEvent);
+ scanEvent.OnScanFailed();
+
+ verify(mNormalScanCallback).onScanFailed();
+ }
+
+ /**
+ * Verifies that WificondControl can invoke WifiMonitor broadcast methods upon pno scan
+ * result event.
+ */
+ @Test
+ public void testPnoScanResultEvent() throws Exception {
+ ArgumentCaptor<IPnoScanEvent> messageCaptor = ArgumentCaptor.forClass(IPnoScanEvent.class);
+ verify(mWifiScannerImpl).subscribePnoScanEvents(messageCaptor.capture());
+ IPnoScanEvent pnoScanEvent = messageCaptor.getValue();
+ assertNotNull(pnoScanEvent);
+ pnoScanEvent.OnPnoNetworkFound();
+ verify(mPnoScanCallback).onScanResultReady();
+ }
+
+ /**
+ * Verifies that WificondControl can invoke WifiMetrics pno scan count methods upon pno event.
+ */
+ @Test
+ public void testPnoScanEventsForMetrics() throws Exception {
+ ArgumentCaptor<IPnoScanEvent> messageCaptor = ArgumentCaptor.forClass(IPnoScanEvent.class);
+ verify(mWifiScannerImpl).subscribePnoScanEvents(messageCaptor.capture());
+ IPnoScanEvent pnoScanEvent = messageCaptor.getValue();
+ assertNotNull(pnoScanEvent);
+
+ pnoScanEvent.OnPnoNetworkFound();
+ verify(mPnoScanCallback).onScanResultReady();
+
+ pnoScanEvent.OnPnoScanFailed();
+ verify(mPnoScanCallback).onScanFailed();
+ }
+
+ /**
+ * Verifies that startPnoScan() can invoke WifiMetrics pno scan count methods correctly.
+ */
+ @Test
+ public void testStartPnoScanForMetrics() throws Exception {
+ when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(false);
+
+ assertFalse(
+ mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS, Runnable::run,
+ mPnoScanRequestCallback));
+ verify(mPnoScanRequestCallback).onPnoRequestFailed();
+ }
+
+ /**
+ * Verifies that abortScan() calls underlying wificond.
+ */
+ @Test
+ public void testAbortScan() throws Exception {
+ mWificondControl.abortScan(TEST_INTERFACE_NAME);
+ verify(mWifiScannerImpl).abortScan();
+ }
+
+ /**
+ * Ensures that the Ap interface callbacks are forwarded to the
+ * SoftApListener used for starting soft AP.
+ */
+ @Test
+ public void testSoftApListenerInvocation() throws Exception {
+ testSetupInterfaceForSoftApMode();
+
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = new String(TEST_SSID, StandardCharsets.UTF_8);
+
+ when(mApInterface.registerCallback(any())).thenReturn(true);
+
+ final ArgumentCaptor<IApInterfaceEventCallback> apInterfaceCallbackCaptor =
+ ArgumentCaptor.forClass(IApInterfaceEventCallback.class);
+
+ assertTrue(mWificondControl.registerApCallback(
+ TEST_INTERFACE_NAME, Runnable::run, mSoftApListener));
+ verify(mApInterface).registerCallback(apInterfaceCallbackCaptor.capture());
+
+ final NativeWifiClient testClient = new NativeWifiClient(TEST_RAW_MAC_BYTES);
+ apInterfaceCallbackCaptor.getValue().onConnectedClientsChanged(testClient, true);
+ verify(mSoftApListener).onConnectedClientsChanged(eq(testClient), eq(true));
+
+ int channelFrequency = 2437;
+ int channelBandwidth = IApInterfaceEventCallback.BANDWIDTH_20;
+ apInterfaceCallbackCaptor.getValue().onSoftApChannelSwitched(channelFrequency,
+ channelBandwidth);
+ verify(mSoftApListener).onSoftApChannelSwitched(eq(channelFrequency),
+ eq(SoftApInfo.CHANNEL_WIDTH_20MHZ));
+ }
+
+ /**
+ * Verifies registration and invocation of wificond death handler.
+ */
+ @Test
+ public void testRegisterDeathHandler() throws Exception {
+ Runnable deathHandler = mock(Runnable.class);
+ mWificondControl.setOnServiceDeadCallback(deathHandler);
+ mWificondControl.binderDied();
+ mLooper.dispatchAll();
+ verify(deathHandler).run();
+ }
+
+ /**
+ * Verifies handling of wificond death and ensures that all internal state is cleared and
+ * handlers are invoked.
+ */
+ @Test
+ public void testDeathHandling() throws Exception {
+ Runnable deathHandler = mock(Runnable.class);
+ mWificondControl.setOnServiceDeadCallback(deathHandler);
+
+ testSetupInterfaceForClientMode();
+
+ mWificondControl.binderDied();
+ mLooper.dispatchAll();
+ verify(deathHandler).run();
+
+ // The handles should be cleared after death.
+ assertEquals(0, mWificondControl.getChannelsMhzForBand(WifiScanner.WIFI_BAND_5_GHZ).length);
+ verify(mWificond, never()).getAvailable5gNonDFSChannels();
+ }
+
+ /**
+ * sendMgmtFrame() should fail if a null callback is passed in.
+ */
+ @Test
+ public void testSendMgmtFrameNullCallback() throws Exception {
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, null);
+
+ verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
+ }
+
+ /**
+ * sendMgmtFrame() should fail if a null frame is passed in.
+ */
+ @Test
+ public void testSendMgmtFrameNullFrame() throws Exception {
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, null, TEST_MCS_RATE, Runnable::run,
+ mSendMgmtFrameCallback);
+
+ verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
+ verify(mSendMgmtFrameCallback).onFailure(anyInt());
+ }
+
+ /**
+ * sendMgmtFrame() should fail if an interface name that does not exist is passed in.
+ */
+ @Test
+ public void testSendMgmtFrameInvalidInterfaceName() throws Exception {
+ mWificondControl.sendMgmtFrame(TEST_INVALID_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, mSendMgmtFrameCallback);
+
+ verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
+ verify(mSendMgmtFrameCallback).onFailure(anyInt());
+ }
+
+ /**
+ * sendMgmtFrame() should fail if it is called a second time before the first call completed.
+ */
+ @Test
+ public void testSendMgmtFrameCalledTwiceBeforeFinished() throws Exception {
+ WifiNl80211Manager.SendMgmtFrameCallback cb1 = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
+ WifiNl80211Manager.SendMgmtFrameCallback cb2 = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
+
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, cb1);
+ verify(cb1, never()).onFailure(anyInt());
+ verify(mClientInterface, times(1))
+ .SendMgmtFrame(AdditionalMatchers.aryEq(TEST_PROBE_FRAME),
+ any(), eq(TEST_MCS_RATE));
+
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, cb2);
+ verify(cb2).onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
+ // verify SendMgmtFrame() still was only called once i.e. not called again
+ verify(mClientInterface, times(1))
+ .SendMgmtFrame(any(), any(), anyInt());
+ }
+
+ /**
+ * Tests that when a RemoteException is triggered on AIDL call, onFailure() is called only once.
+ */
+ @Test
+ public void testSendMgmtFrameThrowsException() throws Exception {
+ WifiNl80211Manager.SendMgmtFrameCallback cb = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
+
+ final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+ ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+
+ doThrow(new RemoteException()).when(mClientInterface)
+ .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+ doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+ alarmListenerCaptor.capture(), handlerCaptor.capture());
+
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, cb);
+ mLooper.dispatchAll();
+
+ verify(cb).onFailure(anyInt());
+ verify(mAlarmManager).cancel(eq(alarmListenerCaptor.getValue()));
+
+ sendMgmtFrameEventCaptor.getValue().OnFailure(
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+ mLooper.dispatchAll();
+
+ handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+ mLooper.dispatchAll();
+
+ verifyNoMoreInteractions(cb);
+ }
+
+ /**
+ * Tests that the onAck() callback is triggered correctly.
+ */
+ @Test
+ public void testSendMgmtFrameSuccess() throws Exception {
+ WifiNl80211Manager.SendMgmtFrameCallback cb = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
+
+ final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+ ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+ doNothing().when(mClientInterface)
+ .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+ doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+ alarmListenerCaptor.capture(), handlerCaptor.capture());
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, cb);
+
+ sendMgmtFrameEventCaptor.getValue().OnAck(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS);
+ mLooper.dispatchAll();
+ verify(cb).onAck(eq(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS));
+ verify(cb, never()).onFailure(anyInt());
+ verify(mAlarmManager).cancel(eq(alarmListenerCaptor.getValue()));
+
+ // verify that even if timeout is triggered afterwards, SendMgmtFrameCallback is not
+ // triggered again
+ handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+ mLooper.dispatchAll();
+ verify(cb, times(1)).onAck(anyInt());
+ verify(cb, never()).onFailure(anyInt());
+ }
+
+ /**
+ * Tests that the onFailure() callback is triggered correctly.
+ */
+ @Test
+ public void testSendMgmtFrameFailure() throws Exception {
+ WifiNl80211Manager.SendMgmtFrameCallback cb = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
+
+ final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+ ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+ doNothing().when(mClientInterface)
+ .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+ doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+ alarmListenerCaptor.capture(), handlerCaptor.capture());
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, cb);
+
+ sendMgmtFrameEventCaptor.getValue().OnFailure(
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+ mLooper.dispatchAll();
+ verify(cb, never()).onAck(anyInt());
+ verify(cb).onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+ verify(mAlarmManager).cancel(eq(alarmListenerCaptor.getValue()));
+
+ // verify that even if timeout is triggered afterwards, SendMgmtFrameCallback is not
+ // triggered again
+ handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+ mLooper.dispatchAll();
+ verify(cb, never()).onAck(anyInt());
+ verify(cb, times(1)).onFailure(anyInt());
+ }
+
+ /**
+ * Tests that the onTimeout() callback is triggered correctly.
+ */
+ @Test
+ public void testSendMgmtFrameTimeout() throws Exception {
+ WifiNl80211Manager.SendMgmtFrameCallback cb = mock(
+ WifiNl80211Manager.SendMgmtFrameCallback.class);
+
+ final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+ ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+ doNothing().when(mClientInterface)
+ .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+ doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+ alarmListenerCaptor.capture(), handlerCaptor.capture());
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, cb);
+
+ handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+ mLooper.dispatchAll();
+ verify(cb, never()).onAck(anyInt());
+ verify(cb).onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
+
+ // verify that even if onAck() callback is triggered after timeout,
+ // SendMgmtFrameCallback is not triggered again
+ sendMgmtFrameEventCaptor.getValue().OnAck(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS);
+ mLooper.dispatchAll();
+ verify(cb, never()).onAck(anyInt());
+ verify(cb, times(1)).onFailure(anyInt());
+ }
+
+ /**
+ * Tests every possible test outcome followed by every other test outcome to ensure that the
+ * internal state is reset correctly between calls.
+ * i.e. (success, success), (success, failure), (success, timeout),
+ * (failure, failure), (failure, success), (failure, timeout),
+ * (timeout, timeout), (timeout, success), (timeout, failure)
+ *
+ * Also tests that internal state is reset correctly after a transient AIDL RemoteException.
+ */
+ @Test
+ public void testSendMgmtFrameMixed() throws Exception {
+ testSendMgmtFrameThrowsException();
+ testSendMgmtFrameSuccess();
+ testSendMgmtFrameSuccess();
+ testSendMgmtFrameFailure();
+ testSendMgmtFrameFailure();
+ testSendMgmtFrameTimeout();
+ testSendMgmtFrameTimeout();
+ testSendMgmtFrameSuccess();
+ testSendMgmtFrameTimeout();
+ testSendMgmtFrameFailure();
+ testSendMgmtFrameSuccess();
+ }
+
+ /**
+ * Tests that OnAck() does not perform any non-thread-safe operations on the binder thread.
+ *
+ * The sequence of instructions are:
+ * 1. post onAlarm() onto main thread
+ * 2. OnAck()
+ * 3. mLooper.dispatchAll()
+ *
+ * The actual order of execution is:
+ * 1. binder thread portion of OnAck()
+ * 2. onAlarm() (which purely executes on the main thread)
+ * 3. main thread portion of OnAck()
+ *
+ * If the binder thread portion of OnAck() is not thread-safe, it can possibly mess up
+ * onAlarm(). Tests that this does not occur.
+ */
+ @Test
+ public void testSendMgmtFrameTimeoutAckThreadSafe() throws Exception {
+ final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+ ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+ doNothing().when(mClientInterface)
+ .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+ doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+ alarmListenerCaptor.capture(), handlerCaptor.capture());
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, mSendMgmtFrameCallback);
+
+ // AlarmManager should post the onAlarm() callback onto the handler, but since we are
+ // triggering onAlarm() ourselves during the test, manually post onto handler
+ handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+ // OnAck posts to the handler
+ sendMgmtFrameEventCaptor.getValue().OnAck(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS);
+ mLooper.dispatchAll();
+ verify(mSendMgmtFrameCallback, never()).onAck(anyInt());
+ verify(mSendMgmtFrameCallback).onFailure(
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
+ }
+
+ /**
+ * See {@link #testSendMgmtFrameTimeoutAckThreadSafe()}. This test replaces OnAck() with
+ * OnFailure().
+ */
+ @Test
+ public void testSendMgmtFrameTimeoutFailureThreadSafe() throws Exception {
+ final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+ ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+ doNothing().when(mClientInterface)
+ .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+ final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+ doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+ alarmListenerCaptor.capture(), handlerCaptor.capture());
+ mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+ Runnable::run, mSendMgmtFrameCallback);
+
+ // AlarmManager should post the onAlarm() callback onto the handler, but since we are
+ // triggering onAlarm() ourselves during the test, manually post onto handler
+ handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+ // OnFailure posts to the handler
+ sendMgmtFrameEventCaptor.getValue().OnFailure(
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+ mLooper.dispatchAll();
+ verify(mSendMgmtFrameCallback).onFailure(
+ WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
+ }
+
+ /**
+ * Tests getDeviceWiphyCapabililties
+ */
+ @Test
+ public void testGetDeviceWiphyCapabilities() throws Exception {
+ DeviceWiphyCapabilities capaExpected = new DeviceWiphyCapabilities();
+
+ capaExpected.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true);
+ capaExpected.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true);
+ capaExpected.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false);
+ capaExpected.setChannelWidthSupported(ScanResult.CHANNEL_WIDTH_160MHZ, true);
+ capaExpected.setChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ, false);
+ capaExpected.setMaxNumberTxSpatialStreams(2);
+ capaExpected.setMaxNumberRxSpatialStreams(1);
+
+ when(mWificond.getDeviceWiphyCapabilities(TEST_INTERFACE_NAME))
+ .thenReturn(capaExpected);
+
+ DeviceWiphyCapabilities capaActual =
+ mWificondControl.getDeviceWiphyCapabilities(TEST_INTERFACE_NAME);
+ assertEquals(capaExpected, capaActual);
+ }
+
+ // Create a ArgumentMatcher which captures a SingleScanSettings parameter and checks if it
+ // matches the provided frequency set and ssid set.
+ private class ScanMatcher implements ArgumentMatcher<SingleScanSettings> {
+ int mExpectedScanType;
+ private final Set<Integer> mExpectedFreqs;
+ private final List<byte[]> mExpectedSsids;
+
+ ScanMatcher(int expectedScanType, Set<Integer> expectedFreqs, List<byte[]> expectedSsids) {
+ this.mExpectedScanType = expectedScanType;
+ this.mExpectedFreqs = expectedFreqs;
+ this.mExpectedSsids = expectedSsids;
+ }
+
+ @Override
+ public boolean matches(SingleScanSettings settings) {
+ if (settings.scanType != mExpectedScanType) {
+ return false;
+ }
+ ArrayList<ChannelSettings> channelSettings = settings.channelSettings;
+ ArrayList<HiddenNetwork> hiddenNetworks = settings.hiddenNetworks;
+ if (mExpectedFreqs != null) {
+ Set<Integer> freqSet = new HashSet<Integer>();
+ for (ChannelSettings channel : channelSettings) {
+ freqSet.add(channel.frequency);
+ }
+ if (!mExpectedFreqs.equals(freqSet)) {
+ return false;
+ }
+ } else {
+ if (channelSettings != null && channelSettings.size() > 0) {
+ return false;
+ }
+ }
+
+ if (mExpectedSsids != null) {
+ List<byte[]> ssidSet = new ArrayList<>();
+ for (HiddenNetwork network : hiddenNetworks) {
+ ssidSet.add(network.ssid);
+ }
+ if (!mExpectedSsids.equals(ssidSet)) {
+ return false;
+ }
+
+ } else {
+ if (hiddenNetworks != null && hiddenNetworks.size() > 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "ScanMatcher{mExpectedFreqs=" + mExpectedFreqs
+ + ", mExpectedSsids=" + mExpectedSsids + '}';
+ }
+ }
+
+ private static class LocalNativeUtil {
+ private static final int SSID_BYTES_MAX_LEN = 32;
+
+ /**
+ * Converts an ArrayList<Byte> of UTF_8 byte values to string.
+ * The string will either be:
+ * a) UTF-8 String encapsulated in quotes (if all the bytes are UTF-8 encodeable and non
+ * null),
+ * or
+ * b) Hex string with no delimiters.
+ *
+ * @param bytes List of bytes for ssid.
+ * @throws IllegalArgumentException for null bytes.
+ */
+ public static String bytesToHexOrQuotedString(ArrayList<Byte> bytes) {
+ if (bytes == null) {
+ throw new IllegalArgumentException("null ssid bytes");
+ }
+ byte[] byteArray = byteArrayFromArrayList(bytes);
+ // Check for 0's in the byte stream in which case we cannot convert this into a string.
+ if (!bytes.contains(Byte.valueOf((byte) 0))) {
+ CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
+ try {
+ CharBuffer decoded = decoder.decode(ByteBuffer.wrap(byteArray));
+ return "\"" + decoded.toString() + "\"";
+ } catch (CharacterCodingException cce) {
+ }
+ }
+ return hexStringFromByteArray(byteArray);
+ }
+
+ /**
+ * Converts an ssid string to an arraylist of UTF_8 byte values.
+ * These forms are acceptable:
+ * a) UTF-8 String encapsulated in quotes, or
+ * b) Hex string with no delimiters.
+ *
+ * @param ssidStr String to be converted.
+ * @throws IllegalArgumentException for null string.
+ */
+ public static ArrayList<Byte> decodeSsid(String ssidStr) {
+ ArrayList<Byte> ssidBytes = hexOrQuotedStringToBytes(ssidStr);
+ if (ssidBytes.size() > SSID_BYTES_MAX_LEN) {
+ throw new IllegalArgumentException(
+ "ssid bytes size out of range: " + ssidBytes.size());
+ }
+ return ssidBytes;
+ }
+
+ /**
+ * Convert from an array list of Byte to an array of primitive bytes.
+ */
+ public static byte[] byteArrayFromArrayList(ArrayList<Byte> bytes) {
+ byte[] byteArray = new byte[bytes.size()];
+ int i = 0;
+ for (Byte b : bytes) {
+ byteArray[i++] = b;
+ }
+ return byteArray;
+ }
+
+ /**
+ * Converts a byte array to hex string.
+ *
+ * @param bytes List of bytes for ssid.
+ * @throws IllegalArgumentException for null bytes.
+ */
+ public static String hexStringFromByteArray(byte[] bytes) {
+ if (bytes == null) {
+ throw new IllegalArgumentException("null hex bytes");
+ }
+ return new String(HexEncoding.encode(bytes)).toLowerCase();
+ }
+
+ /**
+ * Converts an string to an arraylist of UTF_8 byte values.
+ * These forms are acceptable:
+ * a) UTF-8 String encapsulated in quotes, or
+ * b) Hex string with no delimiters.
+ *
+ * @param str String to be converted.
+ * @throws IllegalArgumentException for null string.
+ */
+ public static ArrayList<Byte> hexOrQuotedStringToBytes(String str) {
+ if (str == null) {
+ throw new IllegalArgumentException("null string");
+ }
+ int length = str.length();
+ if ((length > 1) && (str.charAt(0) == '"') && (str.charAt(length - 1) == '"')) {
+ str = str.substring(1, str.length() - 1);
+ return stringToByteArrayList(str);
+ } else {
+ return byteArrayToArrayList(hexStringToByteArray(str));
+ }
+ }
+
+ /**
+ * Convert the string to byte array list.
+ *
+ * @return the UTF_8 char byte values of str, as an ArrayList.
+ * @throws IllegalArgumentException if a null or unencodable string is sent.
+ */
+ public static ArrayList<Byte> stringToByteArrayList(String str) {
+ if (str == null) {
+ throw new IllegalArgumentException("null string");
+ }
+ // Ensure that the provided string is UTF_8 encoded.
+ CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();
+ try {
+ ByteBuffer encoded = encoder.encode(CharBuffer.wrap(str));
+ byte[] byteArray = new byte[encoded.remaining()];
+ encoded.get(byteArray);
+ return byteArrayToArrayList(byteArray);
+ } catch (CharacterCodingException cce) {
+ throw new IllegalArgumentException("cannot be utf-8 encoded", cce);
+ }
+ }
+
+ /**
+ * Convert from an array of primitive bytes to an array list of Byte.
+ */
+ public static ArrayList<Byte> byteArrayToArrayList(byte[] bytes) {
+ ArrayList<Byte> byteList = new ArrayList<>();
+ for (Byte b : bytes) {
+ byteList.add(b);
+ }
+ return byteList;
+ }
+
+ /**
+ * Converts a hex string to byte array.
+ *
+ * @param hexStr String to be converted.
+ * @throws IllegalArgumentException for null string.
+ */
+ public static byte[] hexStringToByteArray(String hexStr) {
+ if (hexStr == null) {
+ throw new IllegalArgumentException("null hex string");
+ }
+ return HexEncoding.decode(hexStr.toCharArray(), false);
+ }
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
index 17ee75594c2f..6edc287068e8 100644
--- a/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
@@ -45,7 +45,7 @@ public class WifiP2pDeviceTest {
assertEquals(devA.groupCapability, devB.groupCapability);
assertEquals(devA.status, devB.status);
if (devA.wfdInfo != null) {
- assertEquals(devA.wfdInfo.isWfdEnabled(), devB.wfdInfo.isWfdEnabled());
+ assertEquals(devA.wfdInfo.isEnabled(), devB.wfdInfo.isEnabled());
assertEquals(devA.wfdInfo.getDeviceInfoHex(), devB.wfdInfo.getDeviceInfoHex());
assertEquals(devA.wfdInfo.getControlPort(), devB.wfdInfo.getControlPort());
assertEquals(devA.wfdInfo.getMaxThroughput(), devB.wfdInfo.getMaxThroughput());
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pWfdInfoTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pWfdInfoTest.java
index d2f11688e4e5..2a9b36b47172 100644
--- a/wifi/tests/src/android/net/wifi/p2p/WifiP2pWfdInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pWfdInfoTest.java
@@ -43,8 +43,9 @@ public class WifiP2pWfdInfoTest {
@Before
public void setUp() {
// initialize device info flags.
- mSourceInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
+ mSourceInfo.setDeviceType(WifiP2pWfdInfo.DEVICE_TYPE_WFD_SOURCE);
mSourceInfo.setSessionAvailable(true);
+ mSourceInfo.setContentProtectionSupported(true);
}
/**
@@ -54,28 +55,25 @@ public class WifiP2pWfdInfoTest {
public void testSettersGetters() throws Exception {
WifiP2pWfdInfo info = new WifiP2pWfdInfo();
- info.setWfdEnabled(true);
- assertTrue(info.isWfdEnabled());
+ info.setEnabled(true);
+ assertTrue(info.isEnabled());
- info.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
- assertEquals(WifiP2pWfdInfo.WFD_SOURCE, info.getDeviceType());
-
- info.setCoupledSinkSupportAtSource(true);
- assertTrue(info.isCoupledSinkSupportedAtSource());
-
- info.setCoupledSinkSupportAtSink(true);
- assertTrue(info.isCoupledSinkSupportedAtSink());
+ info.setDeviceType(WifiP2pWfdInfo.DEVICE_TYPE_WFD_SOURCE);
+ assertEquals(WifiP2pWfdInfo.DEVICE_TYPE_WFD_SOURCE, info.getDeviceType());
info.setSessionAvailable(true);
assertTrue(info.isSessionAvailable());
+ info.setContentProtectionSupported(true);
+ assertTrue(info.isContentProtectionSupported());
+
info.setControlPort(TEST_CTRL_PORT);
assertEquals(TEST_CTRL_PORT, info.getControlPort());
info.setMaxThroughput(TEST_MAX_TPUT);
assertEquals(TEST_MAX_TPUT, info.getMaxThroughput());
- assertEquals("0018270f0400", info.getDeviceInfoHex());
+ assertEquals("0110270f0400", info.getDeviceInfoHex());
}
/**
diff --git a/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java b/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java
index b02eebbe9a01..271339cecf1e 100644
--- a/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java
@@ -20,6 +20,7 @@ import android.location.Address;
import android.location.Location;
import android.net.MacAddress;
import android.os.Parcel;
+import android.util.SparseArray;
import android.webkit.MimeTypeMap;
import static junit.framework.Assert.assertEquals;
@@ -505,6 +506,30 @@ public class ResponderLocationTest {
}
/**
+ * Test that a Civic Location sparseArray can be extracted from a valid lcr buffer.
+ */
+ @Test
+ public void testLcrTestCivicLocationSparseArray() {
+ byte[] testLciBuffer = concatenateArrays(sTestLciIeHeader, sTestLciSE);
+ byte[] testLcrBuffer =
+ concatenateArrays(sTestLcrBufferHeader, sTestCivicLocationSEWithAddress);
+ ResponderLocation responderLocation = new ResponderLocation(testLciBuffer, testLcrBuffer);
+
+ boolean valid = responderLocation.isValid();
+ SparseArray<String> civicLocationSparseArray = responderLocation
+ .toCivicLocationSparseArray();
+
+ assertTrue(valid);
+ assertEquals("15", civicLocationSparseArray.get(CivicLocationKeys.HNO));
+ assertEquals("Alto",
+ civicLocationSparseArray.get(CivicLocationKeys.PRIMARY_ROAD_NAME));
+ assertEquals("Road",
+ civicLocationSparseArray.get(CivicLocationKeys.STREET_NAME_POST_MODIFIER));
+ assertEquals("Mtn View", civicLocationSparseArray.get(CivicLocationKeys.CITY));
+ assertEquals("94043", civicLocationSparseArray.get(CivicLocationKeys.POSTAL_CODE));
+ }
+
+ /**
* Test that a URL can be extracted from a valid lcr buffer with a map image subelement.
*/
@Test
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index 53bd837d29e0..e6eae416ba78 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -54,6 +54,7 @@ public class WifiRttManagerTest {
private Executor mMockLooperExecutor;
private final String packageName = "some.package.name.for.rtt.app";
+ private final String featureId = "some.feature.id.in.rtt.app";
@Mock
public Context mockContext;
@@ -70,6 +71,7 @@ public class WifiRttManagerTest {
mMockLooperExecutor = mMockLooper.getNewExecutor();
when(mockContext.getOpPackageName()).thenReturn(packageName);
+ when(mockContext.getAttributionTag()).thenReturn(featureId);
}
/**
@@ -87,8 +89,8 @@ public class WifiRttManagerTest {
// verify ranging request passed to service
mDut.startRanging(request, mMockLooperExecutor, callbackMock);
- verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(null),
- eq(request), callbackCaptor.capture());
+ verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(featureId),
+ eq(null), eq(request), callbackCaptor.capture());
// service calls back with success
callbackCaptor.getValue().onRangingResults(results);
@@ -111,8 +113,8 @@ public class WifiRttManagerTest {
// verify ranging request passed to service
mDut.startRanging(request, mMockLooperExecutor, callbackMock);
- verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(null),
- eq(request), callbackCaptor.capture());
+ verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(featureId),
+ eq(null), eq(request), callbackCaptor.capture());
// service calls back with failure code
callbackCaptor.getValue().onRangingFailure(failureCode);
diff --git a/wifi/tests/src/android/net/wifi/util/HexEncodingTest.java b/wifi/tests/src/android/net/wifi/util/HexEncodingTest.java
new file mode 100644
index 000000000000..0d751389e244
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/util/HexEncodingTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.util;
+
+import static android.net.wifi.util.HexEncoding.decode;
+import static android.net.wifi.util.HexEncoding.encode;
+import static android.net.wifi.util.HexEncoding.encodeToString;
+
+import junit.framework.TestCase;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Locale;
+
+/** Copied from {@link libcore.libcore.util.HexEncodingTest}. */
+public class HexEncodingTest extends TestCase {
+
+ public void testEncodeByte() {
+ Object[][] testCases = new Object[][]{
+ {0x01, "01"},
+ {0x09, "09"},
+ {0x0A, "0A"},
+ {0x0F, "0F"},
+ {0x10, "10"},
+ {0x1F, "1F"},
+ {0x20, "20"},
+ {0x7F, "7F"},
+ {0x80, "80"},
+ {0xFF, "FF"},
+ };
+ for (Object[] testCase : testCases) {
+ Number toEncode = (Number) testCase[0];
+ String expected = (String) testCase[1];
+
+ String actualUpper = encodeToString(toEncode.byteValue(), true /* upperCase */);
+ assertEquals(upper(expected), actualUpper);
+
+ String actualLower = encodeToString(toEncode.byteValue(), false /* upperCase */);
+ assertEquals(lower(expected), actualLower);
+ }
+ }
+
+ public void testEncodeBytes() {
+ Object[][] testCases = new Object[][]{
+ {"avocados".getBytes(StandardCharsets.UTF_8), "61766F6361646F73"},
+ };
+
+ for (Object[] testCase : testCases) {
+ byte[] bytes = (byte[]) testCase[0];
+ String encodedLower = lower((String) testCase[1]);
+ String encodedUpper = upper((String) testCase[1]);
+
+ assertArraysEqual(encodedUpper.toCharArray(), encode(bytes));
+ assertArraysEqual(encodedUpper.toCharArray(), encode(bytes, true /* upperCase */));
+ assertArraysEqual(encodedLower.toCharArray(), encode(bytes, false /* upperCase */));
+
+ assertArraysEqual(bytes, decode(encode(bytes), false /* allowSingleChar */));
+
+ // Make sure we can handle lower case hex encodings as well.
+ assertArraysEqual(bytes,
+ decode(encodedLower.toCharArray(), false /* allowSingleChar */));
+ }
+ }
+
+ public void testDecode_allow4Bit() {
+ assertArraysEqual(new byte[]{6}, decode("6".toCharArray(), true));
+ assertArraysEqual(new byte[]{6, 0x76}, decode("676".toCharArray(), true));
+ }
+
+ public void testDecode_disallow4Bit() {
+ try {
+ decode("676".toCharArray(), false /* allowSingleChar */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testDecode_invalid() {
+ try {
+ decode("DEADBARD".toCharArray(), false /* allowSingleChar */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // This demonstrates a difference in behaviour from apache commons : apache
+ // commons uses Character.isDigit and would successfully decode a string with
+ // arabic and devanagari characters.
+ try {
+ decode("६१٧٥٥F6361646F73".toCharArray(), false /* allowSingleChar */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ decode("#%6361646F73".toCharArray(), false /* allowSingleChar */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ private static void assertArraysEqual(char[] lhs, char[] rhs) {
+ assertEquals(new String(lhs), new String(rhs));
+ }
+
+ private static void assertArraysEqual(byte[] lhs, byte[] rhs) {
+ assertEquals(Arrays.toString(lhs), Arrays.toString(rhs));
+ }
+
+ private static String lower(String string) {
+ return string.toLowerCase(Locale.ROOT);
+ }
+
+ private static String upper(String string) {
+ return string.toUpperCase(Locale.ROOT);
+ }
+}