1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi;
18 
19 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY;
20 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY;
21 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SCAN_ONLY;
22 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED;
23 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT;
24 import static com.android.server.wifi.ActiveModeManager.ROLE_SOFTAP_LOCAL_ONLY;
25 import static com.android.server.wifi.ActiveModeManager.ROLE_SOFTAP_TETHERED;
26 import static com.android.server.wifi.ActiveModeWarden.INTERNAL_REQUESTOR_WS;
27 
28 import static com.google.common.truth.Truth.assertThat;
29 import static com.google.common.truth.Truth.assertWithMessage;
30 
31 import static org.junit.Assert.assertEquals;
32 import static org.junit.Assert.assertFalse;
33 import static org.junit.Assert.assertNull;
34 import static org.junit.Assert.assertTrue;
35 import static org.mockito.ArgumentMatchers.anyBoolean;
36 import static org.mockito.ArgumentMatchers.argThat;
37 import static org.mockito.Mockito.any;
38 import static org.mockito.Mockito.anyInt;
39 import static org.mockito.Mockito.anyString;
40 import static org.mockito.Mockito.atLeastOnce;
41 import static org.mockito.Mockito.clearInvocations;
42 import static org.mockito.Mockito.doAnswer;
43 import static org.mockito.Mockito.doThrow;
44 import static org.mockito.Mockito.eq;
45 import static org.mockito.Mockito.mock;
46 import static org.mockito.Mockito.mockingDetails;
47 import static org.mockito.Mockito.never;
48 import static org.mockito.Mockito.reset;
49 import static org.mockito.Mockito.times;
50 import static org.mockito.Mockito.verify;
51 import static org.mockito.Mockito.verifyNoMoreInteractions;
52 import static org.mockito.Mockito.verifyZeroInteractions;
53 import static org.mockito.Mockito.when;
54 
55 import android.annotation.Nullable;
56 import android.content.BroadcastReceiver;
57 import android.content.Context;
58 import android.content.Intent;
59 import android.content.res.Resources;
60 import android.location.LocationManager;
61 import android.net.wifi.ISubsystemRestartCallback;
62 import android.net.wifi.IWifiConnectedNetworkScorer;
63 import android.net.wifi.SoftApCapability;
64 import android.net.wifi.SoftApConfiguration;
65 import android.net.wifi.SoftApConfiguration.Builder;
66 import android.net.wifi.SoftApInfo;
67 import android.net.wifi.WifiClient;
68 import android.net.wifi.WifiConfiguration;
69 import android.net.wifi.WifiManager;
70 import android.os.BatteryStatsManager;
71 import android.os.Build;
72 import android.os.IBinder;
73 import android.os.Process;
74 import android.os.RemoteException;
75 import android.os.WorkSource;
76 import android.os.test.TestLooper;
77 import android.telephony.TelephonyManager;
78 import android.util.Log;
79 
80 import androidx.test.filters.SmallTest;
81 
82 import com.android.server.wifi.ActiveModeManager.ClientConnectivityRole;
83 import com.android.server.wifi.ActiveModeManager.Listener;
84 import com.android.server.wifi.ActiveModeManager.SoftApRole;
85 import com.android.server.wifi.ActiveModeWarden.ExternalClientModeManagerRequestListener;
86 import com.android.server.wifi.util.GeneralUtil.Mutable;
87 import com.android.server.wifi.util.WifiPermissionsUtil;
88 import com.android.wifi.resources.R;
89 
90 import org.junit.After;
91 import org.junit.Before;
92 import org.junit.Test;
93 import org.mockito.ArgumentCaptor;
94 import org.mockito.Mock;
95 import org.mockito.Mockito;
96 import org.mockito.MockitoAnnotations;
97 import org.mockito.invocation.InvocationOnMock;
98 import org.mockito.stubbing.Answer;
99 
100 import java.io.ByteArrayOutputStream;
101 import java.io.PrintWriter;
102 import java.util.Collection;
103 import java.util.HashMap;
104 import java.util.List;
105 import java.util.Map;
106 import java.util.stream.Collectors;
107 
108 /**
109  * Unit tests for {@link com.android.server.wifi.ActiveModeWarden}.
110  */
111 @SmallTest
112 public class ActiveModeWardenTest extends WifiBaseTest {
113     public static final String TAG = "WifiActiveModeWardenTest";
114 
115     private static final String ENABLED_STATE_STRING = "EnabledState";
116     private static final String DISABLED_STATE_STRING = "DisabledState";
117     private static final String TEST_SSID_1 = "\"Ssid12345\"";
118     private static final String TEST_SSID_2 = "\"Ssid45678\"";
119     private static final String TEST_SSID_3 = "\"Ssid98765\"";
120     private static final String TEST_BSSID_1 = "01:12:23:34:45:56";
121     private static final String TEST_BSSID_2 = "10:21:32:43:54:65";
122     private static final String TEST_BSSID_3 = "11:22:33:44:55:66";
123 
124     private static final String WIFI_IFACE_NAME = "mockWlan";
125     private static final String WIFI_IFACE_NAME_1 = "mockWlan1";
126     private static final int TEST_WIFI_RECOVERY_DELAY_MS = 2000;
127     private static final int TEST_AP_FREQUENCY = 2412;
128     private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ;
129     private static final int TEST_UID = 435546654;
130     private static final String TEST_PACKAGE = "com.test";
131     private static final WorkSource TEST_WORKSOURCE = new WorkSource(TEST_UID, TEST_PACKAGE);
132 
133     TestLooper mLooper;
134     @Mock WifiInjector mWifiInjector;
135     @Mock Context mContext;
136     @Mock Resources mResources;
137     @Mock WifiNative mWifiNative;
138     @Mock WifiApConfigStore mWifiApConfigStore;
139     @Mock ConcreteClientModeManager mClientModeManager;
140     @Mock SoftApManager mSoftApManager;
141     @Mock DefaultClientModeManager mDefaultClientModeManager;
142     @Mock BatteryStatsManager mBatteryStats;
143     @Mock SelfRecovery mSelfRecovery;
144     @Mock WifiDiagnostics mWifiDiagnostics;
145     @Mock ScanRequestProxy mScanRequestProxy;
146     @Mock FrameworkFacade mFacade;
147     @Mock WifiSettingsStore mSettingsStore;
148     @Mock WifiPermissionsUtil mWifiPermissionsUtil;
149     @Mock SoftApCapability mSoftApCapability;
150     @Mock ActiveModeWarden.ModeChangeCallback mModeChangeCallback;
151     @Mock ActiveModeWarden.PrimaryClientModeManagerChangedCallback mPrimaryChangedCallback;
152     @Mock WifiMetrics mWifiMetrics;
153     @Mock ISubsystemRestartCallback mSubsystemRestartCallback;
154     @Mock ExternalScoreUpdateObserverProxy mExternalScoreUpdateObserverProxy;
155     @Mock DppManager mDppManager;
156     @Mock SarManager mSarManager;
157     @Mock HalDeviceManager mHalDeviceManager;
158 
159     Listener<ConcreteClientModeManager> mClientListener;
160     Listener<SoftApManager> mSoftApListener;
161     WifiServiceImpl.SoftApCallbackInternal mSoftApManagerCallback;
162     SoftApModeConfiguration mSoftApConfig;
163     @Mock WifiServiceImpl.SoftApCallbackInternal mSoftApStateMachineCallback;
164     @Mock WifiServiceImpl.SoftApCallbackInternal mLohsStateMachineCallback;
165     WifiNative.StatusListener mWifiNativeStatusListener;
166     ActiveModeWarden mActiveModeWarden;
167     private SoftApInfo mTestSoftApInfo;
168 
169     final ArgumentCaptor<WifiNative.StatusListener> mStatusListenerCaptor =
170             ArgumentCaptor.forClass(WifiNative.StatusListener.class);
171 
172     private BroadcastReceiver mEmergencyCallbackModeChangedBr;
173     private BroadcastReceiver mEmergencyCallStateChangedBr;
174 
175     /**
176      * Set up the test environment.
177      */
178     @Before
setUp()179     public void setUp() throws Exception {
180         Log.d(TAG, "Setting up ...");
181 
182         MockitoAnnotations.initMocks(this);
183         mLooper = new TestLooper();
184 
185         when(mWifiInjector.getScanRequestProxy()).thenReturn(mScanRequestProxy);
186         when(mWifiInjector.getSarManager()).thenReturn(mSarManager);
187         when(mWifiInjector.getHalDeviceManager()).thenReturn(mHalDeviceManager);
188         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
189         when(mClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
190         when(mContext.getResources()).thenReturn(mResources);
191         when(mSoftApManager.getRole()).thenReturn(ROLE_SOFTAP_TETHERED);
192 
193         when(mResources.getString(R.string.wifi_localhotspot_configure_ssid_default))
194                 .thenReturn("AndroidShare");
195         when(mResources.getInteger(R.integer.config_wifi_framework_recovery_timeout_delay))
196                 .thenReturn(TEST_WIFI_RECOVERY_DELAY_MS);
197         when(mResources.getBoolean(R.bool.config_wifiScanHiddenNetworksScanOnlyMode))
198                 .thenReturn(false);
199         when(mResources.getBoolean(R.bool.config_wifi_turn_off_during_emergency_call))
200                 .thenReturn(true);
201 
202         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
203         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
204         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
205         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
206         when(mFacade.getSettingsWorkSource(mContext)).thenReturn(TEST_WORKSOURCE);
207 
208         doAnswer(new Answer<ClientModeManager>() {
209             public ClientModeManager answer(InvocationOnMock invocation) {
210                 Object[] args = invocation.getArguments();
211                 mClientListener = (Listener<ConcreteClientModeManager>) args[0];
212                 return mClientModeManager;
213             }
214         }).when(mWifiInjector).makeClientModeManager(
215                 any(Listener.class), any(), any(), anyBoolean());
216         doAnswer(new Answer<SoftApManager>() {
217             public SoftApManager answer(InvocationOnMock invocation) {
218                 Object[] args = invocation.getArguments();
219                 mSoftApListener = (Listener<SoftApManager>) args[0];
220                 mSoftApManagerCallback = (WifiServiceImpl.SoftApCallbackInternal) args[1];
221                 mSoftApConfig = (SoftApModeConfiguration) args[2];
222                 return mSoftApManager;
223             }
224         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
225                 any(WifiServiceImpl.SoftApCallbackInternal.class), any(), any(), any(),
226                 anyBoolean());
227         when(mWifiNative.initialize()).thenReturn(true);
228         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(true);
229 
230         mActiveModeWarden = createActiveModeWarden();
231         mActiveModeWarden.start();
232         mLooper.dispatchAll();
233 
234         verify(mWifiMetrics).noteWifiEnabledDuringBoot(false);
235 
236         verify(mWifiNative).registerStatusListener(mStatusListenerCaptor.capture());
237         verify(mWifiNative).initialize();
238         mWifiNativeStatusListener = mStatusListenerCaptor.getValue();
239 
240         mActiveModeWarden.registerSoftApCallback(mSoftApStateMachineCallback);
241         mActiveModeWarden.registerLohsCallback(mLohsStateMachineCallback);
242         mActiveModeWarden.registerModeChangeCallback(mModeChangeCallback);
243         mActiveModeWarden.registerPrimaryClientModeManagerChangedCallback(mPrimaryChangedCallback);
244         when(mSubsystemRestartCallback.asBinder()).thenReturn(Mockito.mock(IBinder.class));
245         mActiveModeWarden.registerSubsystemRestartCallback(mSubsystemRestartCallback);
246         mTestSoftApInfo = new SoftApInfo();
247         mTestSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
248         mTestSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
249 
250         ArgumentCaptor<BroadcastReceiver> bcastRxCaptor =
251                 ArgumentCaptor.forClass(BroadcastReceiver.class);
252         verify(mContext).registerReceiver(
253                 bcastRxCaptor.capture(),
254                 argThat(filter ->
255                         filter.hasAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)));
256         mEmergencyCallbackModeChangedBr = bcastRxCaptor.getValue();
257 
258         verify(mContext).registerReceiver(
259                 bcastRxCaptor.capture(),
260                 argThat(filter ->
261                         filter.hasAction(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED)));
262         mEmergencyCallStateChangedBr = bcastRxCaptor.getValue();
263     }
264 
createActiveModeWarden()265     private ActiveModeWarden createActiveModeWarden() {
266         ActiveModeWarden warden = new ActiveModeWarden(
267                 mWifiInjector,
268                 mLooper.getLooper(),
269                 mWifiNative,
270                 mDefaultClientModeManager,
271                 mBatteryStats,
272                 mWifiDiagnostics,
273                 mContext,
274                 mSettingsStore,
275                 mFacade,
276                 mWifiPermissionsUtil,
277                 mWifiMetrics,
278                 mExternalScoreUpdateObserverProxy,
279                 mDppManager);
280         // SelfRecovery is created in WifiInjector after ActiveModeWarden, so getSelfRecovery()
281         // returns null when constructing ActiveModeWarden.
282         when(mWifiInjector.getSelfRecovery()).thenReturn(mSelfRecovery);
283         return warden;
284     }
285 
286     /**
287      * Clean up after tests - explicitly set tested object to null.
288      */
289     @After
cleanUp()290     public void cleanUp() throws Exception {
291         mActiveModeWarden = null;
292         mLooper.dispatchAll();
293     }
294 
emergencyCallbackModeChanged(boolean enabled)295     private void emergencyCallbackModeChanged(boolean enabled) {
296         Intent intent = new Intent(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
297         intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, enabled);
298         mEmergencyCallbackModeChangedBr.onReceive(mContext, intent);
299     }
300 
emergencyCallStateChanged(boolean enabled)301     private void emergencyCallStateChanged(boolean enabled) {
302         Intent intent = new Intent(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED);
303         intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, enabled);
304         mEmergencyCallStateChangedBr.onReceive(mContext, intent);
305     }
306 
enterClientModeActiveState()307     private void enterClientModeActiveState() throws Exception {
308         enterClientModeActiveState(false);
309     }
310 
311     /**
312      * Helper method to enter the EnabledState and set ClientModeManager in ConnectMode.
313      * @param isClientModeSwitch true if switching from another mode, false if creating a new one
314      */
enterClientModeActiveState(boolean isClientModeSwitch)315     private void enterClientModeActiveState(boolean isClientModeSwitch) throws Exception {
316         String fromState = mActiveModeWarden.getCurrentMode();
317         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
318         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
319         mLooper.dispatchAll();
320         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
321         // ClientModeManager starts in SCAN_ONLY role.
322         mClientListener.onRoleChanged(mClientModeManager);
323         mLooper.dispatchAll();
324 
325         assertInEnabledState();
326         if (!isClientModeSwitch) {
327             verify(mWifiInjector).makeClientModeManager(
328                     any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
329         } else {
330             verify(mClientModeManager).setRole(ROLE_CLIENT_PRIMARY, TEST_WORKSOURCE);
331         }
332         verify(mScanRequestProxy).enableScanning(true, true);
333         if (fromState.equals(DISABLED_STATE_STRING)) {
334             verify(mBatteryStats).reportWifiOn();
335         }
336         assertEquals(mClientModeManager, mActiveModeWarden.getPrimaryClientModeManager());
337         verify(mModeChangeCallback).onActiveModeManagerRoleChanged(mClientModeManager);
338     }
339 
enterScanOnlyModeActiveState()340     private void enterScanOnlyModeActiveState() throws Exception {
341         enterScanOnlyModeActiveState(false);
342     }
343 
344     /**
345      * Helper method to enter the EnabledState and set ClientModeManager in ScanOnlyMode.
346      */
enterScanOnlyModeActiveState(boolean isClientModeSwitch)347     private void enterScanOnlyModeActiveState(boolean isClientModeSwitch) throws Exception {
348         String fromState = mActiveModeWarden.getCurrentMode();
349         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
350         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
351         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
352         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
353         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
354         mLooper.dispatchAll();
355         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SCAN_ONLY);
356 
357         if (!isClientModeSwitch) {
358             mClientListener.onStarted(mClientModeManager);
359             mLooper.dispatchAll();
360             verify(mWifiInjector).makeClientModeManager(
361                     any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_SCAN_ONLY), anyBoolean());
362             verify(mModeChangeCallback).onActiveModeManagerAdded(mClientModeManager);
363         } else {
364             mClientListener.onRoleChanged(mClientModeManager);
365             mLooper.dispatchAll();
366             verify(mClientModeManager).setRole(ROLE_CLIENT_SCAN_ONLY, INTERNAL_REQUESTOR_WS);
367             // If switching from client mode back to scan only mode, role change would have been
368             // called once before when transitioning from scan only mode to client mode.
369             // Verify that it was called again.
370             verify(mModeChangeCallback, times(2))
371                     .onActiveModeManagerRoleChanged(mClientModeManager);
372         }
373         assertInEnabledState();
374         verify(mScanRequestProxy).enableScanning(true, false);
375         if (fromState.equals(DISABLED_STATE_STRING)) {
376             verify(mBatteryStats).reportWifiOn();
377         }
378         verify(mBatteryStats).reportWifiState(BatteryStatsManager.WIFI_STATE_OFF_SCANNING, null);
379         assertEquals(mClientModeManager, mActiveModeWarden.getScanOnlyClientModeManager());
380     }
381 
enterSoftApActiveMode()382     private void enterSoftApActiveMode() throws Exception {
383         enterSoftApActiveMode(
384                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
385                 mSoftApCapability));
386     }
387 
388     private int mTimesCreatedSoftApManager = 1;
389 
390     /**
391      * Helper method to activate SoftApManager.
392      *
393      * This method puts the test object into the correct state and verifies steps along the way.
394      */
enterSoftApActiveMode(SoftApModeConfiguration softApConfig)395     private void enterSoftApActiveMode(SoftApModeConfiguration softApConfig) throws Exception {
396         String fromState = mActiveModeWarden.getCurrentMode();
397         SoftApRole softApRole = softApConfig.getTargetMode() == WifiManager.IFACE_IP_MODE_TETHERED
398                 ? ROLE_SOFTAP_TETHERED : ROLE_SOFTAP_LOCAL_ONLY;
399         mActiveModeWarden.startSoftAp(softApConfig, TEST_WORKSOURCE);
400         mLooper.dispatchAll();
401         when(mSoftApManager.getRole()).thenReturn(softApRole);
402         when(mSoftApManager.getSoftApModeConfiguration()).thenReturn(softApConfig);
403         mSoftApListener.onStarted(mSoftApManager);
404         mLooper.dispatchAll();
405 
406         assertInEnabledState();
407         assertThat(softApConfig).isEqualTo(mSoftApConfig);
408         verify(mWifiInjector, times(mTimesCreatedSoftApManager)).makeSoftApManager(
409                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(softApRole), anyBoolean());
410         mTimesCreatedSoftApManager++;
411         if (fromState.equals(DISABLED_STATE_STRING)) {
412             verify(mBatteryStats).reportWifiOn();
413         }
414         if (softApRole == ROLE_SOFTAP_TETHERED) {
415             assertEquals(mSoftApManager, mActiveModeWarden.getTetheredSoftApManager());
416             assertNull(mActiveModeWarden.getLocalOnlySoftApManager());
417         } else {
418             assertEquals(mSoftApManager, mActiveModeWarden.getLocalOnlySoftApManager());
419             assertNull(mActiveModeWarden.getTetheredSoftApManager());
420         }
421         verify(mModeChangeCallback).onActiveModeManagerAdded(mSoftApManager);
422     }
423 
enterStaDisabledMode(boolean isSoftApModeManagerActive)424     private void enterStaDisabledMode(boolean isSoftApModeManagerActive) {
425         String fromState = mActiveModeWarden.getCurrentMode();
426         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
427         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
428         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
429         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
430         mLooper.dispatchAll();
431         if (mClientListener != null) {
432             mClientListener.onStopped(mClientModeManager);
433             mLooper.dispatchAll();
434             verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
435         }
436 
437         if (isSoftApModeManagerActive) {
438             assertInEnabledState();
439         } else {
440             assertInDisabledState();
441         }
442         if (fromState.equals(ENABLED_STATE_STRING)) {
443             verify(mScanRequestProxy).enableScanning(false, false);
444         }
445         // Ensure we return the default client mode manager when wifi is off.
446         assertEquals(mDefaultClientModeManager, mActiveModeWarden.getPrimaryClientModeManager());
447     }
448 
shutdownWifi()449     private void shutdownWifi() {
450         mActiveModeWarden.recoveryDisableWifi();
451         mLooper.dispatchAll();
452     }
453 
assertInEnabledState()454     private void assertInEnabledState() {
455         assertThat(mActiveModeWarden.getCurrentMode()).isEqualTo(ENABLED_STATE_STRING);
456     }
457 
assertInDisabledState()458     private void assertInDisabledState() {
459         assertThat(mActiveModeWarden.getCurrentMode()).isEqualTo(DISABLED_STATE_STRING);
460     }
461 
462     /**
463      * Emergency mode is a sub-mode within each main state (ScanOnly, Client, DisabledState).
464      */
assertInEmergencyMode()465     private void assertInEmergencyMode() {
466         assertThat(mActiveModeWarden.isInEmergencyMode()).isTrue();
467     }
468 
assertNotInEmergencyMode()469     private void assertNotInEmergencyMode() {
470         assertThat(mActiveModeWarden.isInEmergencyMode()).isFalse();
471     }
472 
473     /**
474      * Counts the number of times a void method was called on a mock.
475      *
476      * Void methods cannot be passed to Mockito.mockingDetails(). Thus we have to use method name
477      * matching instead.
478      */
getMethodInvocationCount(Object mock, String methodName)479     private static int getMethodInvocationCount(Object mock, String methodName) {
480         long count = mockingDetails(mock).getInvocations()
481                 .stream()
482                 .filter(invocation -> methodName.equals(invocation.getMethod().getName()))
483                 .count();
484         return (int) count;
485     }
486 
487     /**
488      * Counts the number of times a non-void method was called on a mock.
489      *
490      * For non-void methods, can pass the method call literal directly:
491      * e.g. getMethodInvocationCount(mock.method());
492      */
getMethodInvocationCount(Object mockMethod)493     private static int getMethodInvocationCount(Object mockMethod) {
494         return mockingDetails(mockMethod).getInvocations().size();
495     }
496 
assertWifiShutDown(Runnable r)497     private void assertWifiShutDown(Runnable r) {
498         assertWifiShutDown(r, 1);
499     }
500 
501     /**
502      * Asserts that the runnable r has shut down wifi properly.
503      *
504      * @param r     runnable that will shut down wifi
505      * @param times expected number of times that <code>r</code> shut down wifi
506      */
assertWifiShutDown(Runnable r, int times)507     private void assertWifiShutDown(Runnable r, int times) {
508         // take snapshot of ActiveModeManagers
509         Collection<ActiveModeManager> activeModeManagers =
510                 mActiveModeWarden.getActiveModeManagers();
511 
512         List<Integer> expectedStopInvocationCounts = activeModeManagers
513                 .stream()
514                 .map(manager -> getMethodInvocationCount(manager, "stop") + times)
515                 .collect(Collectors.toList());
516 
517         r.run();
518 
519         List<Integer> actualStopInvocationCounts = activeModeManagers
520                 .stream()
521                 .map(manager -> getMethodInvocationCount(manager, "stop"))
522                 .collect(Collectors.toList());
523 
524         String managerNames = activeModeManagers.stream()
525                 .map(manager -> manager.getClass().getCanonicalName())
526                 .collect(Collectors.joining(", ", "[", "]"));
527 
528         assertWithMessage(managerNames).that(actualStopInvocationCounts)
529                 .isEqualTo(expectedStopInvocationCounts);
530     }
531 
assertEnteredEcmMode(Runnable r)532     private void assertEnteredEcmMode(Runnable r) {
533         assertEnteredEcmMode(r, 1);
534     }
535 
536     /**
537      * Asserts that the runnable r has entered ECM state properly.
538      *
539      * @param r     runnable that will enter ECM
540      * @param times expected number of times that <code>r</code> shut down wifi
541      */
assertEnteredEcmMode(Runnable r, int times)542     private void assertEnteredEcmMode(Runnable r, int times) {
543         // take snapshot of ActiveModeManagers
544         Collection<ActiveModeManager> activeModeManagers =
545                 mActiveModeWarden.getActiveModeManagers();
546 
547         boolean disableWifiInEcm = mFacade.getConfigWiFiDisableInECBM(mContext);
548 
549         List<Integer> expectedStopInvocationCounts = activeModeManagers.stream()
550                 .map(manager -> {
551                     int initialCount = getMethodInvocationCount(manager, "stop");
552                     // carrier config enabled, all mode managers should have been shut down once
553                     int count = disableWifiInEcm ? initialCount + times : initialCount;
554                     if (manager instanceof SoftApManager) {
555                         // expect SoftApManager.close() to be called
556                         return count + times;
557                     } else {
558                         // don't expect other Managers close() to be called
559                         return count;
560                     }
561                 })
562                 .collect(Collectors.toList());
563 
564         r.run();
565 
566         assertInEmergencyMode();
567 
568         List<Integer> actualStopInvocationCounts = activeModeManagers.stream()
569                 .map(manager -> getMethodInvocationCount(manager, "stop"))
570                 .collect(Collectors.toList());
571 
572         String managerNames = activeModeManagers.stream()
573                 .map(manager -> manager.getClass().getCanonicalName())
574                 .collect(Collectors.joining(", ", "[", "]"));
575 
576         assertWithMessage(managerNames).that(actualStopInvocationCounts)
577                 .isEqualTo(expectedStopInvocationCounts);
578     }
579 
580     /** Test that after starting up, ActiveModeWarden is in the DisabledState State. */
581     @Test
testDisabledStateAtStartup()582     public void testDisabledStateAtStartup() {
583         assertInDisabledState();
584     }
585 
586     /**
587      * Test that ActiveModeWarden properly enters the EnabledState (in ScanOnlyMode) from the
588      * DisabledState state.
589      */
590     @Test
testEnterScanOnlyModeFromDisabled()591     public void testEnterScanOnlyModeFromDisabled() throws Exception {
592         enterScanOnlyModeActiveState();
593     }
594 
595     /**
596      * Test that ActiveModeWarden enables hidden network scanning in scan-only-mode
597      * if configured to do.
598      */
599     @Test
testScanOnlyModeScanHiddenNetworks()600     public void testScanOnlyModeScanHiddenNetworks() throws Exception {
601         when(mResources.getBoolean(R.bool.config_wifiScanHiddenNetworksScanOnlyMode))
602                 .thenReturn(true);
603 
604         mActiveModeWarden = createActiveModeWarden();
605         mActiveModeWarden.start();
606         mLooper.dispatchAll();
607 
608         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SCAN_ONLY);
609         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
610         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
611         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
612         mLooper.dispatchAll();
613         mClientListener.onStarted(mClientModeManager);
614         mLooper.dispatchAll();
615 
616         assertInEnabledState();
617         verify(mWifiInjector).makeClientModeManager(
618                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_SCAN_ONLY), anyBoolean());
619         verify(mScanRequestProxy).enableScanning(true, true);
620     }
621 
622     /**
623      * Test that ActiveModeWarden properly starts the SoftApManager from the
624      * DisabledState state.
625      */
626     @Test
testEnterSoftApModeFromDisabled()627     public void testEnterSoftApModeFromDisabled() throws Exception {
628         enterSoftApActiveMode();
629     }
630 
631     /**
632      * Test that ActiveModeWarden properly starts the SoftApManager from another state.
633      */
634     @Test
testEnterSoftApModeFromDifferentState()635     public void testEnterSoftApModeFromDifferentState() throws Exception {
636         enterClientModeActiveState();
637         assertInEnabledState();
638         reset(mBatteryStats, mScanRequestProxy);
639         enterSoftApActiveMode();
640     }
641 
642     /**
643      * Test that we can disable wifi fully from the EnabledState (in ScanOnlyMode).
644      */
645     @Test
testDisableWifiFromScanOnlyModeActiveState()646     public void testDisableWifiFromScanOnlyModeActiveState() throws Exception {
647         enterScanOnlyModeActiveState();
648 
649         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
650         mActiveModeWarden.scanAlwaysModeChanged();
651         mLooper.dispatchAll();
652         mClientListener.onStopped(mClientModeManager);
653         mLooper.dispatchAll();
654 
655         verify(mClientModeManager).stop();
656         verify(mBatteryStats).reportWifiOff();
657         assertInDisabledState();
658     }
659 
660     /**
661      * Test that we can disable wifi when SoftApManager is active and not impact softap.
662      */
663     @Test
testDisableWifiFromSoftApModeActiveStateDoesNotStopSoftAp()664     public void testDisableWifiFromSoftApModeActiveStateDoesNotStopSoftAp() throws Exception {
665         enterSoftApActiveMode();
666         enterScanOnlyModeActiveState();
667 
668         reset(mDefaultClientModeManager);
669         enterStaDisabledMode(true);
670         verify(mSoftApManager, never()).stop();
671         verify(mBatteryStats, never()).reportWifiOff();
672     }
673 
674     /**
675      * Test that we can switch from the EnabledState (in ScanOnlyMode) to another mode.
676      */
677     @Test
testSwitchModeWhenScanOnlyModeActiveState()678     public void testSwitchModeWhenScanOnlyModeActiveState() throws Exception {
679         enterScanOnlyModeActiveState();
680 
681         reset(mBatteryStats, mScanRequestProxy);
682         enterClientModeActiveState(true);
683         mLooper.dispatchAll();
684     }
685 
686     /**
687      * Test that we can switch from the EnabledState (in ConnectMode) to another mode.
688      */
689     @Test
testSwitchModeWhenConnectModeActiveState()690     public void testSwitchModeWhenConnectModeActiveState() throws Exception {
691         enterClientModeActiveState();
692 
693         verify(mPrimaryChangedCallback).onChange(null, mClientModeManager);
694 
695         reset(mBatteryStats, mScanRequestProxy);
696         enterScanOnlyModeActiveState(true);
697         mLooper.dispatchAll();
698 
699         verify(mPrimaryChangedCallback).onChange(mClientModeManager, null);
700     }
701 
702     /**
703      * Reentering EnabledState should be a NOP.
704      */
705     @Test
testReenterClientModeActiveStateIsNop()706     public void testReenterClientModeActiveStateIsNop() throws Exception {
707         enterClientModeActiveState();
708         verify(mWifiInjector, times(1)).makeClientModeManager(
709                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
710 
711         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
712         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
713         mLooper.dispatchAll();
714         // Should not start again.
715         verify(mWifiInjector, times(1)).makeClientModeManager(
716                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
717     }
718 
719     /**
720      * Test that we can switch mode when SoftApManager is active to another mode.
721      */
722     @Test
testSwitchModeWhenSoftApActiveMode()723     public void testSwitchModeWhenSoftApActiveMode() throws Exception {
724         enterSoftApActiveMode();
725 
726         reset(mWifiNative);
727 
728         enterClientModeActiveState();
729         mLooper.dispatchAll();
730         verify(mSoftApManager, never()).stop();
731         assertInEnabledState();
732         verify(mWifiNative, never()).teardownAllInterfaces();
733     }
734 
735     /**
736      * Test that we activate SoftApModeManager if we are already in DisabledState due to
737      * a failure.
738      */
739     @Test
testEnterSoftApModeActiveWhenAlreadyInSoftApMode()740     public void testEnterSoftApModeActiveWhenAlreadyInSoftApMode() throws Exception {
741         enterSoftApActiveMode();
742         // now inject failure through the SoftApManager.Listener
743         mSoftApListener.onStartFailure(mSoftApManager);
744         mLooper.dispatchAll();
745         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
746         assertInDisabledState();
747         // clear the first call to start SoftApManager
748         reset(mSoftApManager, mBatteryStats, mModeChangeCallback);
749 
750         enterSoftApActiveMode();
751     }
752 
753     /**
754      * Test that we return to the DisabledState after a failure is reported when in the
755      * EnabledState.
756      */
757     @Test
testScanOnlyModeFailureWhenActive()758     public void testScanOnlyModeFailureWhenActive() throws Exception {
759         enterScanOnlyModeActiveState();
760         // now inject a failure through the ScanOnlyModeManager.Listener
761         mClientListener.onStartFailure(mClientModeManager);
762         mLooper.dispatchAll();
763         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
764         assertInDisabledState();
765         verify(mBatteryStats).reportWifiOff();
766     }
767 
768     /**
769      * Test that we return to the DisabledState after a failure is reported when
770      * SoftApManager is active.
771      */
772     @Test
testSoftApFailureWhenActive()773     public void testSoftApFailureWhenActive() throws Exception {
774         enterSoftApActiveMode();
775         // now inject failure through the SoftApManager.Listener
776         mSoftApListener.onStartFailure(mSoftApManager);
777         mLooper.dispatchAll();
778         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
779         verify(mBatteryStats).reportWifiOff();
780     }
781 
782     /**
783      * Test that we return to the DisabledState after the ClientModeManager running in ScanOnlyMode
784      * is stopped.
785      */
786     @Test
testScanOnlyModeDisabledWhenActive()787     public void testScanOnlyModeDisabledWhenActive() throws Exception {
788         enterScanOnlyModeActiveState();
789 
790         // now inject the stop message through the ScanOnlyModeManager.Listener
791         mClientListener.onStopped(mClientModeManager);
792         mLooper.dispatchAll();
793 
794         assertInDisabledState();
795         verify(mBatteryStats).reportWifiOff();
796     }
797 
798     /**
799      * Test that we return to the DisabledState after the SoftApManager is stopped.
800      */
801     @Test
testSoftApDisabledWhenActive()802     public void testSoftApDisabledWhenActive() throws Exception {
803         enterSoftApActiveMode();
804         reset(mWifiNative);
805         // now inject failure through the SoftApManager.Listener
806         mSoftApListener.onStartFailure(mSoftApManager);
807         mLooper.dispatchAll();
808         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
809         verify(mBatteryStats).reportWifiOff();
810         verifyNoMoreInteractions(mWifiNative);
811     }
812 
813     /**
814      * Verifies that SoftApStateChanged event is being passed from SoftApManager to WifiServiceImpl
815      */
816     @Test
callsWifiServiceCallbackOnSoftApStateChanged()817     public void callsWifiServiceCallbackOnSoftApStateChanged() throws Exception {
818         enterSoftApActiveMode();
819 
820         mSoftApListener.onStarted(mSoftApManager);
821         mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0);
822         mLooper.dispatchAll();
823 
824         verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0);
825     }
826 
827     /**
828      * Verifies that SoftApStateChanged event isn't passed to WifiServiceImpl for LOHS,
829      * so the state change for LOHS doesn't affect Wifi Tethering indication.
830      */
831     @Test
doesntCallWifiServiceCallbackOnLOHSStateChanged()832     public void doesntCallWifiServiceCallbackOnLOHSStateChanged() throws Exception {
833         enterSoftApActiveMode(new SoftApModeConfiguration(
834                 WifiManager.IFACE_IP_MODE_LOCAL_ONLY, null, mSoftApCapability));
835 
836         mSoftApListener.onStarted(mSoftApManager);
837         mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0);
838         mLooper.dispatchAll();
839 
840         verify(mSoftApStateMachineCallback, never()).onStateChanged(anyInt(), anyInt());
841         verify(mSoftApStateMachineCallback, never()).onConnectedClientsOrInfoChanged(any(),
842                 any(), anyBoolean());
843     }
844 
845     /**
846      * Verifies that ConnectedClientsOrInfoChanged event is being passed from SoftApManager
847      * to WifiServiceImpl
848      */
849     @Test
callsWifiServiceCallbackOnSoftApConnectedClientsChanged()850     public void callsWifiServiceCallbackOnSoftApConnectedClientsChanged() throws Exception {
851         final Map<String, List<WifiClient>> testClients = new HashMap();
852         final Map<String, SoftApInfo> testInfos = new HashMap();
853         enterSoftApActiveMode();
854         mSoftApManagerCallback.onConnectedClientsOrInfoChanged(testInfos, testClients, false);
855         mLooper.dispatchAll();
856 
857         verify(mSoftApStateMachineCallback).onConnectedClientsOrInfoChanged(
858                 testInfos, testClients, false);
859     }
860 
861     /**
862      * Test that we remain in the active state when we get a state change update that scan mode is
863      * active.
864      */
865     @Test
testScanOnlyModeStaysActiveOnEnabledUpdate()866     public void testScanOnlyModeStaysActiveOnEnabledUpdate() throws Exception {
867         enterScanOnlyModeActiveState();
868         // now inject success through the Listener
869         mClientListener.onStarted(mClientModeManager);
870         mLooper.dispatchAll();
871         assertInEnabledState();
872         verify(mClientModeManager, never()).stop();
873     }
874 
875     /**
876      * Test that a config passed in to the call to enterSoftApMode is used to create the new
877      * SoftApManager.
878      */
879     @Test
testConfigIsPassedToWifiInjector()880     public void testConfigIsPassedToWifiInjector() throws Exception {
881         Builder configBuilder = new SoftApConfiguration.Builder();
882         configBuilder.setSsid("ThisIsAConfig");
883         SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(
884                 WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), mSoftApCapability);
885         enterSoftApActiveMode(softApConfig);
886     }
887 
888     /**
889      * Test that when enterSoftAPMode is called with a null config, we pass a null config to
890      * WifiInjector.makeSoftApManager.
891      *
892      * Passing a null config to SoftApManager indicates that the default config should be used.
893      */
894     @Test
testNullConfigIsPassedToWifiInjector()895     public void testNullConfigIsPassedToWifiInjector() throws Exception {
896         enterSoftApActiveMode();
897     }
898 
899     /**
900      * Test that two calls to switch to SoftAPMode in succession ends up with the correct config.
901      *
902      * Expectation: we should end up in SoftAPMode state configured with the second config.
903      */
904     @Test
testStartSoftApModeTwiceWithTwoConfigs()905     public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception {
906         when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
907         Builder configBuilder1 = new SoftApConfiguration.Builder();
908         configBuilder1.setSsid("ThisIsAConfig");
909         SoftApModeConfiguration softApConfig1 = new SoftApModeConfiguration(
910                 WifiManager.IFACE_IP_MODE_TETHERED, configBuilder1.build(),
911                 mSoftApCapability);
912         Builder configBuilder2 = new SoftApConfiguration.Builder();
913         configBuilder2.setSsid("ThisIsASecondConfig");
914         SoftApModeConfiguration softApConfig2 = new SoftApModeConfiguration(
915                 WifiManager.IFACE_IP_MODE_TETHERED, configBuilder2.build(),
916                 mSoftApCapability);
917 
918         doAnswer(new Answer<SoftApManager>() {
919             public SoftApManager answer(InvocationOnMock invocation) {
920                 Object[] args = invocation.getArguments();
921                 mSoftApListener = (Listener<SoftApManager>) args[0];
922                 return mSoftApManager;
923             }
924         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
925                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(softApConfig1), any(), any(),
926                 anyBoolean());
927         // make a second softap manager
928         SoftApManager softapManager = mock(SoftApManager.class);
929         Mutable<Listener<SoftApManager>> softApListener =
930                 new Mutable<>();
931         doAnswer(new Answer<SoftApManager>() {
932             public SoftApManager answer(InvocationOnMock invocation) {
933                 Object[] args = invocation.getArguments();
934                 softApListener.value = (Listener<SoftApManager>) args[0];
935                 return softapManager;
936             }
937         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
938                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(softApConfig2), any(), any(),
939                 anyBoolean());
940 
941         mActiveModeWarden.startSoftAp(softApConfig1, TEST_WORKSOURCE);
942         mLooper.dispatchAll();
943         mSoftApListener.onStarted(mSoftApManager);
944         mActiveModeWarden.startSoftAp(softApConfig2, TEST_WORKSOURCE);
945         mLooper.dispatchAll();
946         softApListener.value.onStarted(softapManager);
947 
948         verify(mWifiInjector, times(2)).makeSoftApManager(
949                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
950         verify(mBatteryStats).reportWifiOn();
951     }
952 
953     /**
954      * Test that we safely disable wifi if it is already disabled.
955      */
956     @Test
disableWifiWhenAlreadyOff()957     public void disableWifiWhenAlreadyOff() throws Exception {
958         enterStaDisabledMode(false);
959         verifyZeroInteractions(mWifiNative);
960     }
961 
962     /**
963      * Trigger recovery and a bug report if we see a native failure
964      * while the device is not shutting down
965      */
966     @Test
handleWifiNativeFailureDeviceNotShuttingDown()967     public void handleWifiNativeFailureDeviceNotShuttingDown() throws Exception {
968         mWifiNativeStatusListener.onStatusChanged(false);
969         mLooper.dispatchAll();
970         verify(mWifiDiagnostics).triggerBugReportDataCapture(
971                 WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE);
972         verify(mSelfRecovery).trigger(eq(SelfRecovery.REASON_WIFINATIVE_FAILURE));
973     }
974 
975     /**
976      * Verify the device shutting down doesn't trigger recovery or bug report.
977      */
978     @Test
handleWifiNativeFailureDeviceShuttingDown()979     public void handleWifiNativeFailureDeviceShuttingDown() throws Exception {
980         mActiveModeWarden.notifyShuttingDown();
981         mWifiNativeStatusListener.onStatusChanged(false);
982         mLooper.dispatchAll();
983         verify(mWifiDiagnostics, never()).triggerBugReportDataCapture(
984                 WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE);
985         verify(mSelfRecovery, never()).trigger(eq(SelfRecovery.REASON_WIFINATIVE_FAILURE));
986     }
987 
988     /**
989      * Verify an onStatusChanged callback with "true" does not trigger recovery.
990      */
991     @Test
handleWifiNativeStatusReady()992     public void handleWifiNativeStatusReady() throws Exception {
993         mWifiNativeStatusListener.onStatusChanged(true);
994         mLooper.dispatchAll();
995         verify(mWifiDiagnostics, never()).triggerBugReportDataCapture(
996                 WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE);
997         verify(mSelfRecovery, never()).trigger(eq(SelfRecovery.REASON_WIFINATIVE_FAILURE));
998     }
999 
1000     /**
1001      * Verify that mode stop is safe even if the underlying Client mode exited already.
1002      */
1003     @Test
shutdownWifiDoesNotCrashWhenClientModeExitsOnDestroyed()1004     public void shutdownWifiDoesNotCrashWhenClientModeExitsOnDestroyed() throws Exception {
1005         enterClientModeActiveState();
1006 
1007         mClientListener.onStopped(mClientModeManager);
1008         mLooper.dispatchAll();
1009 
1010         shutdownWifi();
1011 
1012         assertInDisabledState();
1013     }
1014 
1015     /**
1016      * Verify that an interface destruction callback is safe after already having been stopped.
1017      */
1018     @Test
onDestroyedCallbackDoesNotCrashWhenClientModeAlreadyStopped()1019     public void onDestroyedCallbackDoesNotCrashWhenClientModeAlreadyStopped() throws Exception {
1020         enterClientModeActiveState();
1021 
1022         shutdownWifi();
1023 
1024         mClientListener.onStopped(mClientModeManager);
1025         mLooper.dispatchAll();
1026 
1027         assertInDisabledState();
1028     }
1029 
1030     /**
1031      * Verify that mode stop is safe even if the underlying softap mode exited already.
1032      */
1033     @Test
shutdownWifiDoesNotCrashWhenSoftApExitsOnDestroyed()1034     public void shutdownWifiDoesNotCrashWhenSoftApExitsOnDestroyed() throws Exception {
1035         enterSoftApActiveMode();
1036 
1037         mSoftApListener.onStopped(mSoftApManager);
1038         mLooper.dispatchAll();
1039         mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
1040         mLooper.dispatchAll();
1041 
1042         shutdownWifi();
1043 
1044         verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
1045     }
1046 
1047     /**
1048      * Verify that an interface destruction callback is safe after already having been stopped.
1049      */
1050     @Test
onDestroyedCallbackDoesNotCrashWhenSoftApModeAlreadyStopped()1051     public void onDestroyedCallbackDoesNotCrashWhenSoftApModeAlreadyStopped() throws Exception {
1052         enterSoftApActiveMode();
1053 
1054         shutdownWifi();
1055 
1056         mSoftApListener.onStopped(mSoftApManager);
1057         mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
1058         mLooper.dispatchAll();
1059 
1060         verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
1061         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
1062     }
1063 
1064     /**
1065      * Verify that we do not crash when calling dump and wifi is fully disabled.
1066      */
1067     @Test
dumpWhenWifiFullyOffDoesNotCrash()1068     public void dumpWhenWifiFullyOffDoesNotCrash() throws Exception {
1069         ByteArrayOutputStream stream = new ByteArrayOutputStream();
1070         PrintWriter writer = new PrintWriter(stream);
1071         mActiveModeWarden.dump(null, writer, null);
1072     }
1073 
1074     /**
1075      * Verify that we trigger dump on active mode managers.
1076      */
1077     @Test
dumpCallsActiveModeManagers()1078     public void dumpCallsActiveModeManagers() throws Exception {
1079         enterSoftApActiveMode();
1080         enterClientModeActiveState();
1081 
1082         ByteArrayOutputStream stream = new ByteArrayOutputStream();
1083         PrintWriter writer = new PrintWriter(stream);
1084         mActiveModeWarden.dump(null, writer, null);
1085 
1086         verify(mSoftApManager).dump(null, writer, null);
1087         verify(mClientModeManager).dump(null, writer, null);
1088     }
1089 
1090     /**
1091      * Verify that stopping tethering doesn't stop LOHS.
1092      */
1093     @Test
testStopTetheringButNotLOHS()1094     public void testStopTetheringButNotLOHS() throws Exception {
1095         // prepare WiFi configurations
1096         when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
1097         SoftApModeConfiguration tetherConfig =
1098                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
1099                 mSoftApCapability);
1100         SoftApConfiguration lohsConfigWC = mWifiApConfigStore.generateLocalOnlyHotspotConfig(
1101                 mContext, SoftApConfiguration.BAND_2GHZ, null);
1102         SoftApModeConfiguration lohsConfig =
1103                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_LOCAL_ONLY, lohsConfigWC,
1104                 mSoftApCapability);
1105 
1106         // mock SoftAPManagers
1107         when(mSoftApManager.getRole()).thenReturn(ROLE_SOFTAP_TETHERED);
1108         doAnswer(new Answer<SoftApManager>() {
1109             public SoftApManager answer(InvocationOnMock invocation) {
1110                 Object[] args = invocation.getArguments();
1111                 mSoftApListener = (Listener<SoftApManager>) args[0];
1112                 return mSoftApManager;
1113             }
1114         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
1115                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(tetherConfig),
1116                 eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
1117         // make a second softap manager
1118         SoftApManager lohsSoftapManager = mock(SoftApManager.class);
1119         when(lohsSoftapManager.getRole()).thenReturn(ROLE_SOFTAP_LOCAL_ONLY);
1120         Mutable<Listener<SoftApManager>> lohsSoftApListener = new Mutable<>();
1121         doAnswer(new Answer<SoftApManager>() {
1122             public SoftApManager answer(InvocationOnMock invocation) {
1123                 Object[] args = invocation.getArguments();
1124                 lohsSoftApListener.value = (Listener<SoftApManager>) args[0];
1125                 return lohsSoftapManager;
1126             }
1127         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
1128                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(lohsConfig),
1129                 eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_LOCAL_ONLY), anyBoolean());
1130 
1131         // enable tethering and LOHS
1132         mActiveModeWarden.startSoftAp(tetherConfig, TEST_WORKSOURCE);
1133         mLooper.dispatchAll();
1134         mSoftApListener.onStarted(mSoftApManager);
1135         mActiveModeWarden.startSoftAp(lohsConfig, TEST_WORKSOURCE);
1136         mLooper.dispatchAll();
1137         lohsSoftApListener.value.onStarted(lohsSoftapManager);
1138         verify(mWifiInjector).makeSoftApManager(any(Listener.class),
1139                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(tetherConfig),
1140                 eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
1141         verify(mWifiInjector).makeSoftApManager(any(Listener.class),
1142                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(lohsConfig),
1143                 eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_LOCAL_ONLY), anyBoolean());
1144         verify(mBatteryStats).reportWifiOn();
1145 
1146         // disable tethering
1147         mActiveModeWarden.stopSoftAp(WifiManager.IFACE_IP_MODE_TETHERED);
1148         mLooper.dispatchAll();
1149         verify(mSoftApManager).stop();
1150         verify(lohsSoftapManager, never()).stop();
1151 
1152         mSoftApListener.onStopped(mSoftApManager);
1153         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
1154     }
1155 
1156     /**
1157      * Verify that toggling wifi from disabled starts client mode.
1158      */
1159     @Test
enableWifi()1160     public void enableWifi() throws Exception {
1161         assertInDisabledState();
1162 
1163         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
1164         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
1165         mLooper.dispatchAll();
1166 
1167         verify(mWifiInjector).makeClientModeManager(
1168                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY),
1169                 anyBoolean());
1170         mClientListener.onStarted(mClientModeManager);
1171         mLooper.dispatchAll();
1172 
1173         // always set primary, even with single STA
1174         verify(mWifiNative).setMultiStaPrimaryConnection(WIFI_IFACE_NAME);
1175 
1176         assertInEnabledState();
1177     }
1178 
1179     /**
1180      * Test verifying that we can enter scan mode when the scan mode changes
1181      */
1182     @Test
enableScanMode()1183     public void enableScanMode() throws Exception {
1184         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1185         mActiveModeWarden.scanAlwaysModeChanged();
1186         mLooper.dispatchAll();
1187         verify(mWifiInjector).makeClientModeManager(
1188                 any(), eq(new WorkSource(Process.WIFI_UID)), eq(ROLE_CLIENT_SCAN_ONLY),
1189                 anyBoolean());
1190         assertInEnabledState();
1191         verify(mClientModeManager, never()).stop();
1192     }
1193 
1194     /**
1195      * Test verifying that we ignore scan enable event when wifi is already enabled.
1196      */
1197     @Test
ignoreEnableScanModeWhenWifiEnabled()1198     public void ignoreEnableScanModeWhenWifiEnabled() throws Exception {
1199         // Turn on WIFI
1200         assertInDisabledState();
1201         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
1202         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
1203         mLooper.dispatchAll();
1204         mClientListener.onStarted(mClientModeManager);
1205         mLooper.dispatchAll();
1206         assertInEnabledState();
1207 
1208         // Now toggle scan only change, should be ignored. We should send a role change
1209         // again with PRIMARY & the cached requestorWs.
1210         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1211         mActiveModeWarden.scanAlwaysModeChanged();
1212         mLooper.dispatchAll();
1213         verify(mClientModeManager).setRole(ROLE_CLIENT_PRIMARY, TEST_WORKSOURCE);
1214         assertInEnabledState();
1215         verify(mClientModeManager, never()).stop();
1216     }
1217 
1218     /**
1219      * Verify that if scanning is enabled at startup, we enter scan mode
1220      */
1221     @Test
testEnterScanModeAtStartWhenSet()1222     public void testEnterScanModeAtStartWhenSet() throws Exception {
1223         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1224 
1225         mActiveModeWarden = createActiveModeWarden();
1226         mActiveModeWarden.start();
1227         mLooper.dispatchAll();
1228 
1229         assertInEnabledState();
1230     }
1231 
1232     /**
1233      * Verify that if Wifi is enabled at startup, we enter client mode
1234      */
1235     @Test
testEnterClientModeAtStartWhenSet()1236     public void testEnterClientModeAtStartWhenSet() throws Exception {
1237         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
1238 
1239         mActiveModeWarden = createActiveModeWarden();
1240         mActiveModeWarden.start();
1241         mLooper.dispatchAll();
1242 
1243         verify(mWifiMetrics).noteWifiEnabledDuringBoot(true);
1244 
1245         assertInEnabledState();
1246 
1247         verify(mWifiInjector)
1248                 .makeClientModeManager(any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1249     }
1250 
1251     /**
1252      * Do not enter scan mode if location mode disabled.
1253      */
1254     @Test
testDoesNotEnterScanModeWhenLocationModeDisabled()1255     public void testDoesNotEnterScanModeWhenLocationModeDisabled() throws Exception {
1256         // Start a new WifiController with wifi disabled
1257         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
1258         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
1259         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
1260 
1261         mActiveModeWarden = createActiveModeWarden();
1262         mActiveModeWarden.start();
1263         mLooper.dispatchAll();
1264 
1265         assertInDisabledState();
1266 
1267         // toggling scan always available is not sufficient for scan mode
1268         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1269         mActiveModeWarden.scanAlwaysModeChanged();
1270         mLooper.dispatchAll();
1271 
1272         assertInDisabledState();
1273     }
1274 
1275     /**
1276      * Only enter scan mode if location mode enabled
1277      */
1278     @Test
testEnterScanModeWhenLocationModeEnabled()1279     public void testEnterScanModeWhenLocationModeEnabled() throws Exception {
1280         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1281         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
1282 
1283         reset(mContext);
1284         when(mContext.getResources()).thenReturn(mResources);
1285         mActiveModeWarden = createActiveModeWarden();
1286         mActiveModeWarden.start();
1287         mLooper.dispatchAll();
1288 
1289         ArgumentCaptor<BroadcastReceiver> bcastRxCaptor =
1290                 ArgumentCaptor.forClass(BroadcastReceiver.class);
1291         verify(mContext).registerReceiver(
1292                 bcastRxCaptor.capture(),
1293                 argThat(filter -> filter.hasAction(LocationManager.MODE_CHANGED_ACTION)));
1294         BroadcastReceiver broadcastReceiver = bcastRxCaptor.getValue();
1295 
1296         assertInDisabledState();
1297 
1298         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
1299         Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
1300         broadcastReceiver.onReceive(mContext, intent);
1301         mLooper.dispatchAll();
1302 
1303         assertInEnabledState();
1304     }
1305 
1306 
1307     /**
1308      * Disabling location mode when in scan mode will disable wifi
1309      */
1310     @Test
testExitScanModeWhenLocationModeDisabled()1311     public void testExitScanModeWhenLocationModeDisabled() throws Exception {
1312         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1313         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
1314         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
1315 
1316         reset(mContext);
1317         when(mContext.getResources()).thenReturn(mResources);
1318         mActiveModeWarden = createActiveModeWarden();
1319         mActiveModeWarden.start();
1320         mLooper.dispatchAll();
1321         mClientListener.onStarted(mClientModeManager);
1322         mLooper.dispatchAll();
1323 
1324         ArgumentCaptor<BroadcastReceiver> bcastRxCaptor =
1325                 ArgumentCaptor.forClass(BroadcastReceiver.class);
1326         verify(mContext).registerReceiver(
1327                 bcastRxCaptor.capture(),
1328                 argThat(filter -> filter.hasAction(LocationManager.MODE_CHANGED_ACTION)));
1329         BroadcastReceiver broadcastReceiver = bcastRxCaptor.getValue();
1330 
1331         assertInEnabledState();
1332 
1333         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
1334         Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
1335         broadcastReceiver.onReceive(mContext, intent);
1336         mLooper.dispatchAll();
1337 
1338         mClientListener.onStopped(mClientModeManager);
1339         mLooper.dispatchAll();
1340 
1341         assertInDisabledState();
1342     }
1343 
1344     /**
1345      * When in Client mode, make sure ECM triggers wifi shutdown.
1346      */
1347     @Test
testEcmOnFromClientMode()1348     public void testEcmOnFromClientMode() throws Exception {
1349         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
1350         enableWifi();
1351 
1352         // Test with WifiDisableInECBM turned on:
1353         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1354 
1355         assertWifiShutDown(() -> {
1356             // test ecm changed
1357             emergencyCallbackModeChanged(true);
1358             mLooper.dispatchAll();
1359         });
1360     }
1361 
1362     /**
1363      * ECM disabling messages, when in client mode (not expected) do not trigger state changes.
1364      */
1365     @Test
testEcmOffInClientMode()1366     public void testEcmOffInClientMode() throws Exception {
1367         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
1368         enableWifi();
1369 
1370         // Test with WifiDisableInECBM turned off
1371         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
1372 
1373         assertEnteredEcmMode(() -> {
1374             // test ecm changed
1375             emergencyCallbackModeChanged(true);
1376             mLooper.dispatchAll();
1377         });
1378     }
1379 
1380     /**
1381      * When ECM activates and we are in client mode, disabling ECM should return us to client mode.
1382      */
1383     @Test
testEcmDisabledReturnsToClientMode()1384     public void testEcmDisabledReturnsToClientMode() throws Exception {
1385         enableWifi();
1386         assertInEnabledState();
1387 
1388         // Test with WifiDisableInECBM turned on:
1389         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1390 
1391         assertWifiShutDown(() -> {
1392             // test ecm changed
1393             emergencyCallbackModeChanged(true);
1394             mLooper.dispatchAll();
1395         });
1396 
1397         // test ecm changed
1398         emergencyCallbackModeChanged(false);
1399         mLooper.dispatchAll();
1400 
1401         assertInEnabledState();
1402     }
1403 
1404     /**
1405      * When Ecm mode is enabled, we should shut down wifi when we get an emergency mode changed
1406      * update.
1407      */
1408     @Test
testEcmOnFromScanMode()1409     public void testEcmOnFromScanMode() throws Exception {
1410         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1411         mActiveModeWarden.scanAlwaysModeChanged();
1412         mLooper.dispatchAll();
1413 
1414         mClientListener.onStarted(mClientModeManager);
1415         mLooper.dispatchAll();
1416 
1417         assertInEnabledState();
1418 
1419         // Test with WifiDisableInECBM turned on:
1420         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1421 
1422         assertWifiShutDown(() -> {
1423             // test ecm changed
1424             emergencyCallbackModeChanged(true);
1425             mLooper.dispatchAll();
1426         });
1427     }
1428 
1429     /**
1430      * When Ecm mode is disabled, we should not shut down scan mode if we get an emergency mode
1431      * changed update, but we should turn off soft AP
1432      */
1433     @Test
testEcmOffInScanMode()1434     public void testEcmOffInScanMode() throws Exception {
1435         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1436         mActiveModeWarden.scanAlwaysModeChanged();
1437         mLooper.dispatchAll();
1438 
1439         assertInEnabledState();
1440 
1441         // Test with WifiDisableInECBM turned off:
1442         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
1443 
1444         assertEnteredEcmMode(() -> {
1445             // test ecm changed
1446             emergencyCallbackModeChanged(true);
1447             mLooper.dispatchAll();
1448         });
1449     }
1450 
1451     /**
1452      * When ECM is disabled, we should return to scan mode
1453      */
1454     @Test
testEcmDisabledReturnsToScanMode()1455     public void testEcmDisabledReturnsToScanMode() throws Exception {
1456         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1457         mActiveModeWarden.scanAlwaysModeChanged();
1458         mLooper.dispatchAll();
1459 
1460         assertInEnabledState();
1461 
1462         // Test with WifiDisableInECBM turned on:
1463         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1464 
1465         assertWifiShutDown(() -> {
1466             // test ecm changed
1467             emergencyCallbackModeChanged(true);
1468             mLooper.dispatchAll();
1469         });
1470 
1471         // test ecm changed
1472         emergencyCallbackModeChanged(false);
1473         mLooper.dispatchAll();
1474 
1475         assertInEnabledState();
1476     }
1477 
1478     /**
1479      * When Ecm mode is enabled, we should shut down wifi when we get an emergency mode changed
1480      * update.
1481      */
1482     @Test
testEcmOnFromSoftApMode()1483     public void testEcmOnFromSoftApMode() throws Exception {
1484         enterSoftApActiveMode();
1485 
1486         // Test with WifiDisableInECBM turned on:
1487         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1488 
1489         assertEnteredEcmMode(() -> {
1490             // test ecm changed
1491             emergencyCallbackModeChanged(true);
1492             mLooper.dispatchAll();
1493         });
1494     }
1495 
1496     /**
1497      * When Ecm mode is disabled, we should shut down softap mode if we get an emergency mode
1498      * changed update
1499      */
1500     @Test
testEcmOffInSoftApMode()1501     public void testEcmOffInSoftApMode() throws Exception {
1502         enterSoftApActiveMode();
1503 
1504         // Test with WifiDisableInECBM turned off:
1505         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
1506 
1507         // test ecm changed
1508         emergencyCallbackModeChanged(true);
1509         mLooper.dispatchAll();
1510 
1511         verify(mSoftApManager).stop();
1512     }
1513 
1514     /**
1515      * When ECM is activated and we were in softap mode, we should just return to wifi off when ECM
1516      * ends
1517      */
1518     @Test
testEcmDisabledRemainsDisabledWhenSoftApHadBeenOn()1519     public void testEcmDisabledRemainsDisabledWhenSoftApHadBeenOn() throws Exception {
1520         assertInDisabledState();
1521 
1522         enterSoftApActiveMode();
1523 
1524         // verify Soft AP Manager started
1525         verify(mWifiInjector).makeSoftApManager(
1526                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
1527 
1528         // Test with WifiDisableInECBM turned on:
1529         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1530 
1531         assertEnteredEcmMode(() -> {
1532             // test ecm changed
1533             emergencyCallbackModeChanged(true);
1534             mLooper.dispatchAll();
1535             mSoftApListener.onStopped(mSoftApManager);
1536             mLooper.dispatchAll();
1537         });
1538 
1539         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
1540 
1541         // test ecm changed
1542         emergencyCallbackModeChanged(false);
1543         mLooper.dispatchAll();
1544 
1545         assertInDisabledState();
1546 
1547         // verify no additional calls to enable softap
1548         verify(mWifiInjector).makeSoftApManager(
1549                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
1550     }
1551 
1552     /**
1553      * Wifi should remain off when already disabled and we enter ECM.
1554      */
1555     @Test
testEcmOnFromDisabledMode()1556     public void testEcmOnFromDisabledMode() throws Exception {
1557         assertInDisabledState();
1558         verify(mWifiInjector, never()).makeSoftApManager(
1559                 any(), any(), any(), any(), any(), anyBoolean());
1560         verify(mWifiInjector, never()).makeClientModeManager(
1561                 any(), any(), any(), anyBoolean());
1562 
1563         // Test with WifiDisableInECBM turned on:
1564         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1565 
1566         assertEnteredEcmMode(() -> {
1567             // test ecm changed
1568             emergencyCallbackModeChanged(true);
1569             mLooper.dispatchAll();
1570         });
1571     }
1572 
1573 
1574     /**
1575      * Updates about call state change also trigger entry of ECM mode.
1576      */
1577     @Test
testEnterEcmOnEmergencyCallStateChange()1578     public void testEnterEcmOnEmergencyCallStateChange() throws Exception {
1579         assertInDisabledState();
1580 
1581         enableWifi();
1582         assertInEnabledState();
1583 
1584         // Test with WifiDisableInECBM turned on:
1585         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1586 
1587         assertEnteredEcmMode(() -> {
1588             // test call state changed
1589             emergencyCallStateChanged(true);
1590             mLooper.dispatchAll();
1591             mClientListener.onStopped(mClientModeManager);
1592             mLooper.dispatchAll();
1593         });
1594 
1595         emergencyCallStateChanged(false);
1596         mLooper.dispatchAll();
1597 
1598         assertInEnabledState();
1599     }
1600 
1601     /**
1602      * Verify when both ECM and call state changes arrive, we enter ECM mode
1603      */
1604     @Test
testEnterEcmWithBothSignals()1605     public void testEnterEcmWithBothSignals() throws Exception {
1606         assertInDisabledState();
1607 
1608         enableWifi();
1609         assertInEnabledState();
1610 
1611         // Test with WifiDisableInECBM turned on:
1612         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1613 
1614         assertWifiShutDown(() -> {
1615             emergencyCallStateChanged(true);
1616             mLooper.dispatchAll();
1617             mClientListener.onStopped(mClientModeManager);
1618             mLooper.dispatchAll();
1619         });
1620 
1621         assertWifiShutDown(() -> {
1622             emergencyCallbackModeChanged(true);
1623             mLooper.dispatchAll();
1624         }, 0); // does not cause another shutdown
1625 
1626         // client mode only started once so far
1627         verify(mWifiInjector).makeClientModeManager(
1628                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1629 
1630         emergencyCallStateChanged(false);
1631         mLooper.dispatchAll();
1632 
1633         // stay in ecm, do not send an additional client mode trigger
1634         assertInEmergencyMode();
1635         // assert that the underlying state is in disabled state
1636         assertInDisabledState();
1637 
1638         // client mode still only started once
1639         verify(mWifiInjector).makeClientModeManager(
1640                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1641 
1642         emergencyCallbackModeChanged(false);
1643         mLooper.dispatchAll();
1644 
1645         // now we can re-enable wifi
1646         verify(mWifiInjector, times(2)).makeClientModeManager(
1647                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1648         assertInEnabledState();
1649     }
1650 
1651     /**
1652      * Verify when both ECM and call state changes arrive but out of order, we enter ECM mode
1653      */
1654     @Test
testEnterEcmWithBothSignalsOutOfOrder()1655     public void testEnterEcmWithBothSignalsOutOfOrder() throws Exception {
1656         assertInDisabledState();
1657 
1658         enableWifi();
1659 
1660         assertInEnabledState();
1661         verify(mWifiInjector).makeClientModeManager(
1662                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1663 
1664         // Test with WifiDisableInECBM turned on:
1665         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1666 
1667         assertEnteredEcmMode(() -> {
1668             emergencyCallbackModeChanged(true);
1669             mLooper.dispatchAll();
1670             mClientListener.onStopped(mClientModeManager);
1671             mLooper.dispatchAll();
1672         });
1673         assertInDisabledState();
1674 
1675         assertEnteredEcmMode(() -> {
1676             emergencyCallStateChanged(true);
1677             mLooper.dispatchAll();
1678         }, 0); // does not enter ECM state again
1679 
1680         emergencyCallStateChanged(false);
1681         mLooper.dispatchAll();
1682 
1683         // stay in ecm, do not send an additional client mode trigger
1684         assertInEmergencyMode();
1685         // assert that the underlying state is in disabled state
1686         assertInDisabledState();
1687 
1688         // client mode still only started once
1689         verify(mWifiInjector).makeClientModeManager(
1690                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1691 
1692         emergencyCallbackModeChanged(false);
1693         mLooper.dispatchAll();
1694 
1695         // now we can re-enable wifi
1696         verify(mWifiInjector, times(2)).makeClientModeManager(
1697                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1698         assertInEnabledState();
1699     }
1700 
1701     /**
1702      * Verify when both ECM and call state changes arrive but completely out of order,
1703      * we still enter and properly exit ECM mode
1704      */
1705     @Test
testEnterEcmWithBothSignalsOppositeOrder()1706     public void testEnterEcmWithBothSignalsOppositeOrder() throws Exception {
1707         assertInDisabledState();
1708 
1709         enableWifi();
1710 
1711         assertInEnabledState();
1712         verify(mWifiInjector).makeClientModeManager(
1713                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1714 
1715         // Test with WifiDisableInECBM turned on:
1716         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1717 
1718         assertEnteredEcmMode(() -> {
1719             emergencyCallStateChanged(true);
1720             mLooper.dispatchAll();
1721             mClientListener.onStopped(mClientModeManager);
1722             mLooper.dispatchAll();
1723         });
1724         assertInDisabledState();
1725 
1726         assertEnteredEcmMode(() -> {
1727             emergencyCallbackModeChanged(true);
1728             mLooper.dispatchAll();
1729         }, 0); // still only 1 shutdown
1730 
1731         emergencyCallbackModeChanged(false);
1732         mLooper.dispatchAll();
1733 
1734         // stay in ecm, do not send an additional client mode trigger
1735         assertInEmergencyMode();
1736         // assert that the underlying state is in disabled state
1737         assertInDisabledState();
1738 
1739         // client mode still only started once
1740         verify(mWifiInjector).makeClientModeManager(
1741                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1742 
1743         emergencyCallStateChanged(false);
1744         mLooper.dispatchAll();
1745 
1746         // now we can re-enable wifi
1747         verify(mWifiInjector, times(2)).makeClientModeManager(
1748                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1749         assertInEnabledState();
1750     }
1751 
1752     /**
1753      * When ECM is active, we might get addition signals of ECM mode, drop those additional signals,
1754      * we must exit when one of each signal is received.
1755      *
1756      * In any case, duplicate signals indicate a bug from Telephony. Each signal should be turned
1757      * off before it is turned on again.
1758      */
1759     @Test
testProperExitFromEcmModeWithMultipleMessages()1760     public void testProperExitFromEcmModeWithMultipleMessages() throws Exception {
1761         assertInDisabledState();
1762 
1763         enableWifi();
1764 
1765         verify(mWifiInjector).makeClientModeManager(
1766                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1767         assertInEnabledState();
1768 
1769         // Test with WifiDisableInECBM turned on:
1770         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1771 
1772         assertEnteredEcmMode(() -> {
1773             emergencyCallbackModeChanged(true);
1774             emergencyCallStateChanged(true);
1775             emergencyCallStateChanged(true);
1776             emergencyCallbackModeChanged(true);
1777             emergencyCallbackModeChanged(true);
1778             mLooper.dispatchAll();
1779             mClientListener.onStopped(mClientModeManager);
1780             mLooper.dispatchAll();
1781         });
1782         assertInDisabledState();
1783 
1784         assertEnteredEcmMode(() -> {
1785             emergencyCallbackModeChanged(false);
1786             mLooper.dispatchAll();
1787             emergencyCallbackModeChanged(false);
1788             mLooper.dispatchAll();
1789             emergencyCallbackModeChanged(false);
1790             mLooper.dispatchAll();
1791             emergencyCallbackModeChanged(false);
1792             mLooper.dispatchAll();
1793         }, 0);
1794 
1795         // didn't enter client mode again
1796         verify(mWifiInjector).makeClientModeManager(
1797                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1798         assertInDisabledState();
1799 
1800         // now we will exit ECM
1801         emergencyCallStateChanged(false);
1802         mLooper.dispatchAll();
1803 
1804         // now we can re-enable wifi
1805         verify(mWifiInjector, times(2)).makeClientModeManager(
1806                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1807         assertInEnabledState();
1808     }
1809 
1810     /**
1811      * Toggling wifi on when in ECM does not exit ecm mode and enable wifi
1812      */
1813     @Test
testWifiDoesNotToggleOnWhenInEcm()1814     public void testWifiDoesNotToggleOnWhenInEcm() throws Exception {
1815         assertInDisabledState();
1816 
1817         // Test with WifiDisableInECBM turned on:
1818         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1819         // test ecm changed
1820         assertEnteredEcmMode(() -> {
1821             emergencyCallbackModeChanged(true);
1822             mLooper.dispatchAll();
1823         });
1824 
1825         // now toggle wifi and verify we do not start wifi
1826         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
1827         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
1828         mLooper.dispatchAll();
1829 
1830         verify(mWifiInjector, never()).makeClientModeManager(
1831                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1832         assertInDisabledState();
1833         assertInEmergencyMode();
1834 
1835         // now we will exit ECM
1836         emergencyCallbackModeChanged(false);
1837         mLooper.dispatchAll();
1838         assertNotInEmergencyMode();
1839 
1840         // Wifi toggle on now takes effect
1841         verify(mWifiInjector).makeClientModeManager(
1842                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1843         assertInEnabledState();
1844     }
1845 
1846     /**
1847      * Toggling wifi off when in ECM does not disable wifi when getConfigWiFiDisableInECBM is
1848      * disabled.
1849      */
1850     @Test
testWifiDoesNotToggleOffWhenInEcmAndConfigDisabled()1851     public void testWifiDoesNotToggleOffWhenInEcmAndConfigDisabled() throws Exception {
1852         enableWifi();
1853         assertInEnabledState();
1854         verify(mWifiInjector).makeClientModeManager(
1855                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1856 
1857         // Test with WifiDisableInECBM turned off
1858         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
1859         // test ecm changed
1860         assertEnteredEcmMode(() -> {
1861             emergencyCallbackModeChanged(true);
1862             mLooper.dispatchAll();
1863         });
1864 
1865         // now toggle wifi and verify we do not start wifi
1866         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
1867         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
1868         mLooper.dispatchAll();
1869 
1870         // still only called once
1871         verify(mWifiInjector).makeClientModeManager(
1872                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1873         verify(mClientModeManager, never()).stop();
1874         assertInEnabledState();
1875         assertInEmergencyMode();
1876 
1877         // now we will exit ECM
1878         emergencyCallbackModeChanged(false);
1879         mLooper.dispatchAll();
1880         assertNotInEmergencyMode();
1881 
1882         // Wifi toggle off now takes effect
1883         verify(mClientModeManager).stop();
1884         mClientListener.onStopped(mClientModeManager);
1885         mLooper.dispatchAll();
1886         assertInDisabledState();
1887     }
1888 
1889     @Test
testAirplaneModeDoesNotToggleOnWhenInEcm()1890     public void testAirplaneModeDoesNotToggleOnWhenInEcm() throws Exception {
1891         // TODO(b/139829963): investigate the expected behavior is when toggling airplane mode in
1892         //  ECM
1893     }
1894 
1895     /**
1896      * Toggling scan mode when in ECM does not exit ecm mode and enable scan mode
1897      */
1898     @Test
testScanModeDoesNotToggleOnWhenInEcm()1899     public void testScanModeDoesNotToggleOnWhenInEcm() throws Exception {
1900         assertInDisabledState();
1901 
1902         // Test with WifiDisableInECBM turned on:
1903         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1904         assertEnteredEcmMode(() -> {
1905             // test ecm changed
1906             emergencyCallbackModeChanged(true);
1907             mLooper.dispatchAll();
1908         });
1909 
1910         // now enable scanning and verify we do not start wifi
1911         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
1912         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1913         mActiveModeWarden.scanAlwaysModeChanged();
1914         mLooper.dispatchAll();
1915 
1916         verify(mWifiInjector, never()).makeClientModeManager(
1917                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1918         assertInDisabledState();
1919     }
1920 
1921 
1922     /**
1923      * Toggling softap mode when in ECM does not exit ecm mode and enable softap
1924      */
1925     @Test
testSoftApModeDoesNotToggleOnWhenInEcm()1926     public void testSoftApModeDoesNotToggleOnWhenInEcm() throws Exception {
1927         assertInDisabledState();
1928 
1929         // Test with WifiDisableInECBM turned on:
1930         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1931         assertEnteredEcmMode(() -> {
1932             // test ecm changed
1933             emergencyCallbackModeChanged(true);
1934             mLooper.dispatchAll();
1935         });
1936 
1937         // try to start Soft AP
1938         mActiveModeWarden.startSoftAp(
1939                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
1940                 mSoftApCapability), TEST_WORKSOURCE);
1941         mLooper.dispatchAll();
1942 
1943         verify(mWifiInjector, never())
1944                 .makeSoftApManager(any(), any(), any(), eq(TEST_WORKSOURCE), any(), anyBoolean());
1945         assertInDisabledState();
1946 
1947         // verify triggered Soft AP failure callback
1948         verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
1949                 WifiManager.SAP_START_FAILURE_GENERAL);
1950 
1951         // try to start LOHS
1952         mActiveModeWarden.startSoftAp(
1953                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_LOCAL_ONLY, null,
1954                 mSoftApCapability), TEST_WORKSOURCE);
1955         mLooper.dispatchAll();
1956 
1957         verify(mWifiInjector, never())
1958                 .makeSoftApManager(any(), any(), any(), eq(TEST_WORKSOURCE), any(), anyBoolean());
1959         assertInDisabledState();
1960 
1961         // verify triggered LOHS failure callback
1962         verify(mLohsStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
1963                 WifiManager.SAP_START_FAILURE_GENERAL);
1964     }
1965 
1966     /**
1967      * Toggling off softap mode when in ECM does not induce a mode change
1968      */
1969     @Test
testSoftApStoppedDoesNotSwitchModesWhenInEcm()1970     public void testSoftApStoppedDoesNotSwitchModesWhenInEcm() throws Exception {
1971         assertInDisabledState();
1972 
1973         // Test with WifiDisableInECBM turned on:
1974         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1975         assertEnteredEcmMode(() -> {
1976             // test ecm changed
1977             emergencyCallbackModeChanged(true);
1978             mLooper.dispatchAll();
1979         });
1980 
1981         mActiveModeWarden.stopSoftAp(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1982         mLooper.dispatchAll();
1983 
1984         assertInDisabledState();
1985         verifyNoMoreInteractions(mSoftApManager, mClientModeManager);
1986     }
1987 
1988     /**
1989      * Toggling softap mode when in airplane mode needs to enable softap
1990      */
1991     @Test
testSoftApModeToggleWhenInAirplaneMode()1992     public void testSoftApModeToggleWhenInAirplaneMode() throws Exception {
1993         // Test with airplane mode turned on:
1994         when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
1995 
1996         // Turn on SoftAp.
1997         mActiveModeWarden.startSoftAp(
1998                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
1999                 mSoftApCapability), TEST_WORKSOURCE);
2000         mLooper.dispatchAll();
2001         verify(mWifiInjector)
2002                 .makeSoftApManager(any(), any(), any(), eq(TEST_WORKSOURCE), any(), anyBoolean());
2003 
2004         // Turn off SoftAp.
2005         mActiveModeWarden.stopSoftAp(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
2006         mLooper.dispatchAll();
2007 
2008         verify(mSoftApManager).stop();
2009     }
2010 
2011     /**
2012      * Toggling off scan mode when in ECM does not induce a mode change
2013      */
2014     @Test
testScanModeStoppedSwitchModeToDisabledStateWhenInEcm()2015     public void testScanModeStoppedSwitchModeToDisabledStateWhenInEcm() throws Exception {
2016         enterScanOnlyModeActiveState();
2017         assertInEnabledState();
2018 
2019         // Test with WifiDisableInECBM turned on:
2020         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2021         assertEnteredEcmMode(() -> {
2022             // test ecm changed
2023             emergencyCallbackModeChanged(true);
2024             mLooper.dispatchAll();
2025             mClientListener.onStopped(mClientModeManager);
2026             mLooper.dispatchAll();
2027         });
2028 
2029         // Spurious onStopped
2030         mClientListener.onStopped(mClientModeManager);
2031         mLooper.dispatchAll();
2032 
2033         assertInDisabledState();
2034     }
2035 
2036     /**
2037      * Toggling off client mode when in ECM does not induce a mode change
2038      */
2039     @Test
testClientModeStoppedSwitchModeToDisabledStateWhenInEcm()2040     public void testClientModeStoppedSwitchModeToDisabledStateWhenInEcm() throws Exception {
2041         enterClientModeActiveState();
2042         assertInEnabledState();
2043 
2044         // Test with WifiDisableInECBM turned on:
2045         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2046         assertEnteredEcmMode(() -> {
2047             // test ecm changed
2048             emergencyCallbackModeChanged(true);
2049             mLooper.dispatchAll();
2050             mClientListener.onStopped(mClientModeManager);
2051             mLooper.dispatchAll();
2052         });
2053 
2054         // Spurious onStopped
2055         mClientListener.onStopped(mClientModeManager);
2056         mLooper.dispatchAll();
2057 
2058         assertInDisabledState();
2059     }
2060 
2061     /**
2062      * When AP mode is enabled and wifi was previously in AP mode, we should return to
2063      * EnabledState after the AP is disabled.
2064      * Enter EnabledState, activate AP mode, disable AP mode.
2065      * <p>
2066      * Expected: AP should successfully start and exit, then return to EnabledState.
2067      */
2068     @Test
testReturnToEnabledStateAfterAPModeShutdown()2069     public void testReturnToEnabledStateAfterAPModeShutdown() throws Exception {
2070         enableWifi();
2071         assertInEnabledState();
2072         verify(mWifiInjector).makeClientModeManager(
2073                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2074 
2075         mActiveModeWarden.startSoftAp(
2076                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
2077                 mSoftApCapability), TEST_WORKSOURCE);
2078         // add an "unexpected" sta mode stop to simulate a single interface device
2079         mClientListener.onStopped(mClientModeManager);
2080         mLooper.dispatchAll();
2081         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2082 
2083         // Now stop the AP
2084         mSoftApListener.onStopped(mSoftApManager);
2085         mLooper.dispatchAll();
2086         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
2087 
2088         // We should re-enable client mode
2089         verify(mWifiInjector, times(2)).makeClientModeManager(
2090                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2091         assertInEnabledState();
2092     }
2093 
2094     /**
2095      * When in STA mode and SoftAP is enabled and the device supports STA+AP (i.e. the STA wasn't
2096      * shut down when the AP started), both modes will be running concurrently.
2097      *
2098      * Then when the AP is disabled, we should remain in STA mode.
2099      *
2100      * Enter EnabledState, activate AP mode, toggle WiFi off.
2101      * <p>
2102      * Expected: AP should successfully start and exit, then return to EnabledState.
2103      */
2104     @Test
testReturnToEnabledStateAfterWifiEnabledShutdown()2105     public void testReturnToEnabledStateAfterWifiEnabledShutdown() throws Exception {
2106         enableWifi();
2107         assertInEnabledState();
2108         verify(mWifiInjector).makeClientModeManager(
2109                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2110 
2111         mActiveModeWarden.startSoftAp(
2112                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
2113                 mSoftApCapability), TEST_WORKSOURCE);
2114         mLooper.dispatchAll();
2115 
2116         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
2117         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
2118         mSoftApListener.onStopped(mSoftApManager);
2119         mLooper.dispatchAll();
2120 
2121         // wasn't called again
2122         verify(mWifiInjector).makeClientModeManager(
2123                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2124         assertInEnabledState();
2125     }
2126 
2127     @Test
testRestartWifiStackInEnabledStateTriggersBugReport()2128     public void testRestartWifiStackInEnabledStateTriggersBugReport() throws Exception {
2129         enableWifi();
2130 
2131         // note: using a reason that will typical not start a bug report on purpose to guarantee
2132         // that it is the flag and not the reason which controls it.
2133         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_LAST_RESORT_WATCHDOG, "some text",
2134                 true);
2135         mLooper.dispatchAll();
2136         verify(mWifiDiagnostics).takeBugReport(anyString(), anyString());
2137         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2138     }
2139 
2140     @Test
testRestartWifiWatchdogDoesNotTriggerBugReport()2141     public void testRestartWifiWatchdogDoesNotTriggerBugReport() throws Exception {
2142         enableWifi();
2143         // note: using a reason that will typical start a bug report on purpose to guarantee that
2144         // it is the flag and not the reason which controls it.
2145         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2146                 "anything", false);
2147         mLooper.dispatchAll();
2148         verify(mWifiDiagnostics, never()).takeBugReport(anyString(), anyString());
2149         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2150     }
2151 
2152     /**
2153      * When in sta mode, CMD_RECOVERY_DISABLE_WIFI messages should trigger wifi to disable.
2154      */
2155     @Test
testRecoveryDisabledTurnsWifiOff()2156     public void testRecoveryDisabledTurnsWifiOff() throws Exception {
2157         enableWifi();
2158         assertInEnabledState();
2159         mActiveModeWarden.recoveryDisableWifi();
2160         mLooper.dispatchAll();
2161         verify(mClientModeManager).stop();
2162         mClientListener.onStopped(mClientModeManager);
2163         mLooper.dispatchAll();
2164         assertInDisabledState();
2165         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2166     }
2167 
2168     /**
2169      * When wifi is disabled, CMD_RECOVERY_DISABLE_WIFI should not trigger a state change.
2170      */
2171     @Test
testRecoveryDisabledWhenWifiAlreadyOff()2172     public void testRecoveryDisabledWhenWifiAlreadyOff() throws Exception {
2173         assertInDisabledState();
2174         assertWifiShutDown(() -> {
2175             mActiveModeWarden.recoveryDisableWifi();
2176             mLooper.dispatchAll();
2177         });
2178         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS + 10);
2179         mLooper.dispatchAll();
2180 
2181         // Ensure we did not restart wifi.
2182         assertInDisabledState();
2183     }
2184 
2185     /**
2186      * The command to trigger a WiFi reset should not trigger any action by WifiController if we
2187      * are not in STA mode.
2188      * WiFi is not in connect mode, so any calls to reset the wifi stack due to connection failures
2189      * should be ignored.
2190      * Create and start WifiController in DisabledState, send command to restart WiFi
2191      * <p>
2192      * Expected: WiFiController should not call ActiveModeWarden.disableWifi()
2193      */
2194     @Test
testRestartWifiStackInDisabledState()2195     public void testRestartWifiStackInDisabledState() throws Exception {
2196         assertInDisabledState();
2197 
2198         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2199                 SelfRecovery.REASON_STRINGS[SelfRecovery.REASON_WIFINATIVE_FAILURE], true);
2200         mLooper.dispatchAll();
2201 
2202         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS + 10);
2203         mLooper.dispatchAll();
2204 
2205         assertInDisabledState();
2206         verifyNoMoreInteractions(mClientModeManager, mSoftApManager);
2207     }
2208 
2209     /**
2210      * The command to trigger a WiFi reset should trigger a wifi reset in ClientModeImpl through
2211      * the ActiveModeWarden.shutdownWifi() call when in STA mode.
2212      * When WiFi is in scan mode, calls to reset the wifi stack due to native failure
2213      * should trigger a supplicant stop, and subsequently, a driver reload.
2214      * Create and start WifiController in EnabledState, send command to restart WiFi
2215      * <p>
2216      * Expected: WiFiController should call ActiveModeWarden.shutdownWifi() and
2217      * ActiveModeWarden should enter SCAN_ONLY mode and the wifi driver should be started.
2218      */
2219     @Test
testRestartWifiStackInStaScanEnabledState()2220     public void testRestartWifiStackInStaScanEnabledState() throws Exception {
2221         assertInDisabledState();
2222 
2223         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
2224         mActiveModeWarden.scanAlwaysModeChanged();
2225         mLooper.dispatchAll();
2226 
2227         assertInEnabledState();
2228         verify(mWifiInjector).makeClientModeManager(
2229                 any(), eq(new WorkSource(Process.WIFI_UID)), eq(ROLE_CLIENT_SCAN_ONLY),
2230                 anyBoolean());
2231 
2232         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2233                 SelfRecovery.REASON_STRINGS[SelfRecovery.REASON_WIFINATIVE_FAILURE], true);
2234         mLooper.dispatchAll();
2235 
2236         verify(mClientModeManager).stop();
2237         mClientListener.onStopped(mClientModeManager);
2238         mLooper.dispatchAll();
2239         assertInDisabledState();
2240         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2241 
2242         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2243         mLooper.dispatchAll();
2244 
2245         verify(mWifiInjector, times(2)).makeClientModeManager(any(), any(), any(), anyBoolean());
2246         assertInEnabledState();
2247 
2248         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2249         verify(mSubsystemRestartCallback).onSubsystemRestarted();
2250     }
2251 
2252     /**
2253      * The command to trigger a WiFi reset should trigger a wifi reset in ClientModeImpl through
2254      * the ActiveModeWarden.shutdownWifi() call when in STA mode.
2255      * WiFi is in connect mode, calls to reset the wifi stack due to connection failures
2256      * should trigger a supplicant stop, and subsequently, a driver reload.
2257      * Create and start WifiController in EnabledState, send command to restart WiFi
2258      * <p>
2259      * Expected: WiFiController should call ActiveModeWarden.shutdownWifi() and
2260      * ActiveModeWarden should enter CONNECT_MODE and the wifi driver should be started.
2261      */
2262     @Test
testRestartWifiStackInStaConnectEnabledState()2263     public void testRestartWifiStackInStaConnectEnabledState() throws Exception {
2264         enableWifi();
2265         assertInEnabledState();
2266         verify(mWifiInjector).makeClientModeManager(
2267                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2268 
2269         assertWifiShutDown(() -> {
2270             mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2271                     SelfRecovery.REASON_STRINGS[SelfRecovery.REASON_WIFINATIVE_FAILURE], true);
2272             mLooper.dispatchAll();
2273             // Complete the stop
2274             mClientListener.onStopped(mClientModeManager);
2275             mLooper.dispatchAll();
2276         });
2277 
2278         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2279 
2280         // still only started once
2281         verify(mWifiInjector).makeClientModeManager(
2282                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2283 
2284         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2285         mLooper.dispatchAll();
2286 
2287         // started again
2288         verify(mWifiInjector, times(2)).makeClientModeManager(any(), any(), any(), anyBoolean());
2289         assertInEnabledState();
2290 
2291         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2292         verify(mSubsystemRestartCallback).onSubsystemRestarted();
2293     }
2294 
2295     /**
2296      * The command to trigger a WiFi reset should not trigger a reset when in ECM mode.
2297      * Enable wifi and enter ECM state, send command to restart wifi.
2298      * <p>
2299      * Expected: The command to trigger a wifi reset should be ignored and we should remain in ECM
2300      * mode.
2301      */
2302     @Test
testRestartWifiStackDoesNotExitECMMode()2303     public void testRestartWifiStackDoesNotExitECMMode() throws Exception {
2304         enableWifi();
2305         assertInEnabledState();
2306         verify(mWifiInjector).makeClientModeManager(
2307                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), eq(false));
2308 
2309         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2310         assertEnteredEcmMode(() -> {
2311             emergencyCallStateChanged(true);
2312             mLooper.dispatchAll();
2313             mClientListener.onStopped(mClientModeManager);
2314             mLooper.dispatchAll();
2315         });
2316         assertInEmergencyMode();
2317         assertInDisabledState();
2318         verify(mClientModeManager).stop();
2319         verify(mClientModeManager, atLeastOnce()).getRole();
2320         verify(mClientModeManager).clearWifiConnectedNetworkScorer();
2321         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2322 
2323         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_LAST_RESORT_WATCHDOG,
2324                 SelfRecovery.REASON_STRINGS[SelfRecovery.REASON_LAST_RESORT_WATCHDOG], false);
2325         mLooper.dispatchAll();
2326 
2327         // wasn't called again
2328         verify(mWifiInjector).makeClientModeManager(
2329                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2330         assertInEmergencyMode();
2331         assertInDisabledState();
2332 
2333         verify(mClientModeManager, atLeastOnce()).getInterfaceName();
2334         verifyNoMoreInteractions(mClientModeManager, mSoftApManager);
2335     }
2336 
2337     /**
2338      * The command to trigger a WiFi reset should trigger a wifi reset in SoftApManager through
2339      * the ActiveModeWarden.shutdownWifi() call when in SAP enabled mode.
2340      */
2341     @Test
testRestartWifiStackInTetheredSoftApEnabledState()2342     public void testRestartWifiStackInTetheredSoftApEnabledState() throws Exception {
2343         enterSoftApActiveMode();
2344         verify(mWifiInjector).makeSoftApManager(
2345                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2346 
2347         assertWifiShutDown(() -> {
2348             mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2349                     SelfRecovery.REASON_STRINGS[SelfRecovery.REASON_WIFINATIVE_FAILURE], true);
2350             mLooper.dispatchAll();
2351             // Complete the stop
2352             mSoftApListener.onStopped(mSoftApManager);
2353             mLooper.dispatchAll();
2354         });
2355 
2356         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
2357 
2358         // still only started once
2359         verify(mWifiInjector).makeSoftApManager(
2360                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2361 
2362         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2363         mLooper.dispatchAll();
2364 
2365         // started again
2366         verify(mWifiInjector, times(2)).makeSoftApManager(
2367                 any(), any(), any(), any(), any(), anyBoolean());
2368         assertInEnabledState();
2369 
2370         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2371         verify(mSubsystemRestartCallback).onSubsystemRestarted();
2372     }
2373 
2374     /**
2375      * The command to trigger a WiFi reset should trigger a wifi reset in SoftApManager &
2376      * ClientModeManager through the ActiveModeWarden.shutdownWifi() call when in STA + SAP
2377      * enabled mode.
2378      */
2379     @Test
testRestartWifiStackInTetheredSoftApAndStaConnectEnabledState()2380     public void testRestartWifiStackInTetheredSoftApAndStaConnectEnabledState() throws Exception {
2381         enableWifi();
2382         enterSoftApActiveMode();
2383         verify(mWifiInjector).makeClientModeManager(
2384                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2385         verify(mWifiInjector).makeSoftApManager(
2386                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2387 
2388         assertWifiShutDown(() -> {
2389             mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2390                     SelfRecovery.REASON_STRINGS[SelfRecovery.REASON_WIFINATIVE_FAILURE], true);
2391             mLooper.dispatchAll();
2392             // Complete the stop
2393             mClientListener.onStopped(mClientModeManager);
2394             mSoftApListener.onStopped(mSoftApManager);
2395             mLooper.dispatchAll();
2396         });
2397 
2398         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2399         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
2400 
2401         // still only started once
2402         verify(mWifiInjector).makeClientModeManager(
2403                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2404         verify(mWifiInjector).makeSoftApManager(
2405                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2406 
2407         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2408         mLooper.dispatchAll();
2409 
2410         // started again
2411         verify(mWifiInjector, times(2)).makeClientModeManager(any(), any(), any(), anyBoolean());
2412         verify(mWifiInjector, times(2)).makeSoftApManager(
2413                 any(), any(), any(), any(), any(), anyBoolean());
2414         assertInEnabledState();
2415 
2416         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2417         verify(mSubsystemRestartCallback).onSubsystemRestarted();
2418     }
2419 
2420     /**
2421      * Tests that when Wifi is already disabled and another Wifi toggle command arrives,
2422      * don't enter scan mode if {@link WifiSettingsStore#isScanAlwaysAvailable()} is false.
2423      * Note: {@link WifiSettingsStore#isScanAlwaysAvailable()} returns false if either the wifi
2424      * scanning is disabled and airplane mode is on.
2425      */
2426     @Test
staDisabled_toggleWifiOff_scanNotAvailable_dontGoToScanMode()2427     public void staDisabled_toggleWifiOff_scanNotAvailable_dontGoToScanMode() {
2428         assertInDisabledState();
2429 
2430         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
2431         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
2432         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
2433         when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
2434 
2435         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
2436         mLooper.dispatchAll();
2437 
2438         assertInDisabledState();
2439         verify(mWifiInjector, never()).makeClientModeManager(
2440                 any(), eq(TEST_WORKSOURCE), any(), anyBoolean());
2441     }
2442 
2443     /**
2444      * Tests that when Wifi is already disabled and another Wifi toggle command arrives,
2445      * enter scan mode if {@link WifiSettingsStore#isScanAlwaysAvailable()} is true.
2446      * Note: {@link WifiSettingsStore#isScanAlwaysAvailable()} returns true if both the wifi
2447      * scanning is enabled and airplane mode is off.
2448      */
2449     @Test
staDisabled_toggleWifiOff_scanAvailable_goToScanMode()2450     public void staDisabled_toggleWifiOff_scanAvailable_goToScanMode() {
2451         assertInDisabledState();
2452 
2453         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
2454         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
2455         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
2456         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
2457 
2458         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
2459         mLooper.dispatchAll();
2460 
2461         assertInEnabledState();
2462         verify(mWifiInjector).makeClientModeManager(
2463                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_SCAN_ONLY), anyBoolean());
2464     }
2465 
2466     /**
2467      * Tests that if the carrier config to disable Wifi is enabled during ECM, Wifi is shut down
2468      * when entering ECM and turned back on when exiting ECM.
2469      */
2470     @Test
ecmDisablesWifi_exitEcm_restartWifi()2471     public void ecmDisablesWifi_exitEcm_restartWifi() throws Exception {
2472         enterClientModeActiveState();
2473 
2474         verify(mWifiInjector).makeClientModeManager(
2475                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2476 
2477         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2478         assertEnteredEcmMode(() -> {
2479             emergencyCallbackModeChanged(true);
2480             mLooper.dispatchAll();
2481         });
2482         assertInEnabledState();
2483         verify(mClientModeManager).stop();
2484 
2485         mClientListener.onStopped(mClientModeManager);
2486         mLooper.dispatchAll();
2487         assertInDisabledState();
2488 
2489         emergencyCallbackModeChanged(false);
2490         mLooper.dispatchAll();
2491 
2492         assertNotInEmergencyMode();
2493         // client mode restarted
2494         verify(mWifiInjector, times(2)).makeClientModeManager(any(), any(), any(), anyBoolean());
2495         assertInEnabledState();
2496     }
2497 
2498     /**
2499      * Tests that if the carrier config to disable Wifi is not enabled during ECM, Wifi remains on
2500      * during ECM, and nothing happens after exiting ECM.
2501      */
2502     @Test
ecmDoesNotDisableWifi_exitEcm_noOp()2503     public void ecmDoesNotDisableWifi_exitEcm_noOp() throws Exception {
2504         enterClientModeActiveState();
2505 
2506         verify(mWifiInjector).makeClientModeManager(
2507                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2508 
2509         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
2510         assertEnteredEcmMode(() -> {
2511             emergencyCallbackModeChanged(true);
2512             mLooper.dispatchAll();
2513         });
2514         assertInEnabledState();
2515         verify(mClientModeManager, never()).stop();
2516 
2517         emergencyCallbackModeChanged(false);
2518         mLooper.dispatchAll();
2519 
2520         assertNotInEmergencyMode();
2521         // client mode manager not started again
2522         verify(mWifiInjector).makeClientModeManager(
2523                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2524         assertInEnabledState();
2525     }
2526 
2527     @Test
testUpdateCapabilityInSoftApActiveMode()2528     public void testUpdateCapabilityInSoftApActiveMode() throws Exception {
2529         SoftApCapability testCapability = new SoftApCapability(0);
2530         enterSoftApActiveMode();
2531         mActiveModeWarden.updateSoftApCapability(testCapability);
2532         mLooper.dispatchAll();
2533         verify(mSoftApManager).updateCapability(testCapability);
2534     }
2535 
2536     @Test
testUpdateConfigInSoftApActiveMode()2537     public void testUpdateConfigInSoftApActiveMode() throws Exception {
2538         SoftApConfiguration testConfig = new SoftApConfiguration.Builder()
2539                 .setSsid("Test123").build();
2540         enterSoftApActiveMode();
2541         mActiveModeWarden.updateSoftApConfiguration(testConfig);
2542         mLooper.dispatchAll();
2543         verify(mSoftApManager).updateConfiguration(testConfig);
2544     }
2545 
2546     @Test
testUpdateCapabilityInNonSoftApActiveMode()2547     public void testUpdateCapabilityInNonSoftApActiveMode() throws Exception {
2548         SoftApCapability testCapability = new SoftApCapability(0);
2549         enterClientModeActiveState();
2550         mActiveModeWarden.updateSoftApCapability(testCapability);
2551         mLooper.dispatchAll();
2552         verify(mSoftApManager, never()).updateCapability(any());
2553     }
2554 
2555     @Test
testUpdateConfigInNonSoftApActiveMode()2556     public void testUpdateConfigInNonSoftApActiveMode() throws Exception {
2557         SoftApConfiguration testConfig = new SoftApConfiguration.Builder()
2558                 .setSsid("Test123").build();
2559         enterClientModeActiveState();
2560         mActiveModeWarden.updateSoftApConfiguration(testConfig);
2561         mLooper.dispatchAll();
2562         verify(mSoftApManager, never()).updateConfiguration(any());
2563     }
2564 
2565     @Test
isStaApConcurrencySupported()2566     public void isStaApConcurrencySupported() throws Exception {
2567         when(mWifiNative.isStaApConcurrencySupported()).thenReturn(false);
2568         assertFalse(mActiveModeWarden.isStaApConcurrencySupported());
2569 
2570         when(mWifiNative.isStaApConcurrencySupported()).thenReturn(true);
2571         assertTrue(mActiveModeWarden.isStaApConcurrencySupported());
2572     }
2573 
2574     @Test
isStaStaConcurrencySupported()2575     public void isStaStaConcurrencySupported() throws Exception {
2576         // STA + STA not supported.
2577         when(mWifiNative.isStaStaConcurrencySupported()).thenReturn(false);
2578         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForLocalOnlyConnections());
2579         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForMbb());
2580         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForRestrictedConnections());
2581 
2582         // STA + STA supported, but no use-cases enabled.
2583         when(mWifiNative.isStaStaConcurrencySupported()).thenReturn(true);
2584         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForLocalOnlyConnections());
2585         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForMbb());
2586         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForRestrictedConnections());
2587 
2588         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
2589                 .thenReturn(true);
2590         assertTrue(mActiveModeWarden.isStaStaConcurrencySupportedForLocalOnlyConnections());
2591 
2592         when(mResources.getBoolean(
2593                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
2594                 .thenReturn(true);
2595         assertTrue(mActiveModeWarden.isStaStaConcurrencySupportedForMbb());
2596 
2597         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
2598                 .thenReturn(true);
2599         assertTrue(mActiveModeWarden.isStaStaConcurrencySupportedForRestrictedConnections());
2600     }
2601 
requestAdditionalClientModeManager( ClientConnectivityRole additionaClientModeManagerRole, ConcreteClientModeManager additionalClientModeManager, ExternalClientModeManagerRequestListener externalRequestListener, String ssid, String bssid)2602     private Listener<ConcreteClientModeManager> requestAdditionalClientModeManager(
2603             ClientConnectivityRole additionaClientModeManagerRole,
2604             ConcreteClientModeManager additionalClientModeManager,
2605             ExternalClientModeManagerRequestListener externalRequestListener,
2606             String ssid, String bssid)
2607             throws Exception {
2608         enterClientModeActiveState();
2609 
2610         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
2611                 new Mutable<>();
2612 
2613         // Connected to ssid1/bssid1
2614         WifiConfiguration config1 = new WifiConfiguration();
2615         config1.SSID = TEST_SSID_1;
2616         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
2617         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
2618 
2619         doAnswer((invocation) -> {
2620             Object[] args = invocation.getArguments();
2621             additionalClientListener.value =
2622                     (Listener<ConcreteClientModeManager>) args[0];
2623             return additionalClientModeManager;
2624         }).when(mWifiInjector).makeClientModeManager(
2625                 any(Listener.class), any(), any(), anyBoolean());
2626         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
2627         when(additionalClientModeManager.getRole()).thenReturn(additionaClientModeManagerRole);
2628 
2629         // request for ssid2/bssid2
2630         if (additionaClientModeManagerRole == ROLE_CLIENT_LOCAL_ONLY) {
2631             mActiveModeWarden.requestLocalOnlyClientModeManager(
2632                     externalRequestListener, TEST_WORKSOURCE, ssid, bssid);
2633         } else if (additionaClientModeManagerRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
2634             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
2635                     externalRequestListener, TEST_WORKSOURCE, ssid, bssid);
2636         } else if (additionaClientModeManagerRole == ROLE_CLIENT_SECONDARY_TRANSIENT) {
2637             mActiveModeWarden.requestSecondaryTransientClientModeManager(
2638                     externalRequestListener, TEST_WORKSOURCE, ssid, bssid);
2639         }
2640         mLooper.dispatchAll();
2641         verify(mWifiInjector)
2642                 .makeClientModeManager(any(), eq(TEST_WORKSOURCE),
2643                         eq(additionaClientModeManagerRole), anyBoolean());
2644         additionalClientListener.value.onStarted(additionalClientModeManager);
2645         mLooper.dispatchAll();
2646         // capture last use case set
2647         ArgumentCaptor<Integer> useCaseCaptor = ArgumentCaptor.forClass(Integer.class);
2648         verify(mWifiNative, atLeastOnce()).setMultiStaUseCase(useCaseCaptor.capture());
2649         int lastUseCaseSet = useCaseCaptor.getValue().intValue();
2650         // Ensure the hardware is correctly configured for STA + STA
2651         if (additionaClientModeManagerRole == ROLE_CLIENT_LOCAL_ONLY
2652                 || additionaClientModeManagerRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
2653             assertEquals(WifiNative.DUAL_STA_NON_TRANSIENT_UNBIASED, lastUseCaseSet);
2654         } else if (additionaClientModeManagerRole == ROLE_CLIENT_SECONDARY_TRANSIENT) {
2655             assertEquals(WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY, lastUseCaseSet);
2656         }
2657 
2658         // verify last set of primary connection is for WIFI_IFACE_NAME
2659         ArgumentCaptor<String> ifaceNameCaptor = ArgumentCaptor.forClass(String.class);
2660         verify(mWifiNative, atLeastOnce()).setMultiStaPrimaryConnection(ifaceNameCaptor.capture());
2661         assertEquals(WIFI_IFACE_NAME, ifaceNameCaptor.getValue());
2662 
2663         // Returns the new local only client mode manager.
2664         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
2665                 ArgumentCaptor.forClass(ClientModeManager.class);
2666         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
2667         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
2668         // the additional CMM never became primary
2669         verify(mPrimaryChangedCallback, never()).onChange(any(), eq(additionalClientModeManager));
2670 
2671         return additionalClientListener.value;
2672     }
2673 
requestRemoveAdditionalClientModeManager( ClientConnectivityRole role)2674     private void requestRemoveAdditionalClientModeManager(
2675             ClientConnectivityRole role) throws Exception {
2676         ConcreteClientModeManager additionalClientModeManager =
2677                 mock(ConcreteClientModeManager.class);
2678         ExternalClientModeManagerRequestListener externalRequestListener = mock(
2679                 ExternalClientModeManagerRequestListener.class);
2680         Listener<ConcreteClientModeManager> additionalClientListener =
2681                 requestAdditionalClientModeManager(role, additionalClientModeManager,
2682                         externalRequestListener, TEST_SSID_2, TEST_BSSID_2);
2683 
2684         mActiveModeWarden.removeClientModeManager(additionalClientModeManager);
2685         mLooper.dispatchAll();
2686         verify(additionalClientModeManager).stop();
2687         additionalClientListener.onStopped(additionalClientModeManager);
2688         mLooper.dispatchAll();
2689         verify(mModeChangeCallback).onActiveModeManagerRemoved(additionalClientModeManager);
2690         // the additional CMM still never became primary
2691         verify(mPrimaryChangedCallback, never()).onChange(any(), eq(additionalClientModeManager));
2692     }
2693 
requestRemoveAdditionalClientModeManagerWhenNotAllowed( ClientConnectivityRole role)2694     private void requestRemoveAdditionalClientModeManagerWhenNotAllowed(
2695             ClientConnectivityRole role) throws Exception {
2696         enterClientModeActiveState();
2697 
2698         // Connected to ssid1/bssid1
2699         WifiConfiguration config1 = new WifiConfiguration();
2700         config1.SSID = TEST_SSID_1;
2701         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
2702         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
2703 
2704         ConcreteClientModeManager additionalClientModeManager =
2705                 mock(ConcreteClientModeManager.class);
2706         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
2707                 new Mutable<>();
2708         doAnswer((invocation) -> {
2709             Object[] args = invocation.getArguments();
2710             additionalClientListener.value =
2711                     (Listener<ConcreteClientModeManager>) args[0];
2712             return additionalClientModeManager;
2713         }).when(mWifiInjector).makeClientModeManager(
2714                 any(Listener.class), any(), any(), anyBoolean());
2715         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
2716         when(additionalClientModeManager.getRole()).thenReturn(role);
2717 
2718         ExternalClientModeManagerRequestListener externalRequestListener = mock(
2719                 ExternalClientModeManagerRequestListener.class);
2720         // request for ssid2/bssid2
2721         if (role == ROLE_CLIENT_LOCAL_ONLY) {
2722             mActiveModeWarden.requestLocalOnlyClientModeManager(
2723                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
2724         } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
2725             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
2726                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
2727         } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
2728             mActiveModeWarden.requestSecondaryTransientClientModeManager(
2729                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
2730         }
2731         mLooper.dispatchAll();
2732         verifyNoMoreInteractions(additionalClientModeManager);
2733         // Returns the existing primary client mode manager.
2734         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
2735                 ArgumentCaptor.forClass(ClientModeManager.class);
2736         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
2737         assertEquals(mClientModeManager, requestedClientModeManager.getValue());
2738 
2739         mActiveModeWarden.removeClientModeManager(requestedClientModeManager.getValue());
2740         mLooper.dispatchAll();
2741         verifyNoMoreInteractions(additionalClientModeManager);
2742     }
2743 
requestAdditionalClientModeManagerWhenWifiIsOff( ClientConnectivityRole role)2744     private void requestAdditionalClientModeManagerWhenWifiIsOff(
2745             ClientConnectivityRole role) throws Exception {
2746         ExternalClientModeManagerRequestListener externalRequestListener = mock(
2747                 ExternalClientModeManagerRequestListener.class);
2748         if (role == ROLE_CLIENT_LOCAL_ONLY) {
2749             mActiveModeWarden.requestLocalOnlyClientModeManager(
2750                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
2751         } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
2752             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
2753                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
2754         } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
2755             mActiveModeWarden.requestSecondaryTransientClientModeManager(
2756                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
2757         }
2758         mLooper.dispatchAll();
2759 
2760         verify(externalRequestListener).onAnswer(null);
2761     }
2762 
requestAdditionalClientModeManagerWhenAlreadyPresent( ClientConnectivityRole role)2763     public void requestAdditionalClientModeManagerWhenAlreadyPresent(
2764             ClientConnectivityRole role) throws Exception {
2765         ConcreteClientModeManager additionalClientModeManager =
2766                 mock(ConcreteClientModeManager.class);
2767         ExternalClientModeManagerRequestListener externalRequestListener = mock(
2768                 ExternalClientModeManagerRequestListener.class);
2769         requestAdditionalClientModeManager(role, additionalClientModeManager,
2770                 externalRequestListener, TEST_SSID_2, TEST_BSSID_2);
2771 
2772         // set additional CMM connected to ssid2/bssid2
2773         WifiConfiguration config2 = new WifiConfiguration();
2774         config2.SSID = TEST_SSID_2;
2775         when(additionalClientModeManager.getConnectedWifiConfiguration()).thenReturn(config2);
2776         when(additionalClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_2);
2777 
2778         // request for ssid3/bssid3
2779         // request for one more CMM (returns the existing one).
2780         if (role == ROLE_CLIENT_LOCAL_ONLY) {
2781             mActiveModeWarden.requestLocalOnlyClientModeManager(
2782                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_3, TEST_BSSID_3);
2783         } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
2784             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
2785                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_3, TEST_BSSID_3);
2786         } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
2787             mActiveModeWarden.requestSecondaryTransientClientModeManager(
2788                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_3, TEST_BSSID_3);
2789         }
2790         mLooper.dispatchAll();
2791 
2792         // Don't make another client mode manager.
2793         verify(mWifiInjector, times(1))
2794                 .makeClientModeManager(any(), any(), eq(role), anyBoolean());
2795         // Returns the existing client mode manager.
2796         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
2797                 ArgumentCaptor.forClass(ClientModeManager.class);
2798         verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
2799         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
2800     }
2801 
requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid( ClientConnectivityRole role)2802     private void requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid(
2803             ClientConnectivityRole role) throws Exception {
2804         enterClientModeActiveState();
2805 
2806         // Connected to ssid1/bssid1
2807         WifiConfiguration config1 = new WifiConfiguration();
2808         config1.SSID = TEST_SSID_1;
2809         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
2810         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
2811 
2812         ConcreteClientModeManager additionalClientModeManager =
2813                 mock(ConcreteClientModeManager.class);
2814         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
2815                 new Mutable<>();
2816         doAnswer((invocation) -> {
2817             Object[] args = invocation.getArguments();
2818             additionalClientListener.value =
2819                     (Listener<ConcreteClientModeManager>) args[0];
2820             return additionalClientModeManager;
2821         }).when(mWifiInjector).makeClientModeManager(
2822                 any(Listener.class), any(), any(), anyBoolean());
2823         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
2824         when(additionalClientModeManager.getRole()).thenReturn(role);
2825 
2826         ExternalClientModeManagerRequestListener externalRequestListener = mock(
2827                 ExternalClientModeManagerRequestListener.class);
2828         // request for same ssid1/bssid1
2829         if (role == ROLE_CLIENT_LOCAL_ONLY) {
2830             mActiveModeWarden.requestLocalOnlyClientModeManager(
2831                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
2832         } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
2833             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
2834                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
2835         } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
2836             mActiveModeWarden.requestSecondaryTransientClientModeManager(
2837                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
2838         }
2839         mLooper.dispatchAll();
2840         verifyNoMoreInteractions(additionalClientModeManager);
2841         // Returns the existing primary client mode manager.
2842         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
2843                 ArgumentCaptor.forClass(ClientModeManager.class);
2844         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
2845         assertEquals(mClientModeManager, requestedClientModeManager.getValue());
2846     }
2847 
2848     @Test
requestRemoveLocalOnlyClientModeManager()2849     public void requestRemoveLocalOnlyClientModeManager() throws Exception {
2850         // Ensure that we can create more client ifaces.
2851         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2852         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
2853                 .thenReturn(true);
2854         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2855                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
2856 
2857         requestRemoveAdditionalClientModeManager(ROLE_CLIENT_LOCAL_ONLY);
2858     }
2859 
2860     @Test
requestRemoveLocalOnlyClientModeManagerWhenStaStaNotSupported()2861     public void requestRemoveLocalOnlyClientModeManagerWhenStaStaNotSupported() throws Exception {
2862         // Ensure that we cannot create more client ifaces.
2863         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
2864         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2865                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
2866         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY);
2867     }
2868 
2869     @Test
requestRemoveLocalOnlyClientModeManagerWhenFeatureDisabled()2870     public void requestRemoveLocalOnlyClientModeManagerWhenFeatureDisabled() throws Exception {
2871         // Ensure that we can create more client ifaces.
2872         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2873         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
2874                 .thenReturn(false);
2875         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2876                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
2877         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY);
2878     }
2879 
2880     @Test
requestLocalOnlyClientModeManagerWhenWifiIsOff()2881     public void requestLocalOnlyClientModeManagerWhenWifiIsOff() throws Exception {
2882         // Ensure that we can create more client ifaces.
2883         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2884         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2885                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
2886 
2887         requestAdditionalClientModeManagerWhenWifiIsOff(ROLE_CLIENT_LOCAL_ONLY);
2888     }
2889 
2890     @Test
requestLocalOnlyClientModeManagerWhenAlreadyPresent()2891     public void requestLocalOnlyClientModeManagerWhenAlreadyPresent() throws Exception {
2892         // Ensure that we can create more client ifaces.
2893         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2894         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
2895                 .thenReturn(true);
2896         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2897                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
2898 
2899         requestAdditionalClientModeManagerWhenAlreadyPresent(ROLE_CLIENT_LOCAL_ONLY);
2900     }
2901 
2902     @Test
requestLocalOnlyClientModeManagerWhenConnectingToPrimaryBssid()2903     public void requestLocalOnlyClientModeManagerWhenConnectingToPrimaryBssid() throws Exception {
2904         // Ensure that we can create more client ifaces.
2905         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2906         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
2907                 .thenReturn(true);
2908         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2909                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
2910 
2911         requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid(ROLE_CLIENT_LOCAL_ONLY);
2912     }
2913 
2914     @Test
requestRemoveLocalOnlyClientModeManagerWhenNotSystemAppAndTargetSdkLessThanS()2915     public void requestRemoveLocalOnlyClientModeManagerWhenNotSystemAppAndTargetSdkLessThanS()
2916             throws Exception {
2917         // Ensure that we can create more client ifaces.
2918         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2919         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
2920                 .thenReturn(true);
2921         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(false);
2922         when(mWifiPermissionsUtil.isTargetSdkLessThan(
2923                 TEST_PACKAGE, Build.VERSION_CODES.S, TEST_UID))
2924                 .thenReturn(true);
2925         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2926                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
2927         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY);
2928     }
2929 
2930     @Test
requestRemoveLocalOnlyClientModeManagerWhenNotSystemAppAndTargetSdkEqualToS()2931     public void requestRemoveLocalOnlyClientModeManagerWhenNotSystemAppAndTargetSdkEqualToS()
2932             throws Exception {
2933         // Ensure that we can create more client ifaces.
2934         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2935         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
2936                 .thenReturn(true);
2937         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(false);
2938         when(mWifiPermissionsUtil.isTargetSdkLessThan(
2939                 TEST_PACKAGE, Build.VERSION_CODES.S, TEST_UID))
2940                 .thenReturn(false);
2941         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2942                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
2943         requestRemoveAdditionalClientModeManager(ROLE_CLIENT_LOCAL_ONLY);
2944     }
2945 
2946     @Test
requestRemoveSecondaryLongLivedClientModeManager()2947     public void requestRemoveSecondaryLongLivedClientModeManager() throws Exception {
2948         // Ensure that we can create more client ifaces.
2949         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2950         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
2951                 .thenReturn(true);
2952         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2953                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED));
2954 
2955         requestRemoveAdditionalClientModeManager(ROLE_CLIENT_SECONDARY_LONG_LIVED);
2956     }
2957 
2958     @Test
requestRemoveSecondaryLongLivedClientModeManagerWhenStaStaNotSupported()2959     public void requestRemoveSecondaryLongLivedClientModeManagerWhenStaStaNotSupported()
2960             throws Exception {
2961         // Ensure that we cannot create more client ifaces.
2962         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
2963         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2964                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED));
2965         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_LONG_LIVED);
2966     }
2967 
2968     @Test
requestRemoveSecondaryLongLivedClientModeManagerWhenFeatureDisabled()2969     public void requestRemoveSecondaryLongLivedClientModeManagerWhenFeatureDisabled()
2970             throws Exception {
2971         // Ensure that we can create more client ifaces.
2972         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2973         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
2974                 .thenReturn(false);
2975         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2976                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED));
2977         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_LONG_LIVED);
2978     }
2979 
2980     @Test
requestSecondaryLongLivedClientModeManagerWhenWifiIsOff()2981     public void requestSecondaryLongLivedClientModeManagerWhenWifiIsOff() throws Exception {
2982         // Ensure that we can create more client ifaces.
2983         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2984         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
2985                 .thenReturn(true);
2986         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2987                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED));
2988 
2989         requestAdditionalClientModeManagerWhenWifiIsOff(ROLE_CLIENT_SECONDARY_LONG_LIVED);
2990     }
2991 
2992     @Test
requestSecondaryLongLivedClientModeManagerWhenAlreadyPresent()2993     public void requestSecondaryLongLivedClientModeManagerWhenAlreadyPresent() throws Exception {
2994         // Ensure that we can create more client ifaces.
2995         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
2996         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
2997                 .thenReturn(true);
2998         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
2999                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED));
3000 
3001         requestAdditionalClientModeManagerWhenAlreadyPresent(ROLE_CLIENT_SECONDARY_LONG_LIVED);
3002     }
3003 
3004     @Test
requestSecondaryLongLivedClientModeManagerWhenConnectingToPrimaryBssid()3005     public void requestSecondaryLongLivedClientModeManagerWhenConnectingToPrimaryBssid()
3006             throws Exception {
3007         // Ensure that we can create more client ifaces.
3008         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3009         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
3010                 .thenReturn(true);
3011         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3012                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED));
3013 
3014         requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid(
3015                 ROLE_CLIENT_SECONDARY_LONG_LIVED);
3016     }
3017 
3018     @Test
requestRemoveSecondaryTransientClientModeManager()3019     public void requestRemoveSecondaryTransientClientModeManager() throws Exception {
3020         // Ensure that we can create more client ifaces.
3021         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3022         when(mResources.getBoolean(
3023                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3024                 .thenReturn(true);
3025         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3026                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3027 
3028         requestRemoveAdditionalClientModeManager(ROLE_CLIENT_SECONDARY_TRANSIENT);
3029     }
3030 
3031     @Test
requestRemoveSecondaryTransientClientModeManagerWhenStaStaNotSupported()3032     public void requestRemoveSecondaryTransientClientModeManagerWhenStaStaNotSupported()
3033             throws Exception {
3034         // Ensure that we cannot create more client ifaces.
3035         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
3036         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3037                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3038         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_TRANSIENT);
3039     }
3040 
3041     @Test
requestRemoveSecondaryTransientClientModeManagerWhenFeatureDisabled()3042     public void requestRemoveSecondaryTransientClientModeManagerWhenFeatureDisabled()
3043             throws Exception {
3044         // Ensure that we can create more client ifaces.
3045         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3046         when(mResources.getBoolean(
3047                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3048                 .thenReturn(false);
3049         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3050                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3051         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_TRANSIENT);
3052     }
3053 
3054     @Test
requestSecondaryTransientClientModeManagerWhenWifiIsOff()3055     public void requestSecondaryTransientClientModeManagerWhenWifiIsOff() throws Exception {
3056         // Ensure that we can create more client ifaces.
3057         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3058         when(mResources.getBoolean(
3059                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3060                 .thenReturn(true);
3061         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3062                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3063 
3064         requestAdditionalClientModeManagerWhenWifiIsOff(ROLE_CLIENT_SECONDARY_TRANSIENT);
3065     }
3066 
3067     @Test
requestSecondaryTransientClientModeManagerWhenAlreadyPresent()3068     public void requestSecondaryTransientClientModeManagerWhenAlreadyPresent() throws Exception {
3069         // Ensure that we can create more client ifaces.
3070         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3071         when(mResources.getBoolean(
3072                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3073                 .thenReturn(true);
3074         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3075                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3076 
3077         requestAdditionalClientModeManagerWhenAlreadyPresent(ROLE_CLIENT_SECONDARY_TRANSIENT);
3078     }
3079 
3080     @Test
requestSecondaryTransientClientModeManagerWhenConnectingToPrimaryBssid()3081     public void requestSecondaryTransientClientModeManagerWhenConnectingToPrimaryBssid()
3082             throws Exception {
3083         // Ensure that we can create more client ifaces.
3084         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3085         when(mResources.getBoolean(
3086                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3087                 .thenReturn(true);
3088         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3089                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3090 
3091         requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid(
3092                 ROLE_CLIENT_SECONDARY_TRANSIENT);
3093     }
3094 
3095     @Test
requestHighPrioSecondaryTransientClientModeManagerWhenConnectedToLocalOnlyBssid()3096     public void requestHighPrioSecondaryTransientClientModeManagerWhenConnectedToLocalOnlyBssid()
3097             throws Exception {
3098         // Ensure that we can create more client ifaces.
3099         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3100         when(mResources.getBoolean(
3101                 R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3102                 .thenReturn(true);
3103         when(mResources.getBoolean(
3104                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3105                 .thenReturn(true);
3106         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3107                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
3108         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3109                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3110 
3111         enterClientModeActiveState();
3112 
3113         // Primary Connected to ssid1/bssid1
3114         WifiConfiguration config1 = new WifiConfiguration();
3115         config1.SSID = TEST_SSID_1;
3116         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
3117         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
3118 
3119         ConcreteClientModeManager additionalClientModeManager =
3120                 mock(ConcreteClientModeManager.class);
3121         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener1 =
3122                 new Mutable<>();
3123         doAnswer((invocation) -> {
3124             Object[] args = invocation.getArguments();
3125             additionalClientListener1.value =
3126                     (Listener<ConcreteClientModeManager>) args[0];
3127             return additionalClientModeManager;
3128         }).when(mWifiInjector).makeClientModeManager(
3129                 any(Listener.class), any(), eq(ROLE_CLIENT_LOCAL_ONLY),
3130                 anyBoolean());
3131         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
3132 
3133         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3134                 ExternalClientModeManagerRequestListener.class);
3135         // request for ssid2/bssid2
3136         mActiveModeWarden.requestLocalOnlyClientModeManager(
3137                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3138         mLooper.dispatchAll();
3139         verify(mWifiInjector).makeClientModeManager(
3140                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_LOCAL_ONLY), anyBoolean());
3141         additionalClientListener1.value.onStarted(additionalClientModeManager);
3142         mLooper.dispatchAll();
3143         // Returns the new client mode manager.
3144         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3145                 ArgumentCaptor.forClass(ClientModeManager.class);
3146         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3147         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3148 
3149         // set additional CMM connected to ssid2/bssid2
3150         WifiConfiguration config2 = new WifiConfiguration();
3151         config2.SSID = TEST_SSID_2;
3152         when(additionalClientModeManager.getConnectedWifiConfiguration()).thenReturn(config2);
3153         when(additionalClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_2);
3154 
3155         // request for same ssid2/bssid2 for a different role.
3156         // request for one more CMM (should return the existing local only one).
3157         mActiveModeWarden.requestSecondaryTransientClientModeManager(
3158                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3159         mLooper.dispatchAll();
3160 
3161         // Don't make another client mode manager, but should switch role of existing client mode
3162         // manager.
3163         verify(mWifiInjector, never())
3164                 .makeClientModeManager(any(), any(), eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3165                         anyBoolean());
3166         ArgumentCaptor<Listener<ConcreteClientModeManager>>
3167                 additionalClientListener2 = ArgumentCaptor.forClass(
3168                         Listener.class);
3169         verify(additionalClientModeManager).setRole(eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3170                 eq(TEST_WORKSOURCE), additionalClientListener2.capture());
3171 
3172         // Simulate completion of role switch.
3173         additionalClientListener2.getValue().onRoleChanged(additionalClientModeManager);
3174 
3175         // Returns the existing client mode manager.
3176         verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
3177         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3178     }
3179 
3180     @Test
requestLowPrioSecondaryTransientClientModeManagerWhenConnectedToLocalOnlyBssid()3181     public void requestLowPrioSecondaryTransientClientModeManagerWhenConnectedToLocalOnlyBssid()
3182             throws Exception {
3183         // Ensure that we can create more client ifaces.
3184         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3185         when(mResources.getBoolean(
3186                 R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3187                 .thenReturn(true);
3188         when(mResources.getBoolean(
3189                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3190                 .thenReturn(true);
3191         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3192                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY));
3193         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3194                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3195 
3196         enterClientModeActiveState();
3197 
3198         // Primary Connected to ssid1/bssid1
3199         WifiConfiguration config1 = new WifiConfiguration();
3200         config1.SSID = TEST_SSID_1;
3201         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
3202         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
3203 
3204         ConcreteClientModeManager additionalClientModeManager =
3205                 mock(ConcreteClientModeManager.class);
3206         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener1 =
3207                 new Mutable<>();
3208         doAnswer((invocation) -> {
3209             Object[] args = invocation.getArguments();
3210             additionalClientListener1.value =
3211                     (Listener<ConcreteClientModeManager>) args[0];
3212             return additionalClientModeManager;
3213         }).when(mWifiInjector).makeClientModeManager(
3214                 any(Listener.class), any(), eq(ROLE_CLIENT_LOCAL_ONLY),
3215                 anyBoolean());
3216         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
3217 
3218         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3219                 ExternalClientModeManagerRequestListener.class);
3220         // request for ssid2/bssid2
3221         mActiveModeWarden.requestLocalOnlyClientModeManager(
3222                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3223         mLooper.dispatchAll();
3224         verify(mWifiInjector).makeClientModeManager(
3225                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_LOCAL_ONLY), anyBoolean());
3226         additionalClientListener1.value.onStarted(additionalClientModeManager);
3227         mLooper.dispatchAll();
3228         // Returns the new client mode manager.
3229         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3230                 ArgumentCaptor.forClass(ClientModeManager.class);
3231         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3232         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3233 
3234         // set additional CMM connected to ssid2/bssid2
3235         WifiConfiguration config2 = new WifiConfiguration();
3236         config2.SSID = TEST_SSID_2;
3237         when(additionalClientModeManager.getConnectedWifiConfiguration()).thenReturn(config2);
3238         when(additionalClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_2);
3239 
3240         // Now, deny the creation of STA for the new request
3241         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
3242 
3243         // request for same ssid2/bssid2 for a different role.
3244         // request for one more CMM (should return null).
3245         mActiveModeWarden.requestSecondaryTransientClientModeManager(
3246                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3247         mLooper.dispatchAll();
3248 
3249         // Don't make another client mode manager or change role
3250         verify(mWifiInjector, never())
3251                 .makeClientModeManager(any(), any(), eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3252                         anyBoolean());
3253         verify(additionalClientModeManager, never()).setRole(eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3254                 eq(TEST_WORKSOURCE), any());
3255 
3256         // Ensure the request is rejected.
3257         verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
3258         assertNull(requestedClientModeManager.getValue());
3259     }
3260 
3261     @Test
requestSecondaryTransientClientModeManagerWhenDppInProgress()3262     public void requestSecondaryTransientClientModeManagerWhenDppInProgress()
3263             throws Exception {
3264         // Ensure that we can create more client ifaces.
3265         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3266         when(mResources.getBoolean(
3267                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3268                 .thenReturn(true);
3269         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3270                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3271 
3272         // Create primary STA.
3273         enterClientModeActiveState();
3274 
3275         // Start DPP session
3276         when(mDppManager.isSessionInProgress()).thenReturn(true);
3277 
3278         // request secondary transient CMM creation.
3279         ConcreteClientModeManager additionalClientModeManager =
3280                 mock(ConcreteClientModeManager.class);
3281         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
3282                 new Mutable<>();
3283         doAnswer((invocation) -> {
3284             Object[] args = invocation.getArguments();
3285             additionalClientListener.value =
3286                     (Listener<ConcreteClientModeManager>) args[0];
3287             return additionalClientModeManager;
3288         }).when(mWifiInjector).makeClientModeManager(
3289                 any(Listener.class), any(), eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3290                 anyBoolean());
3291         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
3292 
3293         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3294                 ExternalClientModeManagerRequestListener.class);
3295         mActiveModeWarden.requestSecondaryTransientClientModeManager(
3296                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3297         mLooper.dispatchAll();
3298 
3299         // verify that we did not create a secondary CMM.
3300         verifyNoMoreInteractions(additionalClientModeManager);
3301         // Returns the existing primary client mode manager.
3302         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3303                 ArgumentCaptor.forClass(ClientModeManager.class);
3304         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3305         assertEquals(mClientModeManager, requestedClientModeManager.getValue());
3306 
3307         // Stop ongoing DPP session.
3308         when(mDppManager.isSessionInProgress()).thenReturn(false);
3309 
3310         // request secondary transient CMM creation again, now it should be allowed.
3311         mActiveModeWarden.requestSecondaryTransientClientModeManager(
3312                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3313         mLooper.dispatchAll();
3314         verify(mWifiInjector)
3315                 .makeClientModeManager(any(), eq(TEST_WORKSOURCE),
3316                         eq(ROLE_CLIENT_SECONDARY_TRANSIENT), anyBoolean());
3317         additionalClientListener.value.onStarted(additionalClientModeManager);
3318         mLooper.dispatchAll();
3319         // Returns the new secondary client mode manager.
3320         verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
3321         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3322     }
3323 
3324     @Test
configureHwOnMbbSwitch()3325     public void configureHwOnMbbSwitch()
3326             throws Exception {
3327         // Ensure that we can create more client ifaces.
3328         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3329         when(mResources.getBoolean(
3330                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3331                 .thenReturn(true);
3332         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3333                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3334 
3335         ConcreteClientModeManager additionalClientModeManager =
3336                 mock(ConcreteClientModeManager.class);
3337         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3338                 ExternalClientModeManagerRequestListener.class);
3339         Listener<ConcreteClientModeManager> additionalClientListener =
3340                 requestAdditionalClientModeManager(ROLE_CLIENT_SECONDARY_TRANSIENT,
3341                         additionalClientModeManager, externalRequestListener, TEST_SSID_2,
3342                         TEST_BSSID_2);
3343 
3344         // Now simulate the MBB role switch.
3345         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
3346         mClientListener.onRoleChanged(mClientModeManager);
3347 
3348         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
3349         additionalClientListener.onRoleChanged(additionalClientModeManager);
3350 
3351         // verify last use case set is PREFER_PRIMARY
3352         ArgumentCaptor<Integer> useCaseCaptor = ArgumentCaptor.forClass(Integer.class);
3353         verify(mWifiNative, atLeastOnce()).setMultiStaUseCase(useCaseCaptor.capture());
3354         int lastUseCaseSet = useCaseCaptor.getValue().intValue();
3355         assertEquals(WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY, lastUseCaseSet);
3356 
3357         // verify last set of primary connection is for WIFI_IFACE_NAME_1
3358         ArgumentCaptor<String> ifaceNameCaptor = ArgumentCaptor.forClass(String.class);
3359         verify(mWifiNative, atLeastOnce()).setMultiStaPrimaryConnection(ifaceNameCaptor.capture());
3360         assertEquals(WIFI_IFACE_NAME_1, ifaceNameCaptor.getValue());
3361     }
3362 
3363     @Test
airplaneModeToggleOnDisablesWifi()3364     public void airplaneModeToggleOnDisablesWifi() throws Exception {
3365         enterClientModeActiveState();
3366         assertInEnabledState();
3367 
3368         assertWifiShutDown(() -> {
3369             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
3370             mActiveModeWarden.airplaneModeToggled();
3371             mLooper.dispatchAll();
3372         });
3373 
3374         mClientListener.onStopped(mClientModeManager);
3375         mLooper.dispatchAll();
3376         assertInDisabledState();
3377     }
3378 
3379     @Test
airplaneModeToggleOnDisablesSoftAp()3380     public void airplaneModeToggleOnDisablesSoftAp() throws Exception {
3381         enterSoftApActiveMode();
3382         assertInEnabledState();
3383 
3384         assertWifiShutDown(() -> {
3385             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
3386             mActiveModeWarden.airplaneModeToggled();
3387             mLooper.dispatchAll();
3388         });
3389 
3390         mSoftApListener.onStopped(mSoftApManager);
3391         mLooper.dispatchAll();
3392         assertInDisabledState();
3393     }
3394 
3395     @Test
airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager()3396     public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager()
3397             throws Exception {
3398         enterClientModeActiveState();
3399         assertInEnabledState();
3400 
3401         // APM toggle on
3402         assertWifiShutDown(() -> {
3403             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
3404             mActiveModeWarden.airplaneModeToggled();
3405             mLooper.dispatchAll();
3406         });
3407 
3408 
3409         // APM toggle off before the stop is complete.
3410         assertInEnabledState();
3411         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
3412         mActiveModeWarden.airplaneModeToggled();
3413         mLooper.dispatchAll();
3414 
3415         mClientListener.onStopped(mClientModeManager);
3416         mLooper.dispatchAll();
3417 
3418         verify(mWifiInjector, times(2)).makeClientModeManager(
3419                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
3420 
3421         mClientListener.onStarted(mClientModeManager);
3422         mLooper.dispatchAll();
3423 
3424         // We should be back to enabled state.
3425         assertInEnabledState();
3426     }
3427 
3428     @Test
airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager2()3429     public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager2()
3430             throws Exception {
3431         enterClientModeActiveState();
3432         assertInEnabledState();
3433 
3434         // APM toggle on
3435         assertWifiShutDown(() -> {
3436             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
3437             mActiveModeWarden.airplaneModeToggled();
3438             mLooper.dispatchAll();
3439         });
3440 
3441 
3442         // APM toggle off before the stop is complete.
3443         assertInEnabledState();
3444         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
3445         mActiveModeWarden.airplaneModeToggled();
3446         // This test is identical to
3447         // airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager, except the
3448         // dispatchAll() here is removed. There could be a race between airplaneModeToggled and
3449         // mClientListener.onStopped(). See b/160105640#comment5.
3450 
3451         mClientListener.onStopped(mClientModeManager);
3452         mLooper.dispatchAll();
3453 
3454         verify(mWifiInjector, times(2)).makeClientModeManager(
3455                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
3456 
3457         mClientListener.onStarted(mClientModeManager);
3458         mLooper.dispatchAll();
3459 
3460         // We should be back to enabled state.
3461         assertInEnabledState();
3462     }
3463 
3464     @Test
airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithTwoModeManager()3465     public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithTwoModeManager()
3466             throws Exception {
3467         enterClientModeActiveState();
3468         enterSoftApActiveMode();
3469         assertInEnabledState();
3470 
3471         // APM toggle on
3472         assertWifiShutDown(() -> {
3473             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
3474             mActiveModeWarden.airplaneModeToggled();
3475             mLooper.dispatchAll();
3476         });
3477 
3478 
3479         // APM toggle off before the stop is complete.
3480         assertInEnabledState();
3481         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
3482         mActiveModeWarden.airplaneModeToggled();
3483         mLooper.dispatchAll();
3484 
3485         // AP stopped, should not process APM toggle.
3486         mSoftApListener.onStopped(mSoftApManager);
3487         mLooper.dispatchAll();
3488         verify(mWifiInjector, times(1)).makeClientModeManager(
3489                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
3490 
3491         // STA also stopped, should process APM toggle.
3492         mClientListener.onStopped(mClientModeManager);
3493         mLooper.dispatchAll();
3494         verify(mWifiInjector, times(2)).makeClientModeManager(
3495                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
3496 
3497         mClientListener.onStarted(mClientModeManager);
3498         mLooper.dispatchAll();
3499 
3500         // We should be back to enabled state.
3501         assertInEnabledState();
3502     }
3503 
3504     @Test
propagateVerboseLoggingFlagToClientModeManager()3505     public void propagateVerboseLoggingFlagToClientModeManager() throws Exception {
3506         mActiveModeWarden.enableVerboseLogging(true);
3507         enterClientModeActiveState();
3508         assertInEnabledState();
3509         verify(mWifiInjector).makeClientModeManager(any(), any(), any(), eq(true));
3510 
3511         mActiveModeWarden.enableVerboseLogging(false);
3512         verify(mClientModeManager).enableVerboseLogging(false);
3513     }
3514 
3515     @Test
propagateConnectedWifiScorerToPrimaryClientModeManager()3516     public void propagateConnectedWifiScorerToPrimaryClientModeManager() throws Exception {
3517         IBinder iBinder = mock(IBinder.class);
3518         IWifiConnectedNetworkScorer iScorer = mock(IWifiConnectedNetworkScorer.class);
3519         mActiveModeWarden.setWifiConnectedNetworkScorer(iBinder, iScorer);
3520         verify(iScorer).onSetScoreUpdateObserver(mExternalScoreUpdateObserverProxy);
3521         enterClientModeActiveState();
3522         assertInEnabledState();
3523         verify(mClientModeManager).setWifiConnectedNetworkScorer(iBinder, iScorer);
3524 
3525         mActiveModeWarden.clearWifiConnectedNetworkScorer();
3526         verify(mClientModeManager).clearWifiConnectedNetworkScorer();
3527 
3528         mActiveModeWarden.setWifiConnectedNetworkScorer(iBinder, iScorer);
3529         verify(mClientModeManager, times(2)).setWifiConnectedNetworkScorer(iBinder, iScorer);
3530     }
3531 
3532     @Test
propagateConnectedWifiScorerToPrimaryClientModeManager_enterScanOnlyState()3533     public void propagateConnectedWifiScorerToPrimaryClientModeManager_enterScanOnlyState()
3534             throws Exception {
3535         IBinder iBinder = mock(IBinder.class);
3536         IWifiConnectedNetworkScorer iScorer = mock(IWifiConnectedNetworkScorer.class);
3537         mActiveModeWarden.setWifiConnectedNetworkScorer(iBinder, iScorer);
3538         verify(iScorer).onSetScoreUpdateObserver(mExternalScoreUpdateObserverProxy);
3539         enterClientModeActiveState();
3540         assertInEnabledState();
3541         verify(mClientModeManager).setWifiConnectedNetworkScorer(iBinder, iScorer);
3542 
3543         enterScanOnlyModeActiveState(true);
3544 
3545         verify(mClientModeManager).clearWifiConnectedNetworkScorer();
3546     }
3547 
3548     @Test
handleWifiScorerSetScoreUpdateObserverFailure()3549     public void handleWifiScorerSetScoreUpdateObserverFailure() throws Exception {
3550         IBinder iBinder = mock(IBinder.class);
3551         IWifiConnectedNetworkScorer iScorer = mock(IWifiConnectedNetworkScorer.class);
3552         doThrow(new RemoteException()).when(iScorer).onSetScoreUpdateObserver(any());
3553         mActiveModeWarden.setWifiConnectedNetworkScorer(iBinder, iScorer);
3554         verify(iScorer).onSetScoreUpdateObserver(mExternalScoreUpdateObserverProxy);
3555         enterClientModeActiveState();
3556         assertInEnabledState();
3557         // Ensure we did not propagate the scorer.
3558         verify(mClientModeManager, never()).setWifiConnectedNetworkScorer(iBinder, iScorer);
3559     }
3560 
3561     /** Verify that the primary changed callback is triggered when entering client mode. */
3562     @Test
testAddPrimaryClientModeManager()3563     public void testAddPrimaryClientModeManager() throws Exception {
3564         enterClientModeActiveState();
3565 
3566         verify(mPrimaryChangedCallback).onChange(null, mClientModeManager);
3567     }
3568 
3569     /** Verify the primary changed callback is not triggered when there is no primary. */
3570     @Test
testNoAddPrimaryClientModeManager()3571     public void testNoAddPrimaryClientModeManager() throws Exception {
3572         enterScanOnlyModeActiveState();
3573 
3574         verify(mPrimaryChangedCallback, never()).onChange(any(), any());
3575     }
3576 
3577     /**
3578      * Verify the primary changed callback is triggered when changing the primary from one
3579      * ClientModeManager to another.
3580      */
3581     @Test
testSwitchPrimaryClientModeManager()3582     public void testSwitchPrimaryClientModeManager() throws Exception {
3583         // Ensure that we can create more client ifaces.
3584         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3585         when(mResources.getBoolean(
3586                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3587                 .thenReturn(true);
3588         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3589                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT));
3590 
3591         enterClientModeActiveState();
3592 
3593         verify(mPrimaryChangedCallback).onChange(null, mClientModeManager);
3594 
3595         // Connected to ssid1/bssid1
3596         WifiConfiguration config1 = new WifiConfiguration();
3597         config1.SSID = TEST_SSID_1;
3598         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
3599         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
3600 
3601         ConcreteClientModeManager additionalClientModeManager =
3602                 mock(ConcreteClientModeManager.class);
3603         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
3604                 new Mutable<>();
3605         doAnswer((invocation) -> {
3606             Object[] args = invocation.getArguments();
3607             additionalClientListener.value =
3608                     (Listener<ConcreteClientModeManager>) args[0];
3609             return additionalClientModeManager;
3610         }).when(mWifiInjector).makeClientModeManager(
3611                 any(Listener.class), any(), eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3612                 anyBoolean());
3613         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
3614 
3615         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3616                 ExternalClientModeManagerRequestListener.class);
3617         // request for ssid2/bssid2
3618         mActiveModeWarden.requestSecondaryTransientClientModeManager(
3619                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3620         mLooper.dispatchAll();
3621         verify(mWifiInjector).makeClientModeManager(
3622                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_SECONDARY_TRANSIENT), anyBoolean());
3623         additionalClientListener.value.onStarted(additionalClientModeManager);
3624         mLooper.dispatchAll();
3625         // Returns the new client mode manager.
3626         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3627                 ArgumentCaptor.forClass(ClientModeManager.class);
3628         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3629         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3630 
3631         // primary didn't change yet
3632         verify(mPrimaryChangedCallback, never()).onChange(any(), eq(additionalClientModeManager));
3633 
3634         // change primary
3635         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
3636         mClientListener.onRoleChanged(mClientModeManager);
3637         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
3638         additionalClientListener.value.onRoleChanged(additionalClientModeManager);
3639 
3640         // verify callback triggered
3641         verify(mPrimaryChangedCallback).onChange(mClientModeManager, null);
3642         verify(mPrimaryChangedCallback).onChange(null, additionalClientModeManager);
3643     }
3644 
3645     @Test
testRegisterPrimaryCmmChangedCallbackWhenConnectModeActiveState()3646     public void testRegisterPrimaryCmmChangedCallbackWhenConnectModeActiveState() throws Exception {
3647         enterClientModeActiveState();
3648 
3649         // register a new primary cmm change callback.
3650         ActiveModeWarden.PrimaryClientModeManagerChangedCallback primarCmmCallback = mock(
3651                 ActiveModeWarden.PrimaryClientModeManagerChangedCallback.class);
3652         mActiveModeWarden.registerPrimaryClientModeManagerChangedCallback(primarCmmCallback);
3653         // Ensure we get the callback immediately.
3654         verify(primarCmmCallback).onChange(null, mClientModeManager);
3655     }
3656 
3657     @Test
testGetCmmInRolesWithNullRoleInOneCmm()3658     public void testGetCmmInRolesWithNullRoleInOneCmm() throws Exception {
3659         enterClientModeActiveState();
3660 
3661         // Ensure that we can create more client ifaces.
3662         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3663         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3664                 .thenReturn(true);
3665 
3666         ConcreteClientModeManager additionalClientModeManager =
3667                 mock(ConcreteClientModeManager.class);
3668         when(mWifiInjector.makeClientModeManager(
3669                 any(), any(), any(), anyBoolean())).thenReturn(additionalClientModeManager);
3670 
3671         mActiveModeWarden.requestLocalOnlyClientModeManager(
3672                 mock(ExternalClientModeManagerRequestListener.class),
3673                 TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3674         mLooper.dispatchAll();
3675 
3676         // No role set, should be ignored.
3677         when(additionalClientModeManager.getRole()).thenReturn(null);
3678         assertEquals(1, mActiveModeWarden.getClientModeManagersInRoles(
3679                 ROLE_CLIENT_PRIMARY, ROLE_CLIENT_LOCAL_ONLY).size());
3680 
3681         // Role set, should be included.
3682         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
3683         assertEquals(2, mActiveModeWarden.getClientModeManagersInRoles(
3684                 ROLE_CLIENT_PRIMARY, ROLE_CLIENT_LOCAL_ONLY).size());
3685     }
3686 
3687     /**
3688      * Helper method to enter the EnabledState and set ClientModeManager in ScanOnlyMode during
3689      * emergency scan processing.
3690      */
indicateStartOfEmergencyScan( boolean hasAnyOtherStaToggleEnabled, @Nullable ActiveModeManager.ClientRole expectedRole)3691     private void indicateStartOfEmergencyScan(
3692             boolean hasAnyOtherStaToggleEnabled,
3693             @Nullable ActiveModeManager.ClientRole expectedRole)
3694             throws Exception {
3695         String fromState = mActiveModeWarden.getCurrentMode();
3696         mActiveModeWarden.setEmergencyScanRequestInProgress(true);
3697         mLooper.dispatchAll();
3698 
3699         if (!hasAnyOtherStaToggleEnabled) {
3700             when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SCAN_ONLY);
3701             mClientListener.onStarted(mClientModeManager);
3702             mLooper.dispatchAll();
3703             verify(mWifiInjector).makeClientModeManager(
3704                     any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_SCAN_ONLY), anyBoolean());
3705             verify(mModeChangeCallback).onActiveModeManagerAdded(mClientModeManager);
3706             verify(mScanRequestProxy).enableScanning(true, false);
3707             verify(mBatteryStats).reportWifiOn();
3708             verify(mBatteryStats).reportWifiState(
3709                     BatteryStatsManager.WIFI_STATE_OFF_SCANNING, null);
3710         } else {
3711             verify(mClientModeManager).setRole(eq(expectedRole), any());
3712             verify(mClientModeManager, never()).stop();
3713             assertEquals(fromState, mActiveModeWarden.getCurrentMode());
3714         }
3715         assertInEnabledState();
3716     }
3717 
indicateEndOfEmergencyScan( boolean hasAnyOtherStaToggleEnabled, @Nullable ActiveModeManager.ClientRole expectedRole)3718     private void indicateEndOfEmergencyScan(
3719             boolean hasAnyOtherStaToggleEnabled,
3720             @Nullable ActiveModeManager.ClientRole expectedRole) {
3721         String fromState = mActiveModeWarden.getCurrentMode();
3722         mActiveModeWarden.setEmergencyScanRequestInProgress(false);
3723         mLooper.dispatchAll();
3724         if (!hasAnyOtherStaToggleEnabled) {
3725             mClientListener.onStopped(mClientModeManager);
3726             mLooper.dispatchAll();
3727             verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
3728             verify(mScanRequestProxy).enableScanning(false, false);
3729             assertInDisabledState();
3730         } else {
3731             // Nothing changes.
3732             verify(mClientModeManager).setRole(eq(expectedRole), any());
3733             verify(mClientModeManager, never()).stop();
3734             assertEquals(fromState, mActiveModeWarden.getCurrentMode());
3735         }
3736     }
3737 
3738     @Test
testEmergencyScanWhenWifiDisabled()3739     public void testEmergencyScanWhenWifiDisabled() throws Exception {
3740         // Wifi fully disabled.
3741         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
3742         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
3743         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
3744         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
3745 
3746         indicateStartOfEmergencyScan(false, null);
3747 
3748         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
3749         clearInvocations(mClientModeManager);
3750 
3751         indicateEndOfEmergencyScan(false, null);
3752     }
3753 
3754     @Test
testEmergencyScanWhenWifiEnabled()3755     public void testEmergencyScanWhenWifiEnabled() throws Exception {
3756         // Wifi enabled.
3757         enterClientModeActiveState();
3758 
3759         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3760 
3761         indicateStartOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
3762 
3763         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
3764         clearInvocations(mClientModeManager);
3765 
3766         indicateEndOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
3767     }
3768 
3769     @Test
testEmergencyScanWhenScanOnlyModeEnabled()3770     public void testEmergencyScanWhenScanOnlyModeEnabled() throws Exception {
3771         // Scan only enabled.
3772         enterScanOnlyModeActiveState();
3773 
3774         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3775 
3776         indicateStartOfEmergencyScan(true, ROLE_CLIENT_SCAN_ONLY);
3777 
3778         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
3779         clearInvocations(mClientModeManager);
3780 
3781         indicateEndOfEmergencyScan(true, ROLE_CLIENT_SCAN_ONLY);
3782     }
3783 
3784     @Test
testEmergencyScanWhenEcmOnWithWifiDisableInEcbm()3785     public void testEmergencyScanWhenEcmOnWithWifiDisableInEcbm() throws Exception {
3786         // Wifi enabled.
3787         enterClientModeActiveState();
3788 
3789         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3790 
3791         // Test with WifiDisableInECBM turned on
3792         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
3793 
3794         assertWifiShutDown(() -> {
3795             // test ecm changed
3796             emergencyCallbackModeChanged(true);
3797             mLooper.dispatchAll();
3798             // fully shutdown
3799             mClientListener.onStopped(mClientModeManager);
3800             mLooper.dispatchAll();
3801         });
3802         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3803 
3804         indicateStartOfEmergencyScan(false, null);
3805 
3806         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
3807         clearInvocations(mClientModeManager);
3808 
3809         indicateEndOfEmergencyScan(false, null);
3810     }
3811 
3812     @Test
testEmergencyScanWhenEcmOnWithoutWifiDisableInEcbm()3813     public void testEmergencyScanWhenEcmOnWithoutWifiDisableInEcbm() throws Exception {
3814         // Wifi enabled.
3815         enterClientModeActiveState();
3816 
3817         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3818 
3819         // Test with WifiDisableInECBM turned off
3820         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
3821 
3822         assertEnteredEcmMode(() -> {
3823             // test ecm changed
3824             emergencyCallbackModeChanged(true);
3825             mLooper.dispatchAll();
3826         });
3827 
3828         indicateStartOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
3829 
3830         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
3831         clearInvocations(mClientModeManager);
3832 
3833         indicateEndOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
3834     }
3835 
3836     @Test
testWifiDisableDuringEmergencyScan()3837     public void testWifiDisableDuringEmergencyScan() throws Exception {
3838         // Wifi enabled.
3839         enterClientModeActiveState();
3840 
3841         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3842 
3843         indicateStartOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
3844 
3845         // Toggle off wifi
3846         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
3847         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
3848         mLooper.dispatchAll();
3849 
3850         // Ensure that we switched the role to scan only state because of the emergency scan.
3851         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SCAN_ONLY);
3852         mClientListener.onRoleChanged(mClientModeManager);
3853         mLooper.dispatchAll();
3854         verify(mClientModeManager).setRole(ROLE_CLIENT_SCAN_ONLY, INTERNAL_REQUESTOR_WS);
3855         verify(mClientModeManager, never()).stop();
3856         assertInEnabledState();
3857 
3858         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
3859         clearInvocations(mClientModeManager);
3860 
3861         indicateEndOfEmergencyScan(false, null);
3862     }
3863 
3864     @Test
testScanOnlyModeDisableDuringEmergencyScan()3865     public void testScanOnlyModeDisableDuringEmergencyScan() throws Exception {
3866         // Scan only enabled.
3867         enterScanOnlyModeActiveState();
3868 
3869         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3870 
3871         indicateStartOfEmergencyScan(true, ROLE_CLIENT_SCAN_ONLY);
3872 
3873         // To reset setRole invocation above which is checked below.
3874         clearInvocations(mClientModeManager);
3875 
3876         // Toggle off scan only mode
3877         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
3878         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
3879         mActiveModeWarden.scanAlwaysModeChanged();
3880         mLooper.dispatchAll();
3881 
3882         // Ensure that we remained in scan only state because of the emergency scan.
3883         verify(mClientModeManager).setRole(eq(ROLE_CLIENT_SCAN_ONLY), any());
3884         verify(mClientModeManager, never()).stop();
3885         assertInEnabledState();
3886 
3887         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
3888         clearInvocations(mClientModeManager);
3889 
3890         indicateEndOfEmergencyScan(false, null);
3891     }
3892 
3893     @Test
testEcmOffWithWifiDisabledStateDuringEmergencyScan()3894     public void testEcmOffWithWifiDisabledStateDuringEmergencyScan() throws Exception {
3895         // Wifi enabled.
3896         enterClientModeActiveState();
3897 
3898         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3899 
3900         // Test with WifiDisableInECBM turned on
3901         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
3902 
3903         assertWifiShutDown(() -> {
3904             // test ecm changed
3905             emergencyCallbackModeChanged(true);
3906             mLooper.dispatchAll();
3907             // fully shutdown
3908             mClientListener.onStopped(mClientModeManager);
3909             mLooper.dispatchAll();
3910         });
3911         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3912 
3913         indicateStartOfEmergencyScan(false, null);
3914 
3915         // Now turn off ECM
3916         emergencyCallbackModeChanged(false);
3917         mLooper.dispatchAll();
3918 
3919         // Ensure we turned wifi back on.
3920         verify(mClientModeManager).setRole(eq(ROLE_CLIENT_PRIMARY), any());
3921         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
3922         mClientListener.onRoleChanged(mClientModeManager);
3923         verify(mScanRequestProxy).enableScanning(true, true);
3924         assertInEnabledState();
3925 
3926         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
3927         clearInvocations(mClientModeManager);
3928 
3929         indicateEndOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
3930     }
3931 
3932     @Test
testEcmOffWithoutWifiDisabledStateDuringEmergencyScan()3933     public void testEcmOffWithoutWifiDisabledStateDuringEmergencyScan() throws Exception {
3934         // Wifi enabled.
3935         enterClientModeActiveState();
3936 
3937         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
3938 
3939         // Test with WifiDisableInECBM turned off
3940         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
3941 
3942         assertEnteredEcmMode(() -> {
3943             // test ecm changed
3944             emergencyCallbackModeChanged(true);
3945             mLooper.dispatchAll();
3946         });
3947 
3948         // Now turn off ECM
3949         emergencyCallbackModeChanged(false);
3950         mLooper.dispatchAll();
3951 
3952         // Ensure that we remained in connected state.
3953         verify(mClientModeManager).setRole(eq(ROLE_CLIENT_PRIMARY), any());
3954         verify(mClientModeManager, never()).stop();
3955         assertInEnabledState();
3956 
3957         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
3958         clearInvocations(mClientModeManager);
3959 
3960         indicateEndOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
3961     }
3962 }
3963