diff options
author | Les Lee <lesl@google.com> | 2020-12-23 13:53:17 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-12-23 13:53:17 +0000 |
commit | b241613297cb47a48eacbe9a140e9a27299781f7 (patch) | |
tree | 0ecd7fffaeb941a6923790f89f730c649b524cee /wifi | |
parent | cf749b91549aab68a28de6e1b467fb2f6536a34a (diff) | |
parent | e5436af58ca25daef3f22d707346fb368238e69c (diff) |
Merge changes from topic "bridged_AP_callback"
* changes:
wifi: Add callback onConnectedClientsOrInfoChanged handling
wifi: Add new callback to support use case in bridged mode
Diffstat (limited to 'wifi')
-rw-r--r-- | wifi/api/system-current.txt | 3 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/ISoftApCallback.aidl | 23 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiManager.java | 145 | ||||
-rw-r--r-- | wifi/tests/src/android/net/wifi/WifiManagerTest.java | 335 |
4 files changed, 427 insertions, 79 deletions
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt index 257f9d53e59f..23e396251f74 100644 --- a/wifi/api/system-current.txt +++ b/wifi/api/system-current.txt @@ -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); } diff --git a/wifi/java/android/net/wifi/ISoftApCallback.aidl b/wifi/java/android/net/wifi/ISoftApCallback.aidl index a28a8fb626b1..3db0a5dfe9c2 100644 --- a/wifi/java/android/net/wifi/ISoftApCallback.aidl +++ b/wifi/java/android/net/wifi/ISoftApCallback.aidl @@ -40,25 +40,16 @@ 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. diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 6496cc7a3ba3..5618ee8e4233 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -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); - }); - } + // 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)); + }); + } - @Override - public void onInfoListChanged(List<SoftApInfo> softApInfoList) { - if (mVerboseLoggingEnabled) { - Log.v(TAG, "SoftApCallbackProxy: onInfoListChange: softApInfoList=" - + 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); + }); } - Binder.clearCallingIdentity(); - mExecutor.execute(() -> { - mCallback.onInfoListChanged(softApInfoList); - }); + 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 diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index b15fa2c926f4..274cff2f41e8 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -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(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(); - verify(mSoftApCallback).onConnectedClientsChanged(testClients); + // 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,42 +1280,140 @@ 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).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(testSoftApInfo); + 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, 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).onInfoListChanged(infoList); + 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); } |