Loading api/system-current.txt +8 −0 Original line number Diff line number Diff line Loading @@ -5848,7 +5848,9 @@ package android.net.wifi { public final class SoftApConfiguration implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List<android.net.MacAddress> getAllowedClientList(); method public int getBand(); method @NonNull public java.util.List<android.net.MacAddress> getBlockedClientList(); method @Nullable public android.net.MacAddress getBssid(); method public int getChannel(); method public int getMaxNumberOfClients(); Loading @@ -5856,6 +5858,7 @@ package android.net.wifi { method public int getSecurityType(); method public int getShutdownTimeoutMillis(); method @Nullable public String getSsid(); method public boolean isClientControlByUserEnabled(); method public boolean isHiddenSsid(); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int BAND_2GHZ = 1; // 0x1 Loading @@ -5873,9 +5876,11 @@ package android.net.wifi { ctor public SoftApConfiguration.Builder(); ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration); method @NonNull public android.net.wifi.SoftApConfiguration build(); method @NonNull public android.net.wifi.SoftApConfiguration.Builder enableClientControlByUser(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientList(@NonNull java.util.List<android.net.MacAddress>, @NonNull java.util.List<android.net.MacAddress>); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(int); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int); Loading Loading @@ -6114,6 +6119,8 @@ package android.net.wifi { field public static final int IFACE_IP_MODE_UNSPECIFIED = -1; // 0xffffffff field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0 field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1 field public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0; // 0x0 field public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1; // 0x1 field public static final int SAP_START_FAILURE_GENERAL = 0; // 0x0 field public static final int SAP_START_FAILURE_NO_CHANNEL = 1; // 0x1 field public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2; // 0x2 Loading Loading @@ -6155,6 +6162,7 @@ package android.net.wifi { } public static interface WifiManager.SoftApCallback { method public default void onBlockedClientConnecting(@NonNull android.net.wifi.WifiClient, int); method public default void onCapabilityChanged(@NonNull android.net.wifi.SoftApCapability); method public default void onConnectedClientsChanged(@NonNull java.util.List<android.net.wifi.WifiClient>); method public default void onInfoChanged(@NonNull android.net.wifi.SoftApInfo); Loading wifi/java/android/net/wifi/ISoftApCallback.aidl +9 −1 Original line number Diff line number Diff line Loading @@ -55,9 +55,17 @@ oneway interface ISoftApCallback /** * Service to manager callback providing information of softap. * Service to manager callback providing capability of softap. * * @param capability is the softap capability. {@link SoftApCapability} */ void onCapabilityChanged(in SoftApCapability capability); /** * Service to manager callback providing blocked client of softap with specific reason code. * * @param client the currently blocked client. * @param blockedReason one of blocked reason from {@link WifiManager.SapClientBlockedReason} */ void onBlockedClientConnecting(in WifiClient client, int blockedReason); } wifi/java/android/net/wifi/SoftApConfiguration.java +156 −5 Original line number Diff line number Diff line Loading @@ -32,6 +32,9 @@ 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; import java.util.concurrent.Executor; Loading Loading @@ -181,6 +184,22 @@ public final class SoftApConfiguration implements Parcelable { */ 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; /** * Delay in milliseconds before shutting down soft AP when * there are no connected devices. Loading Loading @@ -219,7 +238,9 @@ public final class SoftApConfiguration implements Parcelable { /** 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, int shutdownTimeoutMillis) { @SecurityType int securityType, int maxNumberOfClients, int shutdownTimeoutMillis, boolean clientControlByUser, @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList) { mSsid = ssid; mBssid = bssid; mPassphrase = passphrase; Loading @@ -229,6 +250,9 @@ public final class SoftApConfiguration implements Parcelable { mSecurityType = securityType; mMaxNumberOfClients = maxNumberOfClients; mShutdownTimeoutMillis = shutdownTimeoutMillis; mClientControlByUser = clientControlByUser; mBlockedClientList = new ArrayList<>(blockedList); mAllowedClientList = new ArrayList<>(allowedList); } @Override Loading @@ -248,13 +272,17 @@ public final class SoftApConfiguration implements Parcelable { && mChannel == other.mChannel && mSecurityType == other.mSecurityType && mMaxNumberOfClients == other.mMaxNumberOfClients && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis; && 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, mShutdownTimeoutMillis); mBand, mChannel, mSecurityType, mMaxNumberOfClients, mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList, mAllowedClientList); } @Override Loading @@ -270,6 +298,9 @@ public final class SoftApConfiguration implements Parcelable { sbuf.append(" \n SecurityType=").append(getSecurityType()); sbuf.append(" \n MaxClient=").append(mMaxNumberOfClients); 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(); } Loading @@ -284,6 +315,9 @@ public final class SoftApConfiguration implements Parcelable { dest.writeInt(mSecurityType); dest.writeInt(mMaxNumberOfClients); dest.writeInt(mShutdownTimeoutMillis); dest.writeBoolean(mClientControlByUser); dest.writeTypedList(mBlockedClientList); dest.writeTypedList(mAllowedClientList); } @Override Loading @@ -299,7 +333,9 @@ public final class SoftApConfiguration implements Parcelable { in.readString(), in.readParcelable(MacAddress.class.getClassLoader()), in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readInt()); in.readInt(), in.readInt(), in.readBoolean(), in.createTypedArrayList(MacAddress.CREATOR), in.createTypedArrayList(MacAddress.CREATOR)); } @Override Loading Loading @@ -386,6 +422,34 @@ public final class SoftApConfiguration implements Parcelable { 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)}. */ 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)} */ @NonNull 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)} */ @NonNull public List<MacAddress> getAllowedClientList() { return mAllowedClientList; } /** * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a * Soft AP. Loading @@ -403,6 +467,9 @@ public final class SoftApConfiguration implements Parcelable { private int mMaxNumberOfClients; private int mSecurityType; private int mShutdownTimeoutMillis; private boolean mClientControlByUser; private List<MacAddress> mBlockedClientList; private List<MacAddress> mAllowedClientList; /** * Constructs a Builder with default values (see {@link Builder}). Loading @@ -417,6 +484,9 @@ public final class SoftApConfiguration implements Parcelable { mMaxNumberOfClients = 0; mSecurityType = SECURITY_TYPE_OPEN; mShutdownTimeoutMillis = 0; mClientControlByUser = false; mBlockedClientList = new ArrayList<>(); mAllowedClientList = new ArrayList<>(); } /** Loading @@ -434,6 +504,9 @@ public final class SoftApConfiguration implements Parcelable { mMaxNumberOfClients = other.mMaxNumberOfClients; mSecurityType = other.mSecurityType; mShutdownTimeoutMillis = other.mShutdownTimeoutMillis; mClientControlByUser = other.mClientControlByUser; mBlockedClientList = new ArrayList<>(other.mBlockedClientList); mAllowedClientList = new ArrayList<>(other.mAllowedClientList); } /** Loading @@ -445,7 +518,8 @@ public final class SoftApConfiguration implements Parcelable { public SoftApConfiguration build() { return new SoftApConfiguration(mSsid, mBssid, mPassphrase, mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients, mShutdownTimeoutMillis); mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList, mAllowedClientList); } /** Loading Loading @@ -662,5 +736,82 @@ public final class SoftApConfiguration implements Parcelable { 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; } } } wifi/java/android/net/wifi/WifiManager.java +74 −3 Original line number Diff line number Diff line Loading @@ -666,7 +666,8 @@ public class WifiManager { public @interface SapStartFailure {} /** * All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL}. * All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL} and * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. * * @hide */ Loading @@ -691,6 +692,37 @@ public class WifiManager { @SystemApi public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2; /** @hide */ @IntDef(flag = false, prefix = { "SAP_CLIENT_BLOCKED_REASON_" }, value = { SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER, SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS, }) @Retention(RetentionPolicy.SOURCE) public @interface SapClientBlockedReason {} /** * If Soft Ap client is blocked, this reason code means that client doesn't exist in the * specified configuration {@link SoftApConfiguration.Builder#setClientList(List, List)} * and the {@link SoftApConfiguration.Builder#enableClientControlByUser(true)} * is configured as well. * @hide */ @SystemApi public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0; /** * If Soft Ap client is blocked, this reason code means that no more clients can be * associated to this AP since it reached maximum capacity. The maximum capacity is * the minimum of {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} and * {@link SoftApCapability#getMaxSupportedClients} which get from * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}. * * @hide */ @SystemApi public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"IFACE_IP_MODE_"}, value = { Loading Loading @@ -3229,8 +3261,17 @@ public class WifiManager { /** * Sets the Wi-Fi AP Configuration. * * If the API is called while the soft AP is enabled, the configuration will apply to * the current soft AP if the new configuration only includes * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(int)} * or {@link SoftApConfiguration.Builder#enableClientControlByUser(boolean)} * or {@link SoftApConfiguration.Builder#setClientList(List, List)}. * * Otherwise, the configuration changes will be applied when the Soft AP is next started * (the framework will not stop/start the AP). * * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP. * @return {@code true} if the operation succeeded, {@code false} otherwise * * @hide Loading Loading @@ -3460,7 +3501,8 @@ public class WifiManager { * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} * @param failureReason reason when in failed state. One of * {@link #SAP_START_FAILURE_GENERAL}, * {@link #SAP_START_FAILURE_NO_CHANNEL} * {@link #SAP_START_FAILURE_NO_CHANNEL}, * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION} */ default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {} Loading Loading @@ -3489,6 +3531,22 @@ public class WifiManager { // Do nothing: can be updated to add SoftApCapability details (e.g. meximum supported // client number) to the UI. } /** * Called when client trying to connect but device blocked the client with specific reason. * * Can be used to ask user to update client to allowed list or blocked list * when reason is {@link SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER}, or * indicate the block due to maximum supported client number limitation when reason is * {@link SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS}. * * @param client the currently blocked client. * @param blockedReason one of blocked reason from {@link SapClientBlockedReason} */ default void onBlockedClientConnecting(@NonNull WifiClient client, @SapClientBlockedReason int blockedReason) { // Do nothing: can be used to ask user to update client to allowed list or blocked list. } } /** Loading Loading @@ -3555,6 +3613,19 @@ public class WifiManager { mCallback.onCapabilityChanged(capability); }); } @Override public void onBlockedClientConnecting(@NonNull WifiClient client, int blockedReason) { if (mVerboseLoggingEnabled) { Log.v(TAG, "SoftApCallbackProxy: onBlockedClientConnecting: client=" + client + " with reason = " + blockedReason); } Binder.clearCallingIdentity(); mExecutor.execute(() -> { mCallback.onBlockedClientConnecting(client, blockedReason); }); } } /** Loading wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Random; @SmallTest Loading Loading @@ -112,12 +114,18 @@ public class SoftApConfigurationTest { @Test public void testWpa2WithAllFieldCustomized() { List<MacAddress> testBlockedClientList = new ArrayList<>(); List<MacAddress> testAllowedClientList = new ArrayList<>(); testBlockedClientList.add(MacAddress.fromString("11:22:33:44:55:66")); testAllowedClientList.add(MacAddress.fromString("aa:bb:cc:dd:ee:ff")); SoftApConfiguration original = new SoftApConfiguration.Builder() .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) .setChannel(149, SoftApConfiguration.BAND_5GHZ) .setHiddenSsid(true) .setMaxNumberOfClients(10) .setShutdownTimeoutMillis(500000) .enableClientControlByUser(true) .setClientList(testBlockedClientList, testAllowedClientList) .build(); assertThat(original.getPassphrase()).isEqualTo("secretsecret"); assertThat(original.getSecurityType()).isEqualTo( Loading @@ -127,6 +135,9 @@ public class SoftApConfigurationTest { assertThat(original.isHiddenSsid()).isEqualTo(true); assertThat(original.getMaxNumberOfClients()).isEqualTo(10); assertThat(original.getShutdownTimeoutMillis()).isEqualTo(500000); assertThat(original.isClientControlByUserEnabled()).isEqualTo(true); assertThat(original.getBlockedClientList()).isEqualTo(testBlockedClientList); assertThat(original.getAllowedClientList()).isEqualTo(testAllowedClientList); SoftApConfiguration unparceled = parcelUnparcel(original); assertThat(unparceled).isNotSameAs(original); Loading Loading @@ -238,4 +249,17 @@ public class SoftApConfigurationTest { .setShutdownTimeoutMillis(-1) .build(); } @Test(expected = IllegalArgumentException.class) public void testsetClientListExceptionWhenExistMacAddressInBothList() { final MacAddress testMacAddress_1 = MacAddress.fromString("22:33:44:55:66:77"); final MacAddress testMacAddress_2 = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); ArrayList<MacAddress> testAllowedClientList = new ArrayList<>(); testAllowedClientList.add(testMacAddress_1); testAllowedClientList.add(testMacAddress_2); ArrayList<MacAddress> testBlockedClientList = new ArrayList<>(); testBlockedClientList.add(testMacAddress_1); SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); configBuilder.setClientList(testBlockedClientList, testAllowedClientList); } } Loading
api/system-current.txt +8 −0 Original line number Diff line number Diff line Loading @@ -5848,7 +5848,9 @@ package android.net.wifi { public final class SoftApConfiguration implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List<android.net.MacAddress> getAllowedClientList(); method public int getBand(); method @NonNull public java.util.List<android.net.MacAddress> getBlockedClientList(); method @Nullable public android.net.MacAddress getBssid(); method public int getChannel(); method public int getMaxNumberOfClients(); Loading @@ -5856,6 +5858,7 @@ package android.net.wifi { method public int getSecurityType(); method public int getShutdownTimeoutMillis(); method @Nullable public String getSsid(); method public boolean isClientControlByUserEnabled(); method public boolean isHiddenSsid(); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int BAND_2GHZ = 1; // 0x1 Loading @@ -5873,9 +5876,11 @@ package android.net.wifi { ctor public SoftApConfiguration.Builder(); ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration); method @NonNull public android.net.wifi.SoftApConfiguration build(); method @NonNull public android.net.wifi.SoftApConfiguration.Builder enableClientControlByUser(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientList(@NonNull java.util.List<android.net.MacAddress>, @NonNull java.util.List<android.net.MacAddress>); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(int); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int); Loading Loading @@ -6114,6 +6119,8 @@ package android.net.wifi { field public static final int IFACE_IP_MODE_UNSPECIFIED = -1; // 0xffffffff field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0 field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1 field public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0; // 0x0 field public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1; // 0x1 field public static final int SAP_START_FAILURE_GENERAL = 0; // 0x0 field public static final int SAP_START_FAILURE_NO_CHANNEL = 1; // 0x1 field public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2; // 0x2 Loading Loading @@ -6155,6 +6162,7 @@ package android.net.wifi { } public static interface WifiManager.SoftApCallback { method public default void onBlockedClientConnecting(@NonNull android.net.wifi.WifiClient, int); method public default void onCapabilityChanged(@NonNull android.net.wifi.SoftApCapability); method public default void onConnectedClientsChanged(@NonNull java.util.List<android.net.wifi.WifiClient>); method public default void onInfoChanged(@NonNull android.net.wifi.SoftApInfo); Loading
wifi/java/android/net/wifi/ISoftApCallback.aidl +9 −1 Original line number Diff line number Diff line Loading @@ -55,9 +55,17 @@ oneway interface ISoftApCallback /** * Service to manager callback providing information of softap. * Service to manager callback providing capability of softap. * * @param capability is the softap capability. {@link SoftApCapability} */ void onCapabilityChanged(in SoftApCapability capability); /** * Service to manager callback providing blocked client of softap with specific reason code. * * @param client the currently blocked client. * @param blockedReason one of blocked reason from {@link WifiManager.SapClientBlockedReason} */ void onBlockedClientConnecting(in WifiClient client, int blockedReason); }
wifi/java/android/net/wifi/SoftApConfiguration.java +156 −5 Original line number Diff line number Diff line Loading @@ -32,6 +32,9 @@ 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; import java.util.concurrent.Executor; Loading Loading @@ -181,6 +184,22 @@ public final class SoftApConfiguration implements Parcelable { */ 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; /** * Delay in milliseconds before shutting down soft AP when * there are no connected devices. Loading Loading @@ -219,7 +238,9 @@ public final class SoftApConfiguration implements Parcelable { /** 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, int shutdownTimeoutMillis) { @SecurityType int securityType, int maxNumberOfClients, int shutdownTimeoutMillis, boolean clientControlByUser, @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList) { mSsid = ssid; mBssid = bssid; mPassphrase = passphrase; Loading @@ -229,6 +250,9 @@ public final class SoftApConfiguration implements Parcelable { mSecurityType = securityType; mMaxNumberOfClients = maxNumberOfClients; mShutdownTimeoutMillis = shutdownTimeoutMillis; mClientControlByUser = clientControlByUser; mBlockedClientList = new ArrayList<>(blockedList); mAllowedClientList = new ArrayList<>(allowedList); } @Override Loading @@ -248,13 +272,17 @@ public final class SoftApConfiguration implements Parcelable { && mChannel == other.mChannel && mSecurityType == other.mSecurityType && mMaxNumberOfClients == other.mMaxNumberOfClients && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis; && 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, mShutdownTimeoutMillis); mBand, mChannel, mSecurityType, mMaxNumberOfClients, mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList, mAllowedClientList); } @Override Loading @@ -270,6 +298,9 @@ public final class SoftApConfiguration implements Parcelable { sbuf.append(" \n SecurityType=").append(getSecurityType()); sbuf.append(" \n MaxClient=").append(mMaxNumberOfClients); 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(); } Loading @@ -284,6 +315,9 @@ public final class SoftApConfiguration implements Parcelable { dest.writeInt(mSecurityType); dest.writeInt(mMaxNumberOfClients); dest.writeInt(mShutdownTimeoutMillis); dest.writeBoolean(mClientControlByUser); dest.writeTypedList(mBlockedClientList); dest.writeTypedList(mAllowedClientList); } @Override Loading @@ -299,7 +333,9 @@ public final class SoftApConfiguration implements Parcelable { in.readString(), in.readParcelable(MacAddress.class.getClassLoader()), in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readInt()); in.readInt(), in.readInt(), in.readBoolean(), in.createTypedArrayList(MacAddress.CREATOR), in.createTypedArrayList(MacAddress.CREATOR)); } @Override Loading Loading @@ -386,6 +422,34 @@ public final class SoftApConfiguration implements Parcelable { 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)}. */ 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)} */ @NonNull 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)} */ @NonNull public List<MacAddress> getAllowedClientList() { return mAllowedClientList; } /** * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a * Soft AP. Loading @@ -403,6 +467,9 @@ public final class SoftApConfiguration implements Parcelable { private int mMaxNumberOfClients; private int mSecurityType; private int mShutdownTimeoutMillis; private boolean mClientControlByUser; private List<MacAddress> mBlockedClientList; private List<MacAddress> mAllowedClientList; /** * Constructs a Builder with default values (see {@link Builder}). Loading @@ -417,6 +484,9 @@ public final class SoftApConfiguration implements Parcelable { mMaxNumberOfClients = 0; mSecurityType = SECURITY_TYPE_OPEN; mShutdownTimeoutMillis = 0; mClientControlByUser = false; mBlockedClientList = new ArrayList<>(); mAllowedClientList = new ArrayList<>(); } /** Loading @@ -434,6 +504,9 @@ public final class SoftApConfiguration implements Parcelable { mMaxNumberOfClients = other.mMaxNumberOfClients; mSecurityType = other.mSecurityType; mShutdownTimeoutMillis = other.mShutdownTimeoutMillis; mClientControlByUser = other.mClientControlByUser; mBlockedClientList = new ArrayList<>(other.mBlockedClientList); mAllowedClientList = new ArrayList<>(other.mAllowedClientList); } /** Loading @@ -445,7 +518,8 @@ public final class SoftApConfiguration implements Parcelable { public SoftApConfiguration build() { return new SoftApConfiguration(mSsid, mBssid, mPassphrase, mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients, mShutdownTimeoutMillis); mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList, mAllowedClientList); } /** Loading Loading @@ -662,5 +736,82 @@ public final class SoftApConfiguration implements Parcelable { 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; } } }
wifi/java/android/net/wifi/WifiManager.java +74 −3 Original line number Diff line number Diff line Loading @@ -666,7 +666,8 @@ public class WifiManager { public @interface SapStartFailure {} /** * All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL}. * All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL} and * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}. * * @hide */ Loading @@ -691,6 +692,37 @@ public class WifiManager { @SystemApi public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2; /** @hide */ @IntDef(flag = false, prefix = { "SAP_CLIENT_BLOCKED_REASON_" }, value = { SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER, SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS, }) @Retention(RetentionPolicy.SOURCE) public @interface SapClientBlockedReason {} /** * If Soft Ap client is blocked, this reason code means that client doesn't exist in the * specified configuration {@link SoftApConfiguration.Builder#setClientList(List, List)} * and the {@link SoftApConfiguration.Builder#enableClientControlByUser(true)} * is configured as well. * @hide */ @SystemApi public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0; /** * If Soft Ap client is blocked, this reason code means that no more clients can be * associated to this AP since it reached maximum capacity. The maximum capacity is * the minimum of {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} and * {@link SoftApCapability#getMaxSupportedClients} which get from * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}. * * @hide */ @SystemApi public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"IFACE_IP_MODE_"}, value = { Loading Loading @@ -3229,8 +3261,17 @@ public class WifiManager { /** * Sets the Wi-Fi AP Configuration. * * If the API is called while the soft AP is enabled, the configuration will apply to * the current soft AP if the new configuration only includes * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(int)} * or {@link SoftApConfiguration.Builder#enableClientControlByUser(boolean)} * or {@link SoftApConfiguration.Builder#setClientList(List, List)}. * * Otherwise, the configuration changes will be applied when the Soft AP is next started * (the framework will not stop/start the AP). * * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP. * @return {@code true} if the operation succeeded, {@code false} otherwise * * @hide Loading Loading @@ -3460,7 +3501,8 @@ public class WifiManager { * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} * @param failureReason reason when in failed state. One of * {@link #SAP_START_FAILURE_GENERAL}, * {@link #SAP_START_FAILURE_NO_CHANNEL} * {@link #SAP_START_FAILURE_NO_CHANNEL}, * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION} */ default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {} Loading Loading @@ -3489,6 +3531,22 @@ public class WifiManager { // Do nothing: can be updated to add SoftApCapability details (e.g. meximum supported // client number) to the UI. } /** * Called when client trying to connect but device blocked the client with specific reason. * * Can be used to ask user to update client to allowed list or blocked list * when reason is {@link SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER}, or * indicate the block due to maximum supported client number limitation when reason is * {@link SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS}. * * @param client the currently blocked client. * @param blockedReason one of blocked reason from {@link SapClientBlockedReason} */ default void onBlockedClientConnecting(@NonNull WifiClient client, @SapClientBlockedReason int blockedReason) { // Do nothing: can be used to ask user to update client to allowed list or blocked list. } } /** Loading Loading @@ -3555,6 +3613,19 @@ public class WifiManager { mCallback.onCapabilityChanged(capability); }); } @Override public void onBlockedClientConnecting(@NonNull WifiClient client, int blockedReason) { if (mVerboseLoggingEnabled) { Log.v(TAG, "SoftApCallbackProxy: onBlockedClientConnecting: client=" + client + " with reason = " + blockedReason); } Binder.clearCallingIdentity(); mExecutor.execute(() -> { mCallback.onBlockedClientConnecting(client, blockedReason); }); } } /** Loading
wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Random; @SmallTest Loading Loading @@ -112,12 +114,18 @@ public class SoftApConfigurationTest { @Test public void testWpa2WithAllFieldCustomized() { List<MacAddress> testBlockedClientList = new ArrayList<>(); List<MacAddress> testAllowedClientList = new ArrayList<>(); testBlockedClientList.add(MacAddress.fromString("11:22:33:44:55:66")); testAllowedClientList.add(MacAddress.fromString("aa:bb:cc:dd:ee:ff")); SoftApConfiguration original = new SoftApConfiguration.Builder() .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) .setChannel(149, SoftApConfiguration.BAND_5GHZ) .setHiddenSsid(true) .setMaxNumberOfClients(10) .setShutdownTimeoutMillis(500000) .enableClientControlByUser(true) .setClientList(testBlockedClientList, testAllowedClientList) .build(); assertThat(original.getPassphrase()).isEqualTo("secretsecret"); assertThat(original.getSecurityType()).isEqualTo( Loading @@ -127,6 +135,9 @@ public class SoftApConfigurationTest { assertThat(original.isHiddenSsid()).isEqualTo(true); assertThat(original.getMaxNumberOfClients()).isEqualTo(10); assertThat(original.getShutdownTimeoutMillis()).isEqualTo(500000); assertThat(original.isClientControlByUserEnabled()).isEqualTo(true); assertThat(original.getBlockedClientList()).isEqualTo(testBlockedClientList); assertThat(original.getAllowedClientList()).isEqualTo(testAllowedClientList); SoftApConfiguration unparceled = parcelUnparcel(original); assertThat(unparceled).isNotSameAs(original); Loading Loading @@ -238,4 +249,17 @@ public class SoftApConfigurationTest { .setShutdownTimeoutMillis(-1) .build(); } @Test(expected = IllegalArgumentException.class) public void testsetClientListExceptionWhenExistMacAddressInBothList() { final MacAddress testMacAddress_1 = MacAddress.fromString("22:33:44:55:66:77"); final MacAddress testMacAddress_2 = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); ArrayList<MacAddress> testAllowedClientList = new ArrayList<>(); testAllowedClientList.add(testMacAddress_1); testAllowedClientList.add(testMacAddress_2); ArrayList<MacAddress> testBlockedClientList = new ArrayList<>(); testBlockedClientList.add(testMacAddress_1); SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); configBuilder.setClientList(testBlockedClientList, testAllowedClientList); } }