Merge "RouteSessionInfo: Remove isValid() and override equals()/hashCode()"
diff --git a/api/system-current.txt b/api/system-current.txt
index b30897f..6da1524 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5848,7 +5848,9 @@
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();
@@ -5856,6 +5858,7 @@
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
@@ -5873,9 +5876,11 @@
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);
@@ -6114,6 +6119,8 @@
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
@@ -6155,6 +6162,7 @@
}
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);
diff --git a/wifi/java/android/net/wifi/ISoftApCallback.aidl b/wifi/java/android/net/wifi/ISoftApCallback.aidl
index 482b491..f81bcb9 100644
--- a/wifi/java/android/net/wifi/ISoftApCallback.aidl
+++ b/wifi/java/android/net/wifi/ISoftApCallback.aidl
@@ -55,9 +55,17 @@
/**
- * 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);
}
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 2b7f8af..a77d30a 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -32,6 +32,9 @@
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;
@@ -182,6 +185,22 @@
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.
*/
@@ -219,7 +238,9 @@
/** 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;
@@ -229,6 +250,9 @@
mSecurityType = securityType;
mMaxNumberOfClients = maxNumberOfClients;
mShutdownTimeoutMillis = shutdownTimeoutMillis;
+ mClientControlByUser = clientControlByUser;
+ mBlockedClientList = new ArrayList<>(blockedList);
+ mAllowedClientList = new ArrayList<>(allowedList);
}
@Override
@@ -248,13 +272,17 @@
&& 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
@@ -270,6 +298,9 @@
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();
}
@@ -284,6 +315,9 @@
dest.writeInt(mSecurityType);
dest.writeInt(mMaxNumberOfClients);
dest.writeInt(mShutdownTimeoutMillis);
+ dest.writeBoolean(mClientControlByUser);
+ dest.writeTypedList(mBlockedClientList);
+ dest.writeTypedList(mAllowedClientList);
}
@Override
@@ -299,7 +333,9 @@
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
@@ -387,6 +423,34 @@
}
/**
+ * 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.
*
@@ -403,6 +467,9 @@
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}).
@@ -417,6 +484,9 @@
mMaxNumberOfClients = 0;
mSecurityType = SECURITY_TYPE_OPEN;
mShutdownTimeoutMillis = 0;
+ mClientControlByUser = false;
+ mBlockedClientList = new ArrayList<>();
+ mAllowedClientList = new ArrayList<>();
}
/**
@@ -434,6 +504,9 @@
mMaxNumberOfClients = other.mMaxNumberOfClients;
mSecurityType = other.mSecurityType;
mShutdownTimeoutMillis = other.mShutdownTimeoutMillis;
+ mClientControlByUser = other.mClientControlByUser;
+ mBlockedClientList = new ArrayList<>(other.mBlockedClientList);
+ mAllowedClientList = new ArrayList<>(other.mAllowedClientList);
}
/**
@@ -445,7 +518,8 @@
public SoftApConfiguration build() {
return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients,
- mShutdownTimeoutMillis);
+ mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList,
+ mAllowedClientList);
}
/**
@@ -662,5 +736,82 @@
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;
+ }
}
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1baab12..729ac14 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -666,7 +666,8 @@
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
*/
@@ -691,6 +692,37 @@
@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 = {
@@ -3229,8 +3261,17 @@
/**
* 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
@@ -3460,7 +3501,8 @@
* {@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) {}
@@ -3489,6 +3531,22 @@
// 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.
+ }
}
/**
@@ -3555,6 +3613,19 @@
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);
+ });
+ }
}
/**
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index eeea7e2..6884a4e 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -25,6 +25,8 @@
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
@SmallTest
@@ -112,12 +114,18 @@
@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(
@@ -127,6 +135,9 @@
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);
@@ -238,4 +249,17 @@
.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);
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 4b83718..5bdc344 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -70,6 +70,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.net.DhcpInfo;
+import android.net.MacAddress;
import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
import android.net.wifi.WifiManager.LocalOnlyHotspotObserver;
import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
@@ -897,6 +898,25 @@
}
/*
+ * Verify client-provided callback is being called through callback proxy
+ */
+ @Test
+ public void softApCallbackProxyCallsOnBlockedClientConnecting() throws Exception {
+ WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77"));
+ ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
+ verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
+ anyInt());
+
+ callbackCaptor.getValue().onBlockedClientConnecting(testWifiClient,
+ WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS);
+ mLooper.dispatchAll();
+ verify(mSoftApCallback).onBlockedClientConnecting(testWifiClient,
+ WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS);
+ }
+
+ /*
* Verify client-provided callback is being called through callback proxy on multiple events
*/
@Test