Merge changes from topic "bridged_AP_callback"

* changes:
  wifi: Add callback onConnectedClientsOrInfoChanged handling
  wifi: Add new callback to support use case in bridged mode
This commit is contained in:
Les Lee
2020-12-23 13:53:17 +00:00
committed by Android (Google) Code Review
4 changed files with 428 additions and 80 deletions

View File

@@ -639,8 +639,9 @@ package android.net.wifi {
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 onConnectedClientsChanged(@NonNull android.net.wifi.SoftApInfo, @NonNull java.util.List<android.net.wifi.WifiClient>);
method public default void onInfoChanged(@NonNull android.net.wifi.SoftApInfo);
method public default void onInfoListChanged(@NonNull java.util.List<android.net.wifi.SoftApInfo>);
method public default void onInfoChanged(@NonNull java.util.List<android.net.wifi.SoftApInfo>);
method public default void onStateChanged(int, int);
}

View File

@@ -39,26 +39,17 @@ oneway interface ISoftApCallback
*/
void onStateChanged(int state, int failureReason);
/**
* Service to manager callback providing connected client's information.
*
* @param clients the currently connected clients
*/
void onConnectedClientsChanged(in List<WifiClient> clients);
/**
* Service to manager callback providing information of softap.
*
* @param softApInfo is the softap information. {@link SoftApInfo}
*/
void onInfoChanged(in SoftApInfo softApInfo);
/**
* Service to manager callback providing informations of softap.
*
* @param softApInfoList is the list of the softap informations. {@link SoftApInfo}
* @param infos The currently {@link SoftApInfo} in each AP instance.
* @param clients The currently connected clients in each AP instance.
* @param isBridged whether or not the current AP enabled on bridged mode.
* @param isRegistration whether or not the callbackk was triggered when register.
*/
void onInfoListChanged(in List<SoftApInfo> softApInfoList);
void onConnectedClientsOrInfoChanged(in Map<String, SoftApInfo> infos,
in Map<String, List<WifiClient>> clients, boolean isBridged,
boolean isRegistration);
/**
* Service to manager callback providing capability of softap.

View File

@@ -4026,13 +4026,33 @@ public class WifiManager {
*/
default void onConnectedClientsChanged(@NonNull List<WifiClient> clients) {}
/**
* Called when the connected clients for a soft AP instance change.
*
* When the Soft AP is configured in single AP mode, this callback is invoked
* with the same {@link SoftApInfo} for all connected clients changes.
* When the Soft AP is configured in bridged mode, this callback is invoked with
* the corresponding {@link SoftApInfo} for the instance in which the connected clients
* changed.
*
* Use {@link #onConnectedClientsChanged(List<WifiClient>)} if you don't care about
* the mapping from SoftApInfo instance to connected clients.
*
* @param info The {@link SoftApInfo} of the AP.
* @param clients The currently connected clients on the AP instance specified by
* {@code info}.
*/
default void onConnectedClientsChanged(@NonNull SoftApInfo info,
@NonNull List<WifiClient> clients) {}
/**
* Called when information of softap changes.
*
* Note: this API is only valid when the Soft AP is configured as a single AP
* - not as a bridged AP (2 Soft APs). When the Soft AP is configured as bridged AP
* this callback will not be triggered - use the
* {@link #onInfoListChanged(List<SoftApInfo>)} callback in bridged AP mode.
* {@link #onInfoChanged(List<SoftApInfo>)} callback in bridged AP mode.
*
* @param softApInfo is the softap information. {@link SoftApInfo}
*/
@@ -4050,11 +4070,15 @@ public class WifiManager {
* as a single AP, and two information elements will be returned in the list
* when the Soft AP is configured in bridged mode.
*
* Note: One of the Soft APs may be shut down independently of the other by the framework,
* for instance if no devices are connected to it for some duration.
* In that case, one information element will be returned in the list in bridged mode.
*
* See {@link #isBridgedApConcurrencySupported()} for the detail of the bridged AP.
*
* @param softApInfoList is the list of the softap information elements. {@link SoftApInfo}
*/
default void onInfoListChanged(@NonNull List<SoftApInfo> softApInfoList) {
default void onInfoChanged(@NonNull List<SoftApInfo> softApInfoList) {
// Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
}
@@ -4093,6 +4117,16 @@ public class WifiManager {
private class SoftApCallbackProxy extends ISoftApCallback.Stub {
private final Executor mExecutor;
private final SoftApCallback mCallback;
private Map<String, List<WifiClient>> mCurrentClients = new HashMap<>();
private Map<String, SoftApInfo> mCurrentInfos = new HashMap<>();
private List<WifiClient> getConnectedClientList(Map<String, List<WifiClient>> clientsMap) {
List<WifiClient> connectedClientList = new ArrayList<>();
for (List<WifiClient> it : clientsMap.values()) {
connectedClientList.addAll(it);
}
return connectedClientList;
}
SoftApCallbackProxy(Executor executor, SoftApCallback callback) {
mExecutor = executor;
@@ -4113,41 +4147,84 @@ public class WifiManager {
}
@Override
public void onConnectedClientsChanged(List<WifiClient> clients) {
public void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos,
Map<String, List<WifiClient>> clients, boolean isBridged, boolean isRegistration) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "SoftApCallbackProxy: onConnectedClientsChanged: clients="
+ clients.size() + " clients");
Log.v(TAG, "SoftApCallbackProxy: onConnectedClientsOrInfoChanged: clients: "
+ clients + ", infos: " + infos + ", isBridged is " + isBridged
+ ", isRegistration is " + isRegistration);
}
Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mCallback.onConnectedClientsChanged(clients);
});
}
@Override
public void onInfoChanged(SoftApInfo softApInfo) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "SoftApCallbackProxy: onInfoChange: softApInfo=" + softApInfo);
List<SoftApInfo> changedInfoList = new ArrayList<>(infos.values());
Map<SoftApInfo, List<WifiClient>> changedInfoClients = new HashMap<>();
boolean isInfoChanged = infos.size() != mCurrentInfos.size();
for (SoftApInfo info : mCurrentInfos.values()) {
String changedInstance = info.getApInstanceIdentifier();
if (!changedInfoList.contains(info)) {
isInfoChanged = true;
if (mCurrentClients.getOrDefault(changedInstance,
Collections.emptyList()).size() > 0) {
Log.d(TAG, "SoftApCallbackProxy: info changed on client connected"
+ " instance(Shut Down case)");
//Here should notify client changed on old info
changedInfoClients.put(info, Collections.emptyList());
}
} else {
// info doesn't change, check client list
List<WifiClient> changedClientList = clients.getOrDefault(
changedInstance, Collections.emptyList());
if (changedClientList.size()
!= mCurrentClients
.getOrDefault(changedInstance, Collections.emptyList()).size()) {
// Here should notify client changed on new info(same as old info)
changedInfoClients.put(info, changedClientList);
Log.d(TAG, "SoftApCallbackProxy: client changed on " + info
+ " list: " + changedClientList);
}
}
}
if (!isInfoChanged && changedInfoClients.isEmpty()
&& !isRegistration) {
Log.v(TAG, "SoftApCallbackProxy: No changed & Not Registration,"
+ " don't need to notify the client");
return;
}
mCurrentClients = clients;
mCurrentInfos = infos;
Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mCallback.onInfoChanged(softApInfo);
});
}
@Override
public void onInfoListChanged(List<SoftApInfo> softApInfoList) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "SoftApCallbackProxy: onInfoListChange: softApInfoList="
+ softApInfoList);
// Notify the clients changed first for old info shutdown case
for (SoftApInfo changedInfo : changedInfoClients.keySet()) {
Log.v(TAG, "send onConnectedClientsChanged, changedInfo is " + changedInfo);
mExecutor.execute(() -> {
mCallback.onConnectedClientsChanged(
changedInfo, changedInfoClients.get(changedInfo));
});
}
Binder.clearCallingIdentity();
mExecutor.execute(() -> {
mCallback.onInfoListChanged(softApInfoList);
});
if (isInfoChanged || isRegistration) {
if (!isBridged) {
SoftApInfo newInfo = changedInfoList.isEmpty()
? new SoftApInfo() : changedInfoList.get(0);
Log.v(TAG, "SoftApCallbackProxy: send InfoChanged, newInfo: " + newInfo);
mExecutor.execute(() -> {
mCallback.onInfoChanged(newInfo);
});
}
Log.v(TAG, "SoftApCallbackProxy: send InfoChanged, changedInfoList: "
+ changedInfoList);
mExecutor.execute(() -> {
mCallback.onInfoChanged(changedInfoList);
});
}
if (isRegistration || !changedInfoClients.isEmpty()) {
Log.v(TAG, "SoftApCallbackProxy: send onConnectedClientsChanged(clients): "
+ getConnectedClientList(clients));
mExecutor.execute(() -> {
mCallback.onConnectedClientsChanged(getConnectedClientList(clients));
});
}
}
@Override
@@ -4184,8 +4261,20 @@ public class WifiManager {
* <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
* <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
* <li> {@link SoftApCallback#onInfoChanged(SoftApInfo)}</li>
* <li> {@link SoftApCallback#onInfoChanged(List<SoftApInfo>)}</li>
* <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
* </ul>
*
* Use {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)} to know if there are
* any clients connected to any of the bridged instances of this AP (if bridged AP is enabled).
* Use {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} to know
* if there are any clients connected to a specific bridged instance of this AP
* (if bridged AP is enabled).
*
* Note: Caller will receive the callback
* {@link SoftApCallback#onConnectedClientsChangedWithApInfo(SoftApInfo, List<WifiClient>)}
* on registration when there are clients connected to AP.
*
* These will be dispatched on registration to provide the caller with the current state
* (and are not an indication of any current change). Note that receiving an immediate
* WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start

View File

@@ -67,6 +67,7 @@ import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -110,6 +111,7 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@@ -135,10 +137,18 @@ public class WifiManagerTest {
private static final String TEST_FEATURE_ID = "TestFeature";
private static final String TEST_COUNTRY_CODE = "US";
private static final String[] TEST_MAC_ADDRESSES = {"da:a1:19:0:0:0"};
private static final int TEST_AP_FREQUENCY = 2412;
private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ;
private static final int TEST_SUB_ID = 3;
private static final String TEST_AP_INSTANCE = "wlan1";
private static final String[] TEST_AP_INSTANCES = new String[] {"wlan1", "wlan2"};
private static final int[] TEST_AP_FREQS = new int[] {2412, 5220};
private static final int[] TEST_AP_BWS = new int[] {SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT,
SoftApInfo.CHANNEL_WIDTH_80MHZ};
private static final MacAddress[] TEST_AP_BSSIDS = new MacAddress[] {
MacAddress.fromString("22:33:44:55:66:77"),
MacAddress.fromString("aa:bb:cc:dd:ee:ff")};
private static final MacAddress[] TEST_AP_CLIENTS = new MacAddress[] {
MacAddress.fromString("22:33:44:aa:aa:77"),
MacAddress.fromString("aa:bb:cc:11:11:ff"),
MacAddress.fromString("22:bb:cc:11:aa:ff")};
@Mock Context mContext;
@Mock android.net.wifi.IWifiManager mWifiService;
@@ -165,6 +175,11 @@ public class WifiManagerTest {
private CoexCallback mCoexCallback;
private WifiActivityEnergyInfo mWifiActivityEnergyInfo;
private HashMap<String, SoftApInfo> mTestSoftApInfoMap = new HashMap<>();
private HashMap<String, List<WifiClient>> mTestWifiClientsMap = new HashMap<>();
private SoftApInfo mTestApInfo1 = new SoftApInfo();
private SoftApInfo mTestApInfo2 = new SoftApInfo();
/**
* Util function to check public field which used for softap in WifiConfiguration
* same as the value in SoftApConfiguration.
@@ -209,6 +224,31 @@ public class WifiManagerTest {
.build();
}
private void initTestInfoAndAddToTestMap(int numberOfInfos) {
if (numberOfInfos > 2) return;
for (int i = 0; i < numberOfInfos; i++) {
SoftApInfo info = mTestApInfo1;
if (i == 1) info = mTestApInfo2;
info.setFrequency(TEST_AP_FREQS[i]);
info.setBandwidth(TEST_AP_BWS[i]);
info.setBssid(TEST_AP_BSSIDS[i]);
info.setApInstanceIdentifier(TEST_AP_INSTANCES[i]);
mTestSoftApInfoMap.put(TEST_AP_INSTANCES[i], info);
}
}
private List<WifiClient> initWifiClientAndAddToTestMap(String targetInstance,
int numberOfClients, int startIdx) {
if (numberOfClients > 3) return null;
List<WifiClient> clients = new ArrayList<>();
for (int i = startIdx; i < startIdx + numberOfClients; i++) {
WifiClient client = new WifiClient(TEST_AP_CLIENTS[i], targetInstance);
clients.add(client);
}
mTestWifiClientsMap.put(targetInstance, clients);
return clients;
}
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -233,6 +273,8 @@ public class WifiManagerTest {
}
};
mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
mTestSoftApInfoMap.clear();
mTestWifiClientsMap.clear();
}
/**
@@ -1087,11 +1129,149 @@ public class WifiManagerTest {
mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
anyInt());
final List<WifiClient> testClients = new ArrayList();
callbackCaptor.getValue().onConnectedClientsChanged(testClients);
List<WifiClient> clientList;
// Verify the register callback in disable state.
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, true);
mLooper.dispatchAll();
verify(mSoftApCallback).onConnectedClientsChanged(testClients);
verify(mSoftApCallback).onConnectedClientsChanged(new ArrayList<WifiClient>());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
verify(mSoftApCallback).onInfoChanged(new SoftApInfo());
verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Single AP mode Test
// Test info update
initTestInfoAndAddToTestMap(1);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
mLooper.dispatchAll();
verify(mSoftApCallback).onInfoChanged(mTestApInfo1);
verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
infos.contains(mTestApInfo1)));
verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test first client connected
clientList = initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[0], 1, 0);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
mLooper.dispatchAll();
// checked NO any infoChanged, includes InfoChanged(SoftApInfo)
// and InfoChanged(List<SoftApInfo>)
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback, never()).onInfoChanged(any(List.class));
verify(mSoftApCallback).onConnectedClientsChanged(mTestApInfo1, clientList);
verify(mSoftApCallback).onConnectedClientsChanged(clientList);
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test second client connected
mTestWifiClientsMap.clear();
clientList = initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[0], 2, 0);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
mLooper.dispatchAll();
// checked NO any infoChanged, includes InfoChanged(SoftApInfo)
// and InfoChanged(List<SoftApInfo>)
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback, never()).onInfoChanged(any(List.class));
verify(mSoftApCallback).onConnectedClientsChanged(mTestApInfo1, clientList);
verify(mSoftApCallback).onConnectedClientsChanged(clientList);
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test second client disconnect
mTestWifiClientsMap.clear();
clientList = initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[0], 1, 0);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
mLooper.dispatchAll();
// checked NO any infoChanged, includes InfoChanged(SoftApInfo)
// and InfoChanged(List<SoftApInfo>)
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback, never()).onInfoChanged(any(List.class));
verify(mSoftApCallback).onConnectedClientsChanged(mTestApInfo1, clientList);
verify(mSoftApCallback).onConnectedClientsChanged(clientList);
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test bridged mode case
mTestSoftApInfoMap.clear();
initTestInfoAndAddToTestMap(2);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
mLooper.dispatchAll();
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
infos.contains(mTestApInfo1) && infos.contains(mTestApInfo2)
));
verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test client connect to second instance
List<WifiClient> clientListOnSecond =
initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[1], 1, 2); // client3 to wlan2
List<WifiClient> totalList = new ArrayList<>();
totalList.addAll(clientList);
totalList.addAll(clientListOnSecond);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
mLooper.dispatchAll();
// checked NO any infoChanged, includes InfoChanged(SoftApInfo)
// and InfoChanged(List<SoftApInfo>)
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback, never()).onInfoChanged(any(List.class));
verify(mSoftApCallback).onConnectedClientsChanged(mTestApInfo2, clientListOnSecond);
verify(mSoftApCallback).onConnectedClientsChanged(totalList);
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test shutdown on second instance
mTestSoftApInfoMap.clear();
mTestWifiClientsMap.clear();
initTestInfoAndAddToTestMap(1);
clientList = initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[0], 1, 0);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
mLooper.dispatchAll();
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
infos.contains(mTestApInfo1)));
// second instance have client connected before, thus it should send empty list
verify(mSoftApCallback).onConnectedClientsChanged(
mTestApInfo2, new ArrayList<WifiClient>());
verify(mSoftApCallback).onConnectedClientsChanged(clientList);
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test bridged mode disable when client connected
mTestSoftApInfoMap.clear();
mTestWifiClientsMap.clear();
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
mLooper.dispatchAll();
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
verify(mSoftApCallback).onConnectedClientsChanged(new ArrayList<WifiClient>());
verify(mSoftApCallback).onConnectedClientsChanged(
mTestApInfo1, new ArrayList<WifiClient>());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
}
@@ -1100,41 +1280,139 @@ public class WifiManagerTest {
*/
@Test
public void softApCallbackProxyCallsOnSoftApInfoChanged() throws Exception {
SoftApInfo testSoftApInfo = new SoftApInfo();
testSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
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().onInfoChanged(testSoftApInfo);
// Verify the register callback in disable state.
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, true);
mLooper.dispatchAll();
verify(mSoftApCallback).onInfoChanged(testSoftApInfo);
verify(mSoftApCallback).onConnectedClientsChanged(new ArrayList<WifiClient>());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
verify(mSoftApCallback).onInfoChanged(new SoftApInfo());
verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Single AP mode Test
// Test info update
initTestInfoAndAddToTestMap(1);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
mLooper.dispatchAll();
verify(mSoftApCallback).onInfoChanged(mTestApInfo1);
verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
infos.contains(mTestApInfo1)));
verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test info changed
SoftApInfo changedInfo = new SoftApInfo(mTestSoftApInfoMap.get(TEST_AP_INSTANCES[0]));
changedInfo.setFrequency(2422);
mTestSoftApInfoMap.put(TEST_AP_INSTANCES[0], changedInfo);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
mLooper.dispatchAll();
verify(mSoftApCallback).onInfoChanged(changedInfo);
verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
infos.contains(changedInfo)));
verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
// Test Stop, all of infos is empty
mTestSoftApInfoMap.clear();
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
mLooper.dispatchAll();
verify(mSoftApCallback).onInfoChanged(new SoftApInfo());
verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
}
/*
* Verify client-provided callback is being called through callback proxy
*/
@Test
public void softApCallbackProxyCallsOnSoftApInfoListChanged() throws Exception {
SoftApInfo testSoftApInfo = new SoftApInfo();
testSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
List<SoftApInfo> infoList = new ArrayList<>();
infoList.add(testSoftApInfo);
public void softApCallbackProxyCallsOnSoftApInfoChangedInBridgedMode() throws Exception {
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().onInfoListChanged(infoList);
// Test bridged mode case
initTestInfoAndAddToTestMap(2);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
mLooper.dispatchAll();
verify(mSoftApCallback).onInfoListChanged(infoList);
}
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
infos.contains(mTestApInfo1) && infos.contains(mTestApInfo2)
));
verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test bridged mode case but an info changed
SoftApInfo changedInfoBridgedMode = new SoftApInfo(mTestSoftApInfoMap.get(
TEST_AP_INSTANCES[0]));
changedInfoBridgedMode.setFrequency(2422);
mTestSoftApInfoMap.put(TEST_AP_INSTANCES[0], changedInfoBridgedMode);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
mLooper.dispatchAll();
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
infos.contains(changedInfoBridgedMode) && infos.contains(mTestApInfo2)
));
verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test bridged mode case but an instance shutdown
mTestSoftApInfoMap.clear();
initTestInfoAndAddToTestMap(1);
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
mLooper.dispatchAll();
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
infos.contains(mTestApInfo1)
));
verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
// Test bridged mode disable case
mTestSoftApInfoMap.clear();
callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
(Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
(Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
mLooper.dispatchAll();
verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
// After verify, reset mSoftApCallback for nex test
reset(mSoftApCallback);
}
/*
* Verify client-provided callback is being called through callback proxy
@@ -1160,7 +1438,7 @@ public class WifiManagerTest {
@Test
public void softApCallbackProxyCallsOnBlockedClientConnecting() throws Exception {
WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77"),
TEST_AP_INSTANCE);
TEST_AP_INSTANCES[0]);
ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
@@ -1179,11 +1457,6 @@ public class WifiManagerTest {
*/
@Test
public void softApCallbackProxyCallsOnMultipleUpdates() throws Exception {
SoftApInfo testSoftApInfo = new SoftApInfo();
testSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
List<SoftApInfo> infoList = new ArrayList<>();
infoList.add(testSoftApInfo);
SoftApCapability testSoftApCapability = new SoftApCapability(0);
testSoftApCapability.setMaxSupportedClients(10);
ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
@@ -1194,18 +1467,12 @@ public class WifiManagerTest {
final List<WifiClient> testClients = new ArrayList();
callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLING, 0);
callbackCaptor.getValue().onConnectedClientsChanged(testClients);
callbackCaptor.getValue().onInfoChanged(testSoftApInfo);
callbackCaptor.getValue().onInfoListChanged(infoList);
callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
callbackCaptor.getValue().onCapabilityChanged(testSoftApCapability);
mLooper.dispatchAll();
verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLING, 0);
verify(mSoftApCallback).onConnectedClientsChanged(testClients);
verify(mSoftApCallback).onInfoChanged(testSoftApInfo);
verify(mSoftApCallback).onInfoListChanged(infoList);
verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
verify(mSoftApCallback).onCapabilityChanged(testSoftApCapability);
}