| /* |
| * 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.Iterator; |
| 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 of the band types from {@link @BandType}. |
| */ |
| 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 security types from {@link @SecurityType} |
| */ |
| 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 int 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, |
| int 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.writeInt(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.readInt(), 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 {@link BandType} set to be the band for the AP. |
| * {@link Builder#setBand(@BandType 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(int)}. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public int 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#enableClientControlByUser(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#setClientList(List, 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#setClientList(List, 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; |
| if (mBssid != null) { |
| wifiConfig.BSSID = mBssid.toString(); |
| } |
| 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 int 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() { |
| 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> |
| * Only supported when configuring a local-only hotspot. |
| * <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 security types from {@link @SecurityType}. |
| * @param passphrase The passphrase to use for sepcific {@link @SecurityType} configuration |
| * or null with {@link @SecurityType#SECURITY_TYPE_OPEN}. |
| * |
| * @return Builder for chaining. |
| * @throws IllegalArgumentException when the passphrase length is invalid and |
| * {@code securityType} is not {@link @SecurityType#SECURITY_TYPE_OPEN} |
| * or non-null passphrase and {@code securityType} is |
| * {@link @SecurityType#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 BAND_2GHZ {@link @BandType}.</li> |
| * |
| * @param band One or combination of the band types from {@link @BandType}. |
| * @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(@BandType int)}. |
| * |
| * The channel auto selection will offload to driver when |
| * {@link SoftApCapability#isFeatureSupported(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#isFeatureSupported(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(int) |
| */ |
| @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) int 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 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 #setClientList(List, List)}. |
| * |
| * <p> |
| * This method requires hardware support. Hardware support can be determined using |
| * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and |
| * {@link SoftApCapability#isFeatureSupported(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 enableClientControlByUser(boolean enabled) { |
| mClientControlByUser = enabled; |
| return this; |
| } |
| |
| |
| /** |
| * This method together with {@link enableClientControlByUser(boolean)} control client |
| * connections to the AP. If {@link enableClientControlByUser(false)} is configured than |
| * this API has no effect and clients are allowed to associate to the AP (within limit of |
| * max number of clients). |
| * |
| * If {@link enableClientControlByUser(true)} is configured then this API configures |
| * 2 lists: |
| * <ul> |
| * <li>List of clients which are blocked. These are rejected.</li> |
| * <li>List of clients which are explicitly allowed. These are auto-accepted.</li> |
| * </ul> |
| * |
| * <p> |
| * 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 blockedClientList list of clients which are not allowed to associate to the AP. |
| * @param allowedClientList list of clients which are allowed to associate to the AP |
| * without user pre-approval. |
| * @return Builder for chaining. |
| */ |
| @NonNull |
| public Builder setClientList(@NonNull List<MacAddress> blockedClientList, |
| @NonNull List<MacAddress> allowedClientList) { |
| mBlockedClientList = new ArrayList<>(blockedClientList); |
| mAllowedClientList = new ArrayList<>(allowedClientList); |
| Iterator<MacAddress> iterator = mAllowedClientList.iterator(); |
| while (iterator.hasNext()) { |
| MacAddress client = iterator.next(); |
| int index = mBlockedClientList.indexOf(client); |
| if (index != -1) { |
| throw new IllegalArgumentException("A MacAddress exist in both list"); |
| } |
| } |
| return this; |
| } |
| } |
| } |