summaryrefslogtreecommitdiff
path: root/wifi/java/android
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/java/android
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/java/android')
-rw-r--r--wifi/java/android/net/wifi/EasyConnectStatusCallback.java134
-rw-r--r--wifi/java/android/net/wifi/IActionListener.aidl (renamed from wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl)16
-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.aidl (renamed from wifi/java/android/net/wifi/WpsResult.aidl)16
-rw-r--r--wifi/java/android/net/wifi/IScanResultsListener.aidl (renamed from wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.aidl)11
-rw-r--r--wifi/java/android/net/wifi/IScoreUpdateObserver.aidl (renamed from wifi/java/android/net/wifi/WifiActivityEnergyInfo.aidl)18
-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
85 files changed, 12044 insertions, 2639 deletions
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/PasspointManagementObjectDefinition.aidl b/wifi/java/android/net/wifi/IActionListener.aidl
index eb7cc39d5e33..faa0901cb087 100644
--- a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl
+++ b/wifi/java/android/net/wifi/IActionListener.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,12 @@
package android.net.wifi;
-parcelable PasspointManagementObjectDefinition;
+/**
+ * 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/WpsResult.aidl b/wifi/java/android/net/wifi/IScanResultsCallback.aidl
index eb4c4f5539ba..56f602510fd9 100644
--- a/wifi/java/android/net/wifi/WpsResult.aidl
+++ b/wifi/java/android/net/wifi/IScanResultsCallback.aidl
@@ -1,11 +1,11 @@
-/**
- * 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.
* 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,12 @@
package android.net.wifi;
-parcelable WpsResult;
+/**
+ * Interface for Wi-Fi scan result available callback.
+ *
+ * @hide
+ */
+oneway interface IScanResultsCallback
+{
+ void onScanResultsAvailable();
+}
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.aidl b/wifi/java/android/net/wifi/IScanResultsListener.aidl
index c81d1f98422d..e7eaddd712c9 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.aidl
+++ b/wifi/java/android/net/wifi/IScanResultsListener.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,11 @@
* limitations under the License.
*/
-package android.net.wifi.p2p.servicediscovery;
+package android.net.wifi;
-parcelable WifiP2pServiceResponse;
+/** @hide */
+
+oneway interface IScanResultsListener
+{
+ void onScanResultsAvailable();
+}
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.aidl b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
index 007ec94378fd..775fed7d47ef 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.aidl
+++ b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
+/*
+ * 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
+ * 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,14 @@
package android.net.wifi;
-parcelable WifiActivityEnergyInfo;
+/**
+ * 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);
+ }
+}