1742 lines
78 KiB
Java
1742 lines
78 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2018 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.net.wifi;
|
||
|
|
||
|
import static com.android.internal.util.Preconditions.checkNotNull;
|
||
|
|
||
|
import android.annotation.FlaggedApi;
|
||
|
import android.annotation.IntDef;
|
||
|
import android.annotation.IntRange;
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.annotation.RequiresPermission;
|
||
|
import android.annotation.SystemApi;
|
||
|
import android.net.MacAddress;
|
||
|
import android.net.NetworkCapabilities;
|
||
|
import android.net.NetworkRequest;
|
||
|
import android.net.wifi.hotspot2.PasspointConfiguration;
|
||
|
import android.os.Build;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.ParcelUuid;
|
||
|
import android.os.Parcelable;
|
||
|
import android.telephony.SubscriptionInfo;
|
||
|
import android.telephony.SubscriptionManager;
|
||
|
import android.telephony.TelephonyManager;
|
||
|
import android.text.TextUtils;
|
||
|
|
||
|
import androidx.annotation.RequiresApi;
|
||
|
|
||
|
import com.android.modules.utils.build.SdkLevel;
|
||
|
import com.android.wifi.flags.Flags;
|
||
|
|
||
|
import java.lang.annotation.Retention;
|
||
|
import java.lang.annotation.RetentionPolicy;
|
||
|
import java.nio.charset.CharsetEncoder;
|
||
|
import java.nio.charset.StandardCharsets;
|
||
|
import java.util.List;
|
||
|
import java.util.Objects;
|
||
|
|
||
|
/**
|
||
|
* The Network Suggestion object is used to provide a Wi-Fi network for consideration when
|
||
|
* auto-connecting to networks. Apps cannot directly create this object, they must use
|
||
|
* {@link WifiNetworkSuggestion.Builder#build()} to obtain an instance of this object.
|
||
|
*<p>
|
||
|
* Apps can provide a list of such networks to the platform using
|
||
|
* {@link WifiManager#addNetworkSuggestions(List)}.
|
||
|
*/
|
||
|
public final class WifiNetworkSuggestion implements Parcelable {
|
||
|
/** @hide */
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(prefix = {"RANDOMIZATION_"}, value = {
|
||
|
RANDOMIZATION_PERSISTENT,
|
||
|
RANDOMIZATION_NON_PERSISTENT})
|
||
|
public @interface MacRandomizationSetting {}
|
||
|
/**
|
||
|
* Generate a randomized MAC from a secret seed and information from the Wi-Fi configuration
|
||
|
* (SSID or Passpoint profile) and reuse it for all connections to this network. The
|
||
|
* randomized MAC address for this network will stay the same for each subsequent association
|
||
|
* until the device undergoes factory reset.
|
||
|
*/
|
||
|
public static final int RANDOMIZATION_PERSISTENT = 0;
|
||
|
/**
|
||
|
* With this option, the randomized MAC address will periodically get re-randomized, and
|
||
|
* the randomized MAC address will change if the suggestion is removed and then added back.
|
||
|
*/
|
||
|
public static final int RANDOMIZATION_NON_PERSISTENT = 1;
|
||
|
/**
|
||
|
* Builder used to create {@link WifiNetworkSuggestion} objects.
|
||
|
*/
|
||
|
public static final class Builder {
|
||
|
private static final int UNASSIGNED_PRIORITY = -1;
|
||
|
|
||
|
/**
|
||
|
* Set WPA Enterprise type according to certificate security level.
|
||
|
* This is for backward compatibility in R.
|
||
|
*/
|
||
|
private static final int WPA3_ENTERPRISE_AUTO = 0;
|
||
|
/** Set WPA Enterprise type to standard mode only. */
|
||
|
private static final int WPA3_ENTERPRISE_STANDARD = 1;
|
||
|
/** Set WPA Enterprise type to 192 bit mode only. */
|
||
|
private static final int WPA3_ENTERPRISE_192_BIT = 2;
|
||
|
|
||
|
/**
|
||
|
* SSID of the network.
|
||
|
*/
|
||
|
private WifiSsid mWifiSsid;
|
||
|
/**
|
||
|
* Optional BSSID within the network.
|
||
|
*/
|
||
|
private MacAddress mBssid;
|
||
|
/**
|
||
|
* Whether this is an OWE network or not.
|
||
|
*/
|
||
|
private boolean mIsEnhancedOpen;
|
||
|
/**
|
||
|
* Pre-shared key for use with WPA-PSK networks.
|
||
|
*/
|
||
|
private @Nullable String mWpa2PskPassphrase;
|
||
|
/**
|
||
|
* Pre-shared key for use with WPA3-SAE networks.
|
||
|
*/
|
||
|
private @Nullable String mWpa3SaePassphrase;
|
||
|
/**
|
||
|
* The enterprise configuration details specifying the EAP method,
|
||
|
* certificates and other settings associated with the WPA/WPA2-Enterprise networks.
|
||
|
*/
|
||
|
private @Nullable WifiEnterpriseConfig mWpa2EnterpriseConfig;
|
||
|
/**
|
||
|
* The enterprise configuration details specifying the EAP method,
|
||
|
* certificates and other settings associated with the WPA3-Enterprise networks.
|
||
|
*/
|
||
|
private @Nullable WifiEnterpriseConfig mWpa3EnterpriseConfig;
|
||
|
/**
|
||
|
* Indicate what type this WPA3-Enterprise network is.
|
||
|
*/
|
||
|
private int mWpa3EnterpriseType = WPA3_ENTERPRISE_AUTO;
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
private boolean mIsHiddenSSID;
|
||
|
/**
|
||
|
* Whether app needs to log in to captive portal to obtain Internet access.
|
||
|
*/
|
||
|
private boolean mIsAppInteractionRequired;
|
||
|
/**
|
||
|
* Whether user needs to log in to captive portal to obtain Internet access.
|
||
|
*/
|
||
|
private boolean mIsUserInteractionRequired;
|
||
|
/**
|
||
|
* Whether this network is metered or not.
|
||
|
*/
|
||
|
private int mMeteredOverride;
|
||
|
/**
|
||
|
* Priority of this network among other network suggestions from same priority group
|
||
|
* provided by the app.
|
||
|
* The higher the number, the higher the priority (i.e value of 0 = lowest priority).
|
||
|
*/
|
||
|
private int mPriority;
|
||
|
/**
|
||
|
* Priority group ID, while suggestion priority will only effect inside the priority group.
|
||
|
*/
|
||
|
private int mPriorityGroup;
|
||
|
|
||
|
/**
|
||
|
* The carrier ID identifies the operator who provides this network configuration.
|
||
|
* see {@link TelephonyManager#getSimCarrierId()}
|
||
|
*/
|
||
|
private int mCarrierId;
|
||
|
|
||
|
/**
|
||
|
* The Subscription ID identifies the SIM card for which this network configuration is
|
||
|
* valid.
|
||
|
*/
|
||
|
private int mSubscriptionId;
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
|
||
|
/**
|
||
|
* Whether this network will be brought up as OEM paid (OEM_PAID capability bit added).
|
||
|
*/
|
||
|
private boolean mIsNetworkOemPaid;
|
||
|
|
||
|
/**
|
||
|
* Whether this network will be brought up as OEM private (OEM_PRIVATE capability bit
|
||
|
* added).
|
||
|
*/
|
||
|
private boolean mIsNetworkOemPrivate;
|
||
|
|
||
|
/**
|
||
|
* Whether this network is a carrier merged network.
|
||
|
*/
|
||
|
private boolean mIsCarrierMerged;
|
||
|
|
||
|
/**
|
||
|
* The MAC randomization strategy.
|
||
|
*/
|
||
|
@MacRandomizationSetting
|
||
|
private int mMacRandomizationSetting;
|
||
|
|
||
|
/**
|
||
|
* The SAE Hash-to-Element only mode.
|
||
|
*/
|
||
|
private boolean mSaeH2eOnlyMode;
|
||
|
|
||
|
/**
|
||
|
* Whether this network will be brought up as restricted
|
||
|
*/
|
||
|
private boolean mIsNetworkRestricted;
|
||
|
|
||
|
/**
|
||
|
* Whether enable Wi-Fi 7 for this network
|
||
|
*/
|
||
|
private boolean mIsWifi7Enabled;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* The Subscription group UUID identifies the SIM cards for which this network configuration
|
||
|
* is valid.
|
||
|
*/
|
||
|
private ParcelUuid mSubscriptionGroup;
|
||
|
|
||
|
public Builder() {
|
||
|
mBssid = null;
|
||
|
mIsEnhancedOpen = false;
|
||
|
mWpa2PskPassphrase = null;
|
||
|
mWpa3SaePassphrase = null;
|
||
|
mWpa2EnterpriseConfig = null;
|
||
|
mWpa3EnterpriseConfig = null;
|
||
|
mPasspointConfiguration = null;
|
||
|
mIsHiddenSSID = false;
|
||
|
mIsAppInteractionRequired = false;
|
||
|
mIsUserInteractionRequired = 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;
|
||
|
mIsNetworkOemPaid = false;
|
||
|
mIsNetworkOemPrivate = false;
|
||
|
mIsCarrierMerged = false;
|
||
|
mPriorityGroup = 0;
|
||
|
mMacRandomizationSetting = RANDOMIZATION_PERSISTENT;
|
||
|
mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||
|
mSaeH2eOnlyMode = false;
|
||
|
mIsNetworkRestricted = false;
|
||
|
mSubscriptionGroup = null;
|
||
|
mWifiSsid = null;
|
||
|
mIsWifi7Enabled = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the unicode SSID for the network.
|
||
|
* <p>
|
||
|
* <li>Overrides any previous value set using {@link #setSsid(String)}.</li>
|
||
|
*
|
||
|
* <p>
|
||
|
* Note: use {@link #setWifiSsid(WifiSsid)} which supports both unicode and non-unicode
|
||
|
* SSID.
|
||
|
*
|
||
|
* @param ssid The SSID of the network. It must be valid Unicode.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
* @throws IllegalArgumentException if the SSID is not valid unicode.
|
||
|
*/
|
||
|
public @NonNull Builder setSsid(@NonNull String ssid) {
|
||
|
checkNotNull(ssid);
|
||
|
final CharsetEncoder unicodeEncoder = StandardCharsets.UTF_8.newEncoder();
|
||
|
if (!unicodeEncoder.canEncode(ssid)) {
|
||
|
throw new IllegalArgumentException("SSID is not a valid unicode string");
|
||
|
}
|
||
|
mWifiSsid = WifiSsid.fromUtf8Text(ssid);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the SSID for the network. {@link WifiSsid} support both unicode and non-unicode SSID.
|
||
|
* <p>
|
||
|
* <li>Overrides any previous value set using {@link #setWifiSsid(WifiSsid)}
|
||
|
* or {@link #setSsid(String)}.</li>
|
||
|
* <p>
|
||
|
* Note: this method is the superset of the {@link #setSsid(String)}
|
||
|
*
|
||
|
* @param wifiSsid The SSID of the network, in {@link WifiSsid} format.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
* @throws IllegalArgumentException if the wifiSsid is invalid.
|
||
|
*/
|
||
|
public @NonNull Builder setWifiSsid(@NonNull WifiSsid wifiSsid) {
|
||
|
checkNotNull(wifiSsid);
|
||
|
if (wifiSsid.getBytes().length == 0) {
|
||
|
throw new IllegalArgumentException("Empty WifiSsid is invalid");
|
||
|
}
|
||
|
mWifiSsid = WifiSsid.fromBytes(wifiSsid.getBytes());
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the BSSID to use for filtering networks from scan results. Will only match network
|
||
|
* whose BSSID is identical to the specified value.
|
||
|
* <p>
|
||
|
* <li Sets a specific BSSID for the network suggestion. If set, only the specified BSSID
|
||
|
* with the specified SSID will be considered for connection.
|
||
|
* <li>If set, only the specified BSSID with the specified SSID will be considered for
|
||
|
* connection.</li>
|
||
|
* <li>If not set, all BSSIDs with the specified SSID will be considered for connection.
|
||
|
* </li>
|
||
|
* <li>Overrides any previous value set using {@link #setBssid(MacAddress)}.</li>
|
||
|
*
|
||
|
* @param bssid BSSID of the network.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
public @NonNull Builder setBssid(@NonNull MacAddress bssid) {
|
||
|
checkNotNull(bssid);
|
||
|
mBssid = MacAddress.fromBytes(bssid.toByteArray());
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies whether this represents an Enhanced Open (OWE) network.
|
||
|
*
|
||
|
* @param isEnhancedOpen {@code true} to indicate that the network used enhanced open,
|
||
|
* {@code false} otherwise.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
public @NonNull Builder setIsEnhancedOpen(boolean isEnhancedOpen) {
|
||
|
mIsEnhancedOpen = isEnhancedOpen;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the ASCII WPA2 passphrase for this network. Needed for authenticating to
|
||
|
* WPA2-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 setWpa2Passphrase(@NonNull String passphrase) {
|
||
|
checkNotNull(passphrase);
|
||
|
final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
|
||
|
if (!asciiEncoder.canEncode(passphrase)) {
|
||
|
throw new IllegalArgumentException("passphrase not ASCII encodable");
|
||
|
}
|
||
|
mWpa2PskPassphrase = passphrase;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the ASCII WPA3 passphrase for this network. Needed for authenticating to WPA3-SAE
|
||
|
* 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 setWpa3Passphrase(@NonNull String passphrase) {
|
||
|
checkNotNull(passphrase);
|
||
|
final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
|
||
|
if (!asciiEncoder.canEncode(passphrase)) {
|
||
|
throw new IllegalArgumentException("passphrase not ASCII encodable");
|
||
|
}
|
||
|
mWpa3SaePassphrase = passphrase;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the associated enterprise configuration for this network. Needed for authenticating
|
||
|
* 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 uses server certificate but validation
|
||
|
* is not enabled. See {@link WifiEnterpriseConfig#isServerCertValidationEnabled()}
|
||
|
*/
|
||
|
public @NonNull Builder setWpa2EnterpriseConfig(
|
||
|
@NonNull WifiEnterpriseConfig enterpriseConfig) {
|
||
|
checkNotNull(enterpriseConfig);
|
||
|
if (enterpriseConfig.isEapMethodServerCertUsed()
|
||
|
&& !enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) {
|
||
|
throw new IllegalArgumentException("Enterprise configuration mandates server "
|
||
|
+ "certificate but validation is not enabled.");
|
||
|
}
|
||
|
mWpa2EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the associated enterprise configuration for this network. Needed for authenticating
|
||
|
* to WPA3-Enterprise networks (standard and 192-bit security). See
|
||
|
* {@link WifiEnterpriseConfig} for description. For 192-bit security networks, both the
|
||
|
* client and CA certificates must be provided, and must be of type of either
|
||
|
* sha384WithRSAEncryption (OID 1.2.840.113549.1.1.12) or ecdsa-with-SHA384
|
||
|
* (OID 1.2.840.10045.4.3.3).
|
||
|
*
|
||
|
* @deprecated use {@link #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)} or
|
||
|
* {@link #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig)} to specify
|
||
|
* WPA3-Enterprise type explicitly.
|
||
|
*
|
||
|
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
* @throws IllegalArgumentException If configuration uses server certificate but validation
|
||
|
* is not enabled. See {@link WifiEnterpriseConfig#isServerCertValidationEnabled()}
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public @NonNull Builder setWpa3EnterpriseConfig(
|
||
|
@NonNull WifiEnterpriseConfig enterpriseConfig) {
|
||
|
checkNotNull(enterpriseConfig);
|
||
|
if (enterpriseConfig.isEapMethodServerCertUsed()
|
||
|
&& !enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) {
|
||
|
throw new IllegalArgumentException("Enterprise configuration mandates server "
|
||
|
+ "certificate but validation is not enabled.");
|
||
|
}
|
||
|
mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the associated enterprise configuration for this network. Needed for authenticating
|
||
|
* to WPA3-Enterprise standard networks. See {@link WifiEnterpriseConfig} for description.
|
||
|
* For WPA3-Enterprise in 192-bit security mode networks,
|
||
|
* see {@link #setWpa3Enterprise192BitModeConfig(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 uses server certificate but validation
|
||
|
* is not enabled. See {@link WifiEnterpriseConfig#isServerCertValidationEnabled()}
|
||
|
*/
|
||
|
public @NonNull Builder setWpa3EnterpriseStandardModeConfig(
|
||
|
@NonNull WifiEnterpriseConfig enterpriseConfig) {
|
||
|
checkNotNull(enterpriseConfig);
|
||
|
if (enterpriseConfig.isEapMethodServerCertUsed()
|
||
|
&& !enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) {
|
||
|
throw new IllegalArgumentException("Enterprise configuration mandates server "
|
||
|
+ "certificate but validation is not enabled.");
|
||
|
}
|
||
|
mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
|
||
|
mWpa3EnterpriseType = WPA3_ENTERPRISE_STANDARD;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the associated enterprise configuration for this network. Needed for authenticating
|
||
|
* to WPA3-Enterprise in 192-bit security mode networks. See {@link WifiEnterpriseConfig}
|
||
|
* for description. Both the client and CA certificates must be provided,
|
||
|
* and must be of type of either sha384WithRSAEncryption with key length of 3072bit or
|
||
|
* more (OID 1.2.840.113549.1.1.12), or ecdsa-with-SHA384 with key length of 384bit or
|
||
|
* more (OID 1.2.840.10045.4.3.3).
|
||
|
*
|
||
|
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
* @throws IllegalArgumentException if the EAP type or certificates do not
|
||
|
* meet 192-bit mode requirements.
|
||
|
*/
|
||
|
public @NonNull Builder setWpa3Enterprise192BitModeConfig(
|
||
|
@NonNull WifiEnterpriseConfig enterpriseConfig) {
|
||
|
checkNotNull(enterpriseConfig);
|
||
|
if (enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.TLS) {
|
||
|
throw new IllegalArgumentException("The 192-bit mode network type must be TLS");
|
||
|
}
|
||
|
if (!WifiEnterpriseConfig.isSuiteBCipherCert(
|
||
|
enterpriseConfig.getClientCertificate())) {
|
||
|
throw new IllegalArgumentException(
|
||
|
"The client certificate does not meet 192-bit mode requirements.");
|
||
|
}
|
||
|
if (!WifiEnterpriseConfig.isSuiteBCipherCert(
|
||
|
enterpriseConfig.getCaCertificate())) {
|
||
|
throw new IllegalArgumentException(
|
||
|
"The CA certificate does not meet 192-bit mode requirements.");
|
||
|
}
|
||
|
|
||
|
mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
|
||
|
mWpa3EnterpriseType = WPA3_ENTERPRISE_192_BIT;
|
||
|
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 = new PasspointConfiguration(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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Configure the suggestion to only be used with the SIM identified by the subscription
|
||
|
* ID specified in this method. The suggested network will only be used by that SIM and
|
||
|
* no other SIM - even from the same carrier.
|
||
|
* <p>
|
||
|
* The caller is restricted to be either of:
|
||
|
* <li>A carrier provisioning app (which holds the
|
||
|
* {@code android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission).
|
||
|
* <li>A carrier-privileged app - which is restricted to only specify a subscription ID
|
||
|
* which belong to the same carrier which signed the app, see
|
||
|
* {@link TelephonyManager#hasCarrierPrivileges()}.
|
||
|
* <p>
|
||
|
* Specifying a subscription ID which doesn't match these restriction will cause the
|
||
|
* suggestion to be rejected with the error code
|
||
|
* {@link WifiManager#STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED}.
|
||
|
*
|
||
|
* Only one of the {@link #setSubscriptionGroup(ParcelUuid)} and
|
||
|
* {@link #setSubscriptionId(int)} should be called for a suggestion.
|
||
|
*
|
||
|
* @param subscriptionId subscription ID see {@link SubscriptionInfo#getSubscriptionId()}
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
* @throws IllegalArgumentException if subscriptionId equals to {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||
|
public @NonNull Builder setSubscriptionId(int subscriptionId) {
|
||
|
if (!SdkLevel.isAtLeastS()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||
|
throw new IllegalArgumentException("Subscription Id is invalid");
|
||
|
}
|
||
|
mSubscriptionId = subscriptionId;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Configure the suggestion to only be used with the SIMs that belong to the Subscription
|
||
|
* Group specified in this method. The suggested network will only be used by the SIM in
|
||
|
* this Subscription Group and no other SIMs - even from the same carrier.
|
||
|
* <p>
|
||
|
* The caller is restricted to be either of:
|
||
|
* <li>A carrier provisioning app.
|
||
|
* <li>A carrier-privileged app - which is restricted to only specify a subscription ID
|
||
|
* which belong to the same carrier which signed the app, see
|
||
|
* {@link TelephonyManager#hasCarrierPrivileges()}.
|
||
|
* <p>
|
||
|
* Specifying a subscription group which doesn't match these restriction will cause the
|
||
|
* suggestion to be rejected with the error code
|
||
|
* {@link WifiManager#STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED}.
|
||
|
*
|
||
|
* Only one of the {@link #setSubscriptionGroup(ParcelUuid)} and
|
||
|
* {@link #setSubscriptionId(int)} should be called for a suggestion.
|
||
|
*
|
||
|
* @param groupUuid Subscription group UUID see
|
||
|
* {@link SubscriptionManager#createSubscriptionGroup(List)}
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
* @throws IllegalArgumentException if group UUID is {@code null}.
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||
|
public @NonNull Builder setSubscriptionGroup(@NonNull ParcelUuid groupUuid) {
|
||
|
if (!SdkLevel.isAtLeastT()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
if (groupUuid == null) {
|
||
|
throw new IllegalArgumentException("SubscriptionGroup is invalid");
|
||
|
}
|
||
|
mSubscriptionGroup = groupUuid;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suggested networks are considered as part of a pool of all suggested networks and other
|
||
|
* networks (e.g. saved networks) - one of which will be selected.
|
||
|
* <ul>
|
||
|
* <li> Any app can suggest any number of networks. </li>
|
||
|
* <li> Priority: only the highest priority (0 being the lowest) currently visible suggested
|
||
|
* network or networks (multiple suggested networks may have the same priority) are added to
|
||
|
* the network selection pool.</li>
|
||
|
* </ul>
|
||
|
* <p>
|
||
|
* However, this restricts a suggesting app to have a single group of networks which can be
|
||
|
* prioritized. In some circumstances multiple groups are useful: for instance, suggesting
|
||
|
* networks for 2 different SIMs - each of which may have its own priority order.
|
||
|
* <p>
|
||
|
* Priority group: creates a separate priority group. Only the highest priority, currently
|
||
|
* visible suggested network or networks, within each priority group are included in the
|
||
|
* network selection pool.
|
||
|
* <p>
|
||
|
* Specify an arbitrary integer only used as the priority group. Use with
|
||
|
* {@link #setPriority(int)}.
|
||
|
*
|
||
|
* @param priorityGroup priority group id, if not set default is 0.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
public @NonNull Builder setPriorityGroup(@IntRange(from = 0) int priorityGroup) {
|
||
|
mPriorityGroup = priorityGroup;
|
||
|
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>
|
||
|
*
|
||
|
* @param isHiddenSsid {@code true} to indicate that the network is hidden, {@code false}
|
||
|
* otherwise.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
public @NonNull Builder setIsHiddenSsid(boolean isHiddenSsid) {
|
||
|
mIsHiddenSSID = isHiddenSsid;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies the MAC randomization method.
|
||
|
* <p>
|
||
|
* Suggested networks will never use the device (factory) MAC address to associate to the
|
||
|
* network - instead they use a locally generated random MAC address. This method controls
|
||
|
* the strategy for generating the random MAC address. If not set, defaults to
|
||
|
* {@link #RANDOMIZATION_PERSISTENT}.
|
||
|
*
|
||
|
* @param macRandomizationSetting - one of {@code RANDOMIZATION_*} values
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
public @NonNull Builder setMacRandomizationSetting(
|
||
|
@MacRandomizationSetting int macRandomizationSetting) {
|
||
|
switch (macRandomizationSetting) {
|
||
|
case RANDOMIZATION_PERSISTENT:
|
||
|
case RANDOMIZATION_NON_PERSISTENT:
|
||
|
mMacRandomizationSetting = macRandomizationSetting;
|
||
|
break;
|
||
|
default:
|
||
|
throw new IllegalArgumentException();
|
||
|
}
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies whether the app needs to log in to a captive portal to obtain Internet access.
|
||
|
* <p>
|
||
|
* This will dictate if the directed broadcast
|
||
|
* {@link WifiManager#ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} will be sent to the
|
||
|
* app after successfully connecting to the network.
|
||
|
* Use this for captive portal type networks where the app needs to authenticate the user
|
||
|
* before the device can access the network.
|
||
|
* <p>
|
||
|
* <li>If not set, defaults to false (i.e no app interaction required).</li>
|
||
|
*
|
||
|
* @param isAppInteractionRequired {@code true} to indicate that app interaction is
|
||
|
* required, {@code false} otherwise.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
public @NonNull Builder setIsAppInteractionRequired(boolean isAppInteractionRequired) {
|
||
|
mIsAppInteractionRequired = isAppInteractionRequired;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies whether the user needs to log in to a captive portal to obtain Internet access.
|
||
|
* <p>
|
||
|
* <li>If not set, defaults to false (i.e no user interaction required).</li>
|
||
|
*
|
||
|
* @param isUserInteractionRequired {@code true} to indicate that user interaction is
|
||
|
* required, {@code false} otherwise.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
public @NonNull Builder setIsUserInteractionRequired(boolean isUserInteractionRequired) {
|
||
|
mIsUserInteractionRequired = isUserInteractionRequired;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specify the priority of this network among other network suggestions provided by the same
|
||
|
* app and within the same priority group, see {@link #setPriorityGroup(int)}. Priorities
|
||
|
* have no impact on suggestions by other apps or suggestions from the same app using a
|
||
|
* different priority group. The higher the number, the higher the priority
|
||
|
* (i.e value of 0 = lowest priority). If not set, defaults to a lower priority than any
|
||
|
* assigned priority.
|
||
|
*
|
||
|
* @param priority Integer number representing the priority among suggestions by the app.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
* @throws IllegalArgumentException if the priority value is negative.
|
||
|
*/
|
||
|
public @NonNull Builder setPriority(@IntRange(from = 0) int priority) {
|
||
|
if (priority < 0) {
|
||
|
throw new IllegalArgumentException("Invalid priority value " + priority);
|
||
|
}
|
||
|
mPriority = priority;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies whether this network is metered.
|
||
|
* <p>
|
||
|
* <li>If not set, defaults to detect automatically.</li>
|
||
|
*
|
||
|
* @param isMetered {@code true} to indicate that the network is metered, {@code false}
|
||
|
* for not metered.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
public @NonNull Builder setIsMetered(boolean 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 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> These suggestions are only considered for network selection if a
|
||
|
* {@link NetworkRequest} without {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED}
|
||
|
* capability is filed.
|
||
|
* <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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies whether the system will bring up the network (if selected) as restricted. A
|
||
|
* restricted network has its {@link NetworkCapabilities#NET_CAPABILITY_NOT_RESTRICTED}
|
||
|
* 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> These suggestions are only considered for network selection if a
|
||
|
* {@link NetworkRequest} without {@link NetworkCapabilities#NET_CAPABILITY_NOT_RESTRICTED}
|
||
|
* capability is filed.
|
||
|
* <li> A restricted 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 unrestricted).</li>
|
||
|
*
|
||
|
* @param isRestricted Boolean indicating whether the network should be brought up
|
||
|
* restricted (if true) or unrestricted (if false).
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
public @NonNull Builder setRestricted(boolean isRestricted) {
|
||
|
mIsNetworkRestricted = isRestricted;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets whether Wi-Fi 7 is enabled for this network.
|
||
|
*
|
||
|
* @param enabled Enable Wi-Fi 7 if true, otherwise disable Wi-Fi 7
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
|
||
|
public @NonNull Builder setWifi7Enabled(boolean enabled) {
|
||
|
mIsWifi7Enabled = enabled;
|
||
|
return this;
|
||
|
}
|
||
|
/**
|
||
|
* Specifies whether the system will bring up the network (if selected) as OEM paid. An
|
||
|
* OEM paid network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID} capability
|
||
|
* added.
|
||
|
* Note:
|
||
|
* <li>The connectivity service may use this information to influence the overall
|
||
|
* network configuration of the device. This network is typically only available to system
|
||
|
* apps.
|
||
|
* <li>On devices which do not support concurrent connection (indicated via
|
||
|
* {@link WifiManager#isStaConcurrencyForRestrictedConnectionsSupported()}), 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).
|
||
|
* <li>On devices which support concurrent connections (indicated via
|
||
|
* {@link WifiManager#isStaConcurrencyForRestrictedConnectionsSupported()}), these
|
||
|
* OEM paid networks may be brought up as a secondary concurrent connection (primary
|
||
|
* connection will be used for networks available to the user and all apps.
|
||
|
* <p>
|
||
|
* <li> An OEM paid network's credentials may not be shared with the user using
|
||
|
* {@link #setCredentialSharedWithUser(boolean)}.</li>
|
||
|
* <li> These suggestions are only considered for network selection if a
|
||
|
* {@link NetworkRequest} with {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}
|
||
|
* capability is filed.
|
||
|
* <li> Each suggestion can have both {@link #setOemPaid(boolean)} and
|
||
|
* {@link #setOemPrivate(boolean)} set if the app wants these suggestions considered
|
||
|
* for creating either an OEM paid network or OEM private network determined based on
|
||
|
* the {@link NetworkRequest} that is active.
|
||
|
* <li> If not set, defaults to false (i.e. network is not OEM paid).</li>
|
||
|
*
|
||
|
* @param isOemPaid Boolean indicating whether the network should be brought up as OEM paid
|
||
|
* (if true) or not OEM paid (if false).
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi
|
||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||
|
public @NonNull Builder setOemPaid(boolean isOemPaid) {
|
||
|
if (!SdkLevel.isAtLeastS()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
mIsNetworkOemPaid = isOemPaid;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies whether the system will bring up the network (if selected) as OEM private. An
|
||
|
* OEM private network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE} capability
|
||
|
* added.
|
||
|
* Note:
|
||
|
* <li>The connectivity service may use this information to influence the overall
|
||
|
* network configuration of the device. This network is typically only available to system
|
||
|
* apps.
|
||
|
* <li>On devices which do not support concurrent connection (indicated via
|
||
|
* {@link WifiManager#isStaConcurrencyForRestrictedConnectionsSupported()}), 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).
|
||
|
* <li>On devices which support concurrent connections (indicated via
|
||
|
* {@link WifiManager#isStaConcurrencyForRestrictedConnectionsSupported()}), these OEM
|
||
|
* private networks may be brought up as a secondary concurrent connection (primary
|
||
|
* connection will be used for networks available to the user and all apps.
|
||
|
* <p>
|
||
|
* <li> An OEM private network's credentials may not be shared with the user using
|
||
|
* {@link #setCredentialSharedWithUser(boolean)}.</li>
|
||
|
* <li> These suggestions are only considered for network selection if a
|
||
|
* {@link NetworkRequest} with {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}
|
||
|
* capability is filed.
|
||
|
* <li> Each suggestion can have both {@link #setOemPaid(boolean)} and
|
||
|
* {@link #setOemPrivate(boolean)} set if the app wants these suggestions considered
|
||
|
* for creating either an OEM paid network or OEM private network determined based on
|
||
|
* the {@link NetworkRequest} that is active.
|
||
|
* <li> If not set, defaults to false (i.e. network is not OEM private).</li>
|
||
|
*
|
||
|
* @param isOemPrivate Boolean indicating whether the network should be brought up as OEM
|
||
|
* private (if true) or not OEM private (if false).
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi
|
||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||
|
public @NonNull Builder setOemPrivate(boolean isOemPrivate) {
|
||
|
if (!SdkLevel.isAtLeastS()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
mIsNetworkOemPrivate = isOemPrivate;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies whether the suggestion represents a carrier merged network. A carrier merged
|
||
|
* Wi-Fi network is treated as part of the mobile carrier network. Such configuration may
|
||
|
* impact the user interface and data usage accounting.
|
||
|
* <p>
|
||
|
* Only carriers with the
|
||
|
* {@link android.telephony.CarrierConfigManager#KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL}
|
||
|
* flag set to {@code true} may use this API.
|
||
|
* <p>
|
||
|
* <li>A suggestion marked as carrier merged must be metered enterprise network with a valid
|
||
|
* subscription Id set.
|
||
|
* @see #setIsMetered(boolean)
|
||
|
* @see #setSubscriptionId(int)
|
||
|
* @see #setWpa2EnterpriseConfig(WifiEnterpriseConfig)
|
||
|
* @see #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig)
|
||
|
* @see #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)
|
||
|
* @see #setPasspointConfig(PasspointConfiguration)
|
||
|
* </li>
|
||
|
* <li>If not set, defaults to false (i.e. not a carrier merged network.)</li>
|
||
|
* </p>
|
||
|
* @param isCarrierMerged Boolean indicating whether the network is treated a carrier
|
||
|
* merged network (if true) or non-merged network (if false);
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||
|
public @NonNull Builder setCarrierMerged(boolean isCarrierMerged) {
|
||
|
if (!SdkLevel.isAtLeastS()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
mIsCarrierMerged = isCarrierMerged;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies whether the suggestion represents an SAE network which only
|
||
|
* accepts Hash-to-Element mode.
|
||
|
* If this is enabled, Hunting & Pecking mode is disabled and only Hash-to-Element
|
||
|
* mode is used for this network.
|
||
|
* This is only valid for an SAE network which is configured using the
|
||
|
* {@link #setWpa3Passphrase}.
|
||
|
* Before calling this API, the application should check Hash-to-Element support using
|
||
|
* {@link WifiManager#isWpa3SaeH2eSupported()}.
|
||
|
*
|
||
|
* @param enable Boolean indicating whether the network only accepts Hash-to-Element mode,
|
||
|
* default is false.
|
||
|
* @return Instance of {@link Builder} to enable chaining of the builder method.
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||
|
public @NonNull Builder setIsWpa3SaeH2eOnlyModeEnabled(boolean enable) {
|
||
|
if (!SdkLevel.isAtLeastS()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
mSaeH2eOnlyMode = enable;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
private void setSecurityParamsInWifiConfiguration(
|
||
|
@NonNull WifiConfiguration configuration) {
|
||
|
if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
|
||
|
configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
|
||
|
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
|
||
|
configuration.preSharedKey = "\"" + mWpa2PskPassphrase + "\"";
|
||
|
} else if (!TextUtils.isEmpty(mWpa3SaePassphrase)) { // WPA3-SAE network.
|
||
|
configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
|
||
|
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
|
||
|
configuration.preSharedKey = "\"" + mWpa3SaePassphrase + "\"";
|
||
|
if (mSaeH2eOnlyMode) configuration.enableSaeH2eOnlyMode(mSaeH2eOnlyMode);
|
||
|
} else if (mWpa2EnterpriseConfig != null) { // WPA-EAP network
|
||
|
configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
|
||
|
configuration.enterpriseConfig = mWpa2EnterpriseConfig;
|
||
|
} else if (mWpa3EnterpriseConfig != null) { // WPA3-Enterprise
|
||
|
if (mWpa3EnterpriseType == WPA3_ENTERPRISE_AUTO
|
||
|
&& mWpa3EnterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS
|
||
|
&& WifiEnterpriseConfig.isSuiteBCipherCert(
|
||
|
mWpa3EnterpriseConfig.getClientCertificate())
|
||
|
&& WifiEnterpriseConfig.isSuiteBCipherCert(
|
||
|
mWpa3EnterpriseConfig.getCaCertificate())) {
|
||
|
// WPA3-Enterprise in 192-bit security mode
|
||
|
configuration.setSecurityParams(
|
||
|
WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
|
||
|
} else if (mWpa3EnterpriseType == WPA3_ENTERPRISE_192_BIT) {
|
||
|
// WPA3-Enterprise in 192-bit security mode
|
||
|
configuration.setSecurityParams(
|
||
|
WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
|
||
|
} else {
|
||
|
// WPA3-Enterprise
|
||
|
configuration.setSecurityParams(
|
||
|
WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
|
||
|
}
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Helper method to build WifiConfiguration object from the builder.
|
||
|
* @return Instance of {@link WifiConfiguration}.
|
||
|
*/
|
||
|
private WifiConfiguration buildWifiConfiguration() {
|
||
|
final WifiConfiguration wifiConfiguration = new WifiConfiguration();
|
||
|
// WifiConfiguration.SSID needs quotes around unicode SSID.
|
||
|
wifiConfiguration.SSID = mWifiSsid.toString();
|
||
|
if (mBssid != null) {
|
||
|
wifiConfiguration.BSSID = mBssid.toString();
|
||
|
}
|
||
|
|
||
|
setSecurityParamsInWifiConfiguration(wifiConfiguration);
|
||
|
|
||
|
wifiConfiguration.hiddenSSID = mIsHiddenSSID;
|
||
|
wifiConfiguration.priority = mPriority;
|
||
|
wifiConfiguration.meteredOverride = mMeteredOverride;
|
||
|
wifiConfiguration.carrierId = mCarrierId;
|
||
|
wifiConfiguration.trusted = !mIsNetworkUntrusted;
|
||
|
wifiConfiguration.oemPaid = mIsNetworkOemPaid;
|
||
|
wifiConfiguration.oemPrivate = mIsNetworkOemPrivate;
|
||
|
wifiConfiguration.carrierMerged = mIsCarrierMerged;
|
||
|
wifiConfiguration.macRandomizationSetting =
|
||
|
mMacRandomizationSetting == RANDOMIZATION_NON_PERSISTENT
|
||
|
? WifiConfiguration.RANDOMIZATION_NON_PERSISTENT
|
||
|
: WifiConfiguration.RANDOMIZATION_PERSISTENT;
|
||
|
wifiConfiguration.subscriptionId = mSubscriptionId;
|
||
|
wifiConfiguration.restricted = mIsNetworkRestricted;
|
||
|
wifiConfiguration.setSubscriptionGroup(mSubscriptionGroup);
|
||
|
wifiConfiguration.setWifi7Enabled(mIsWifi7Enabled);
|
||
|
return wifiConfiguration;
|
||
|
}
|
||
|
|
||
|
private void validateSecurityParams() {
|
||
|
int numSecurityTypes = 0;
|
||
|
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, 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;
|
||
|
wifiConfiguration.oemPaid = mIsNetworkOemPaid;
|
||
|
wifiConfiguration.oemPrivate = mIsNetworkOemPrivate;
|
||
|
wifiConfiguration.carrierMerged = mIsCarrierMerged;
|
||
|
wifiConfiguration.carrierId = mCarrierId;
|
||
|
wifiConfiguration.subscriptionId = mSubscriptionId;
|
||
|
wifiConfiguration.macRandomizationSetting =
|
||
|
mMacRandomizationSetting == RANDOMIZATION_NON_PERSISTENT
|
||
|
? WifiConfiguration.RANDOMIZATION_NON_PERSISTENT
|
||
|
: WifiConfiguration.RANDOMIZATION_PERSISTENT;
|
||
|
wifiConfiguration.restricted = mIsNetworkRestricted;
|
||
|
wifiConfiguration.setSubscriptionGroup(mSubscriptionGroup);
|
||
|
wifiConfiguration.setWifi7Enabled(mIsWifi7Enabled);
|
||
|
mPasspointConfiguration.setCarrierId(mCarrierId);
|
||
|
mPasspointConfiguration.setSubscriptionId(mSubscriptionId);
|
||
|
mPasspointConfiguration.setSubscriptionGroup(mSubscriptionGroup);
|
||
|
mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride);
|
||
|
mPasspointConfiguration.setOemPrivate(mIsNetworkOemPrivate);
|
||
|
mPasspointConfiguration.setOemPaid(mIsNetworkOemPaid);
|
||
|
mPasspointConfiguration.setCarrierMerged(mIsCarrierMerged);
|
||
|
// MAC randomization should always be enabled for passpoint suggestions regardless of
|
||
|
// the PasspointConfiguration's original setting.
|
||
|
mPasspointConfiguration.setMacRandomizationEnabled(true);
|
||
|
mPasspointConfiguration.setNonPersistentMacRandomizationEnabled(
|
||
|
mMacRandomizationSetting == RANDOMIZATION_NON_PERSISTENT);
|
||
|
return wifiConfiguration;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a network suggestion object for use in
|
||
|
* {@link WifiManager#addNetworkSuggestions(List)}.
|
||
|
*
|
||
|
*<p class="note">
|
||
|
* <b>Note:</b> Apps can set a combination of SSID using {@link #setSsid(String)} and BSSID
|
||
|
* using {@link #setBssid(MacAddress)} to provide more fine grained network suggestions to
|
||
|
* the platform.
|
||
|
* </p>
|
||
|
*
|
||
|
* For example:
|
||
|
* 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();
|
||
|
* final WifiNetworkSuggestion suggestion2 =
|
||
|
* new Builder()
|
||
|
* .setSsid("test222222")
|
||
|
* .setWpa2Passphrase("test123456")
|
||
|
* .build();
|
||
|
* final WifiNetworkSuggestion suggestion3 =
|
||
|
* new Builder()
|
||
|
* .setSsid("test333333")
|
||
|
* .setWpa3Passphrase("test6789")
|
||
|
* .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);
|
||
|
* wifiManager.addNetworkSuggestions(suggestionsList);
|
||
|
* // ...
|
||
|
* }</pre>
|
||
|
*
|
||
|
* @return Instance of {@link WifiNetworkSuggestion}
|
||
|
* @throws IllegalStateException on invalid params set
|
||
|
* @see WifiNetworkSuggestion
|
||
|
*/
|
||
|
public @NonNull WifiNetworkSuggestion build() {
|
||
|
validateSecurityParams();
|
||
|
WifiConfiguration wifiConfiguration;
|
||
|
if (mPasspointConfiguration != null) {
|
||
|
if (mWifiSsid != 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 (mWifiSsid == null) {
|
||
|
throw new IllegalStateException("setSsid should be invoked for suggestion");
|
||
|
}
|
||
|
if (mWifiSsid.getBytes().length == 0) {
|
||
|
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");
|
||
|
}
|
||
|
if (TextUtils.isEmpty(mWpa3SaePassphrase) && mSaeH2eOnlyMode) {
|
||
|
throw new IllegalStateException(
|
||
|
"Hash-to-Element only mode is only allowed for the SAE network");
|
||
|
}
|
||
|
|
||
|
wifiConfiguration = buildWifiConfiguration();
|
||
|
if (wifiConfiguration.isOpenNetwork()) {
|
||
|
if (mIsSharedWithUserSet && mIsSharedWithUser) {
|
||
|
throw new IllegalStateException("Open network should not be "
|
||
|
+ "setCredentialSharedWithUser to true");
|
||
|
}
|
||
|
mIsSharedWithUser = false;
|
||
|
}
|
||
|
}
|
||
|
if (!mIsSharedWithUser && !mIsInitialAutojoinEnabled) {
|
||
|
throw new IllegalStateException("Should have not a network with both "
|
||
|
+ "setCredentialSharedWithUser and "
|
||
|
+ "setIsAutojoinEnabled set to false");
|
||
|
}
|
||
|
if (mIsNetworkUntrusted || mIsNetworkRestricted) {
|
||
|
if (mIsSharedWithUserSet && mIsSharedWithUser) {
|
||
|
throw new IllegalStateException("Should not be both"
|
||
|
+ "setCredentialSharedWithUser and +"
|
||
|
+ "setUntrusted or setRestricted to true");
|
||
|
}
|
||
|
mIsSharedWithUser = false;
|
||
|
}
|
||
|
if (mIsNetworkOemPaid) {
|
||
|
if (mIsSharedWithUserSet && mIsSharedWithUser) {
|
||
|
throw new IllegalStateException("Should not be both"
|
||
|
+ "setCredentialSharedWithUser and +"
|
||
|
+ "setOemPaid to true");
|
||
|
}
|
||
|
mIsSharedWithUser = false;
|
||
|
}
|
||
|
if (mIsNetworkOemPrivate) {
|
||
|
if (mIsSharedWithUserSet && mIsSharedWithUser) {
|
||
|
throw new IllegalStateException("Should not be both"
|
||
|
+ "setCredentialSharedWithUser and +"
|
||
|
+ "setOemPrivate to true");
|
||
|
}
|
||
|
mIsSharedWithUser = false;
|
||
|
}
|
||
|
if (mIsCarrierMerged) {
|
||
|
if ((mSubscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||
|
&& mSubscriptionGroup == null)
|
||
|
|| mMeteredOverride != WifiConfiguration.METERED_OVERRIDE_METERED
|
||
|
|| !isEnterpriseSuggestion()) {
|
||
|
throw new IllegalStateException("A carrier merged network must be a metered, "
|
||
|
+ "enterprise network with valid subscription Id");
|
||
|
}
|
||
|
}
|
||
|
if (mSubscriptionGroup != null
|
||
|
&& mSubscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||
|
throw new IllegalStateException("Should not be set both SubscriptionGroup and "
|
||
|
+ "SubscriptionId");
|
||
|
}
|
||
|
return new WifiNetworkSuggestion(
|
||
|
wifiConfiguration,
|
||
|
mPasspointConfiguration,
|
||
|
mIsAppInteractionRequired,
|
||
|
mIsUserInteractionRequired,
|
||
|
mIsSharedWithUser,
|
||
|
mIsInitialAutojoinEnabled,
|
||
|
mPriorityGroup);
|
||
|
}
|
||
|
|
||
|
private boolean isEnterpriseSuggestion() {
|
||
|
return !(mWpa2EnterpriseConfig == null && mWpa3EnterpriseConfig == null
|
||
|
&& mWapiEnterpriseConfig == null && mPasspointConfiguration == null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* 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
|
||
|
*/
|
||
|
public final boolean isAppInteractionRequired;
|
||
|
|
||
|
/**
|
||
|
* Whether user needs to log in to captive portal to obtain Internet access.
|
||
|
* @hide
|
||
|
*/
|
||
|
public final boolean isUserInteractionRequired;
|
||
|
|
||
|
/**
|
||
|
* Whether app share credential with the user, allow user use provided credential to
|
||
|
* connect network manually.
|
||
|
* @hide
|
||
|
*/
|
||
|
public final boolean isUserAllowedToManuallyConnect;
|
||
|
|
||
|
/**
|
||
|
* Whether the suggestion will be initialized as auto-joined or not.
|
||
|
* @hide
|
||
|
*/
|
||
|
public final boolean isInitialAutoJoinEnabled;
|
||
|
|
||
|
/**
|
||
|
* Priority group ID.
|
||
|
* @hide
|
||
|
*/
|
||
|
public final int priorityGroup;
|
||
|
|
||
|
/** @hide */
|
||
|
public WifiNetworkSuggestion() {
|
||
|
this.wifiConfiguration = new WifiConfiguration();
|
||
|
this.passpointConfiguration = null;
|
||
|
this.isAppInteractionRequired = false;
|
||
|
this.isUserInteractionRequired = false;
|
||
|
this.isUserAllowedToManuallyConnect = true;
|
||
|
this.isInitialAutoJoinEnabled = true;
|
||
|
this.priorityGroup = 0;
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
public WifiNetworkSuggestion(@NonNull WifiConfiguration networkConfiguration,
|
||
|
@Nullable PasspointConfiguration passpointConfiguration,
|
||
|
boolean isAppInteractionRequired,
|
||
|
boolean isUserInteractionRequired,
|
||
|
boolean isUserAllowedToManuallyConnect,
|
||
|
boolean isInitialAutoJoinEnabled, int priorityGroup) {
|
||
|
checkNotNull(networkConfiguration);
|
||
|
this.wifiConfiguration = networkConfiguration;
|
||
|
this.passpointConfiguration = passpointConfiguration;
|
||
|
|
||
|
this.isAppInteractionRequired = isAppInteractionRequired;
|
||
|
this.isUserInteractionRequired = isUserInteractionRequired;
|
||
|
this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
|
||
|
this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled;
|
||
|
this.priorityGroup = priorityGroup;
|
||
|
}
|
||
|
|
||
|
public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
|
||
|
new Creator<WifiNetworkSuggestion>() {
|
||
|
@Override
|
||
|
public WifiNetworkSuggestion createFromParcel(Parcel in) {
|
||
|
return new WifiNetworkSuggestion(
|
||
|
in.readParcelable(null), // wifiConfiguration
|
||
|
in.readParcelable(null), // PasspointConfiguration
|
||
|
in.readBoolean(), // isAppInteractionRequired
|
||
|
in.readBoolean(), // isUserInteractionRequired
|
||
|
in.readBoolean(), // isSharedCredentialWithUser
|
||
|
in.readBoolean(), // isAutojoinEnabled
|
||
|
in.readInt() // priorityGroup
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public WifiNetworkSuggestion[] newArray(int size) {
|
||
|
return new WifiNetworkSuggestion[size];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void writeToParcel(Parcel dest, int flags) {
|
||
|
dest.writeParcelable(wifiConfiguration, flags);
|
||
|
dest.writeParcelable(passpointConfiguration, flags);
|
||
|
dest.writeBoolean(isAppInteractionRequired);
|
||
|
dest.writeBoolean(isUserInteractionRequired);
|
||
|
dest.writeBoolean(isUserAllowedToManuallyConnect);
|
||
|
dest.writeBoolean(isInitialAutoJoinEnabled);
|
||
|
dest.writeInt(priorityGroup);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID,
|
||
|
wifiConfiguration.getDefaultSecurityType(),
|
||
|
wifiConfiguration.getPasspointUniqueId(),
|
||
|
wifiConfiguration.subscriptionId, wifiConfiguration.carrierId,
|
||
|
wifiConfiguration.getSubscriptionGroup());
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean equals(Object obj) {
|
||
|
if (this == obj) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!(obj instanceof WifiNetworkSuggestion)) {
|
||
|
return false;
|
||
|
}
|
||
|
WifiNetworkSuggestion lhs = (WifiNetworkSuggestion) obj;
|
||
|
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)
|
||
|
&& TextUtils.equals(this.wifiConfiguration.getDefaultSecurityType(),
|
||
|
lhs.wifiConfiguration.getDefaultSecurityType())
|
||
|
&& TextUtils.equals(this.wifiConfiguration.getPasspointUniqueId(),
|
||
|
lhs.wifiConfiguration.getPasspointUniqueId())
|
||
|
&& this.wifiConfiguration.carrierId == lhs.wifiConfiguration.carrierId
|
||
|
&& this.wifiConfiguration.subscriptionId == lhs.wifiConfiguration.subscriptionId
|
||
|
&& Objects.equals(this.wifiConfiguration.getSubscriptionGroup(),
|
||
|
lhs.wifiConfiguration.getSubscriptionGroup());
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
StringBuilder sb = new StringBuilder("WifiNetworkSuggestion[ ")
|
||
|
.append("SSID=").append(wifiConfiguration.SSID)
|
||
|
.append(", BSSID=").append(wifiConfiguration.BSSID)
|
||
|
.append(", FQDN=").append(wifiConfiguration.FQDN)
|
||
|
.append(", SecurityParams=");
|
||
|
wifiConfiguration.getSecurityParamsList().stream()
|
||
|
.forEach(param -> {
|
||
|
sb.append(" ");
|
||
|
sb.append(WifiConfiguration.getSecurityTypeName(param.getSecurityType()));
|
||
|
if (param.isAddedByAutoUpgrade()) sb.append("^");
|
||
|
});
|
||
|
sb.append(", isAppInteractionRequired=").append(isAppInteractionRequired)
|
||
|
.append(", isUserInteractionRequired=").append(isUserInteractionRequired)
|
||
|
.append(", isCredentialSharedWithUser=").append(isUserAllowedToManuallyConnect)
|
||
|
.append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
|
||
|
.append(", isUnTrusted=").append(!wifiConfiguration.trusted)
|
||
|
.append(", isOemPaid=").append(wifiConfiguration.oemPaid)
|
||
|
.append(", isOemPrivate=").append(wifiConfiguration.oemPrivate)
|
||
|
.append(", isCarrierMerged=").append(wifiConfiguration.carrierMerged)
|
||
|
.append(", isHiddenSsid=").append(wifiConfiguration.hiddenSSID)
|
||
|
.append(", priorityGroup=").append(priorityGroup)
|
||
|
.append(", subscriptionId=").append(wifiConfiguration.subscriptionId)
|
||
|
.append(", subscriptionGroup=").append(wifiConfiguration.getSubscriptionGroup())
|
||
|
.append(", carrierId=").append(wifiConfiguration.carrierId)
|
||
|
.append(", priority=").append(wifiConfiguration.priority)
|
||
|
.append(", meteredness=").append(wifiConfiguration.meteredOverride)
|
||
|
.append(", restricted=").append(wifiConfiguration.restricted)
|
||
|
.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 unicode SSID of the network, or null if this is a Passpoint network or the SSID is
|
||
|
* non-unicode.
|
||
|
* <p>
|
||
|
* Note: use {@link #getWifiSsid()} which supports both unicode and non-unicode SSID.
|
||
|
* @see Builder#setSsid(String)
|
||
|
*/
|
||
|
@Nullable
|
||
|
public String getSsid() {
|
||
|
if (wifiConfiguration.SSID == null) {
|
||
|
return null;
|
||
|
}
|
||
|
WifiSsid wifiSsid;
|
||
|
try {
|
||
|
wifiSsid = WifiSsid.fromString(wifiConfiguration.SSID);
|
||
|
} catch (IllegalArgumentException e) {
|
||
|
return null;
|
||
|
}
|
||
|
if (wifiSsid.getUtf8Text() == null) {
|
||
|
return null;
|
||
|
}
|
||
|
return wifiSsid.getUtf8Text().toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the {@link WifiSsid} of the network, or null if this is a Passpoint network.
|
||
|
* @see Builder#setWifiSsid(WifiSsid)
|
||
|
* @return An object representing the SSID the network. {@code null} for passpoint network.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public WifiSsid getWifiSsid() {
|
||
|
if (wifiConfiguration.SSID == null) {
|
||
|
return null;
|
||
|
}
|
||
|
WifiSsid wifiSsid;
|
||
|
try {
|
||
|
wifiSsid = WifiSsid.fromString(wifiConfiguration.SSID);
|
||
|
} catch (IllegalArgumentException e) {
|
||
|
throw new IllegalStateException("Invalid SSID in the network suggestion");
|
||
|
}
|
||
|
return wifiSsid;
|
||
|
}
|
||
|
|
||
|
/** @see Builder#setUntrusted(boolean) */
|
||
|
public boolean isUntrusted() {
|
||
|
return !wifiConfiguration.trusted;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return if a suggestion is for a restricted network
|
||
|
* @see Builder#setRestricted(boolean)
|
||
|
* @return true if the suggestion is restricted, false otherwise
|
||
|
*/
|
||
|
public boolean isRestricted() {
|
||
|
return wifiConfiguration.restricted;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see Builder#setOemPaid(boolean)
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi
|
||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||
|
public boolean isOemPaid() {
|
||
|
if (!SdkLevel.isAtLeastS()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
return wifiConfiguration.oemPaid;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see Builder#setOemPrivate(boolean)
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi
|
||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||
|
public boolean isOemPrivate() {
|
||
|
if (!SdkLevel.isAtLeastS()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
return wifiConfiguration.oemPrivate;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see Builder#setCarrierMerged(boolean)
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||
|
public boolean isCarrierMerged() {
|
||
|
if (!SdkLevel.isAtLeastS()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
return wifiConfiguration.carrierMerged;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the WifiEnterpriseConfig, or null if unset.
|
||
|
* @see Builder#setWapiEnterpriseConfig(WifiEnterpriseConfig)
|
||
|
* @see Builder#setWpa2EnterpriseConfig(WifiEnterpriseConfig)
|
||
|
* @see Builder#setWpa3EnterpriseConfig(WifiEnterpriseConfig)
|
||
|
*/
|
||
|
@Nullable
|
||
|
public WifiEnterpriseConfig getEnterpriseConfig() {
|
||
|
if (!wifiConfiguration.isEnterprise()) {
|
||
|
return null;
|
||
|
}
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see Builder#setPriorityGroup(int)
|
||
|
*/
|
||
|
@IntRange(from = 0)
|
||
|
public int getPriorityGroup() {
|
||
|
return priorityGroup;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see Builder#setSubscriptionId(int)
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.S)
|
||
|
public int getSubscriptionId() {
|
||
|
if (!SdkLevel.isAtLeastS()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
return wifiConfiguration.subscriptionId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see Builder#setCarrierId(int)
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi
|
||
|
public int getCarrierId() {
|
||
|
return wifiConfiguration.carrierId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the MAC randomization method.
|
||
|
* @return one of {@code RANDOMIZATION_*} values
|
||
|
* @see Builder#setMacRandomizationSetting(int)
|
||
|
*/
|
||
|
public @MacRandomizationSetting int getMacRandomizationSetting() {
|
||
|
return wifiConfiguration.macRandomizationSetting
|
||
|
== WifiConfiguration.RANDOMIZATION_NON_PERSISTENT
|
||
|
? RANDOMIZATION_NON_PERSISTENT : RANDOMIZATION_PERSISTENT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the subscription Group UUID of the suggestion
|
||
|
* @see Builder#setSubscriptionGroup(ParcelUuid)
|
||
|
* @return Uuid represent a Subscription Group
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||
|
public @Nullable ParcelUuid getSubscriptionGroup() {
|
||
|
if (!SdkLevel.isAtLeastT()) {
|
||
|
throw new UnsupportedOperationException();
|
||
|
}
|
||
|
return wifiConfiguration.getSubscriptionGroup();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* See {@link Builder#setWifi7Enabled(boolean)}
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
|
||
|
public boolean isWifi7Enabled() {
|
||
|
return wifiConfiguration.isWifi7Enabled();
|
||
|
}
|
||
|
}
|