• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
20 
21 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY;
22 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY;
23 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SCAN_ONLY;
24 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED;
25 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT;
26 import static com.android.server.wifi.ActiveModeManager.ROLE_SOFTAP_LOCAL_ONLY;
27 import static com.android.server.wifi.ActiveModeManager.ROLE_SOFTAP_TETHERED;
28 import static com.android.server.wifi.ActiveModeWarden.INTERNAL_REQUESTOR_WS;
29 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_NATIVE_SUPPORTED_STA_BANDS;
30 
31 import static com.google.common.truth.Truth.assertThat;
32 import static com.google.common.truth.Truth.assertWithMessage;
33 
34 import static org.junit.Assert.assertEquals;
35 import static org.junit.Assert.assertFalse;
36 import static org.junit.Assert.assertNull;
37 import static org.junit.Assert.assertTrue;
38 import static org.junit.Assume.assumeTrue;
39 import static org.mockito.ArgumentMatchers.anyBoolean;
40 import static org.mockito.ArgumentMatchers.argThat;
41 import static org.mockito.Mockito.any;
42 import static org.mockito.Mockito.anyInt;
43 import static org.mockito.Mockito.anyString;
44 import static org.mockito.Mockito.atLeastOnce;
45 import static org.mockito.Mockito.clearInvocations;
46 import static org.mockito.Mockito.doAnswer;
47 import static org.mockito.Mockito.doThrow;
48 import static org.mockito.Mockito.eq;
49 import static org.mockito.Mockito.inOrder;
50 import static org.mockito.Mockito.mock;
51 import static org.mockito.Mockito.mockingDetails;
52 import static org.mockito.Mockito.never;
53 import static org.mockito.Mockito.reset;
54 import static org.mockito.Mockito.times;
55 import static org.mockito.Mockito.verify;
56 import static org.mockito.Mockito.verifyNoMoreInteractions;
57 import static org.mockito.Mockito.verifyZeroInteractions;
58 import static org.mockito.Mockito.when;
59 
60 import android.annotation.Nullable;
61 import android.content.BroadcastReceiver;
62 import android.content.Context;
63 import android.content.Intent;
64 import android.content.pm.PackageManager;
65 import android.content.res.Resources;
66 import android.location.LocationManager;
67 import android.net.MacAddress;
68 import android.net.Network;
69 import android.net.wifi.ISubsystemRestartCallback;
70 import android.net.wifi.IWifiConnectedNetworkScorer;
71 import android.net.wifi.IWifiNetworkStateChangedListener;
72 import android.net.wifi.SoftApCapability;
73 import android.net.wifi.SoftApConfiguration;
74 import android.net.wifi.SoftApConfiguration.Builder;
75 import android.net.wifi.SoftApInfo;
76 import android.net.wifi.WifiClient;
77 import android.net.wifi.WifiConfiguration;
78 import android.net.wifi.WifiManager;
79 import android.net.wifi.WifiScanner;
80 import android.os.BatteryStatsManager;
81 import android.os.Build;
82 import android.os.IBinder;
83 import android.os.Process;
84 import android.os.RemoteException;
85 import android.os.UserManager;
86 import android.os.WorkSource;
87 import android.os.test.TestLooper;
88 import android.telephony.TelephonyManager;
89 import android.util.LocalLog;
90 import android.util.Log;
91 
92 import androidx.test.filters.SmallTest;
93 
94 import com.android.modules.utils.build.SdkLevel;
95 import com.android.server.wifi.ActiveModeManager.ClientConnectivityRole;
96 import com.android.server.wifi.ActiveModeManager.Listener;
97 import com.android.server.wifi.ActiveModeManager.SoftApRole;
98 import com.android.server.wifi.ActiveModeWarden.ExternalClientModeManagerRequestListener;
99 import com.android.server.wifi.util.GeneralUtil.Mutable;
100 import com.android.server.wifi.util.LastCallerInfoManager;
101 import com.android.server.wifi.util.WifiPermissionsUtil;
102 import com.android.wifi.resources.R;
103 
104 import org.junit.After;
105 import org.junit.Before;
106 import org.junit.Test;
107 import org.mockito.ArgumentCaptor;
108 import org.mockito.InOrder;
109 import org.mockito.Mock;
110 import org.mockito.Mockito;
111 import org.mockito.MockitoAnnotations;
112 import org.mockito.invocation.InvocationOnMock;
113 import org.mockito.stubbing.Answer;
114 
115 import java.io.ByteArrayOutputStream;
116 import java.io.PrintWriter;
117 import java.util.Collection;
118 import java.util.HashMap;
119 import java.util.List;
120 import java.util.Map;
121 import java.util.stream.Collectors;
122 
123 /**
124  * Unit tests for {@link com.android.server.wifi.ActiveModeWarden}.
125  */
126 @SmallTest
127 public class ActiveModeWardenTest extends WifiBaseTest {
128     public static final String TAG = "WifiActiveModeWardenTest";
129 
130     private static final String ENABLED_STATE_STRING = "EnabledState";
131     private static final String DISABLED_STATE_STRING = "DisabledState";
132     private static final String TEST_SSID_1 = "\"Ssid12345\"";
133     private static final String TEST_SSID_2 = "\"Ssid45678\"";
134     private static final String TEST_SSID_3 = "\"Ssid98765\"";
135     private static final String TEST_BSSID_1 = "01:12:23:34:45:56";
136     private static final String TEST_BSSID_2 = "10:21:32:43:54:65";
137     private static final String TEST_BSSID_3 = "11:22:33:44:55:66";
138 
139     private static final String WIFI_IFACE_NAME = "mockWlan";
140     private static final String WIFI_IFACE_NAME_1 = "mockWlan1";
141     private static final int TEST_WIFI_RECOVERY_DELAY_MS = 2000;
142     private static final int TEST_AP_FREQUENCY = 2412;
143     private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ;
144     private static final int TEST_UID = 435546654;
145     private static final long TEST_FEATURE_SET = 0xAB3DEF;
146     private static final String TEST_PACKAGE = "com.test";
147     private static final String TEST_COUNTRYCODE = "US";
148     private static final WorkSource TEST_WORKSOURCE = new WorkSource(TEST_UID, TEST_PACKAGE);
149     private static final WorkSource SETTINGS_WORKSOURCE =
150             new WorkSource(Process.SYSTEM_UID, "system-service");
151     private static final int TEST_SUPPORTED_BANDS = 15;
152 
153     TestLooper mLooper;
154     @Mock WifiInjector mWifiInjector;
155     @Mock Context mContext;
156     @Mock Resources mResources;
157     @Mock WifiNative mWifiNative;
158     @Mock WifiApConfigStore mWifiApConfigStore;
159     @Mock ConcreteClientModeManager mClientModeManager;
160     @Mock SoftApManager mSoftApManager;
161     @Mock DefaultClientModeManager mDefaultClientModeManager;
162     @Mock BatteryStatsManager mBatteryStats;
163     @Mock SelfRecovery mSelfRecovery;
164     @Mock WifiDiagnostics mWifiDiagnostics;
165     @Mock ScanRequestProxy mScanRequestProxy;
166     @Mock FrameworkFacade mFacade;
167     @Mock WifiSettingsStore mSettingsStore;
168     @Mock WifiPermissionsUtil mWifiPermissionsUtil;
169     @Mock SoftApCapability mSoftApCapability;
170     @Mock ActiveModeWarden.ModeChangeCallback mModeChangeCallback;
171     @Mock ActiveModeWarden.PrimaryClientModeManagerChangedCallback mPrimaryChangedCallback;
172     @Mock WifiMetrics mWifiMetrics;
173     @Mock ISubsystemRestartCallback mSubsystemRestartCallback;
174     @Mock ExternalScoreUpdateObserverProxy mExternalScoreUpdateObserverProxy;
175     @Mock DppManager mDppManager;
176     @Mock SarManager mSarManager;
177     @Mock HalDeviceManager mHalDeviceManager;
178     @Mock UserManager mUserManager;
179     @Mock PackageManager mPackageManager;
180     @Mock Network mNetwork;
181     @Mock LocalLog mLocalLog;
182     @Mock WifiSettingsConfigStore mSettingsConfigStore;
183     @Mock LastCallerInfoManager mLastCallerInfoManager;
184 
185     Listener<ConcreteClientModeManager> mClientListener;
186     Listener<SoftApManager> mSoftApListener;
187     WifiServiceImpl.SoftApCallbackInternal mSoftApManagerCallback;
188     SoftApModeConfiguration mSoftApConfig;
189     @Mock WifiServiceImpl.SoftApCallbackInternal mSoftApStateMachineCallback;
190     @Mock WifiServiceImpl.SoftApCallbackInternal mLohsStateMachineCallback;
191     WifiNative.StatusListener mWifiNativeStatusListener;
192     ActiveModeWarden mActiveModeWarden;
193     private SoftApInfo mTestSoftApInfo;
194 
195     final ArgumentCaptor<WifiNative.StatusListener> mStatusListenerCaptor =
196             ArgumentCaptor.forClass(WifiNative.StatusListener.class);
197 
198     private BroadcastReceiver mEmergencyCallbackModeChangedBr;
199     private BroadcastReceiver mEmergencyCallStateChangedBr;
200 
201     /**
202      * Set up the test environment.
203      */
204     @Before
setUp()205     public void setUp() throws Exception {
206         Log.d(TAG, "Setting up ...");
207 
208         MockitoAnnotations.initMocks(this);
209         mLooper = new TestLooper();
210 
211         when(mWifiInjector.getScanRequestProxy()).thenReturn(mScanRequestProxy);
212         when(mWifiInjector.getSarManager()).thenReturn(mSarManager);
213         when(mWifiInjector.getHalDeviceManager()).thenReturn(mHalDeviceManager);
214         when(mWifiInjector.getUserManager()).thenReturn(mUserManager);
215         when(mWifiInjector.getWifiHandlerLocalLog()).thenReturn(mLocalLog);
216         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
217         when(mClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
218         when(mContext.getResources()).thenReturn(mResources);
219         when(mSoftApManager.getRole()).thenReturn(ROLE_SOFTAP_TETHERED);
220 
221         when(mResources.getString(R.string.wifi_localhotspot_configure_ssid_default))
222                 .thenReturn("AndroidShare");
223         when(mResources.getInteger(R.integer.config_wifi_framework_recovery_timeout_delay))
224                 .thenReturn(TEST_WIFI_RECOVERY_DELAY_MS);
225         when(mResources.getBoolean(R.bool.config_wifiScanHiddenNetworksScanOnlyMode))
226                 .thenReturn(false);
227         when(mResources.getBoolean(R.bool.config_wifi_turn_off_during_emergency_call))
228                 .thenReturn(true);
229 
230         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
231         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
232         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
233         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
234         when(mFacade.getSettingsWorkSource(mContext)).thenReturn(SETTINGS_WORKSOURCE);
235         when(mContext.getPackageManager()).thenReturn(mPackageManager);
236         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)).thenReturn(true);
237         when(mWifiInjector.getSettingsConfigStore()).thenReturn(mSettingsConfigStore);
238         when(mWifiInjector.getLastCallerInfoManager()).thenReturn(mLastCallerInfoManager);
239         when(mSettingsConfigStore.get(
240                 eq(WIFI_NATIVE_SUPPORTED_STA_BANDS))).thenReturn(
241                 TEST_SUPPORTED_BANDS);
242         doAnswer(new Answer<ClientModeManager>() {
243             public ClientModeManager answer(InvocationOnMock invocation) {
244                 Object[] args = invocation.getArguments();
245                 mClientListener = (Listener<ConcreteClientModeManager>) args[0];
246                 return mClientModeManager;
247             }
248         }).when(mWifiInjector).makeClientModeManager(
249                 any(Listener.class), any(), any(), anyBoolean());
250         doAnswer(new Answer<SoftApManager>() {
251             public SoftApManager answer(InvocationOnMock invocation) {
252                 Object[] args = invocation.getArguments();
253                 mSoftApListener = (Listener<SoftApManager>) args[0];
254                 mSoftApManagerCallback = (WifiServiceImpl.SoftApCallbackInternal) args[1];
255                 mSoftApConfig = (SoftApModeConfiguration) args[2];
256                 return mSoftApManager;
257             }
258         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
259                 any(WifiServiceImpl.SoftApCallbackInternal.class), any(), any(), any(),
260                 anyBoolean());
261         when(mWifiNative.initialize()).thenReturn(true);
262         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(true);
263 
264         mActiveModeWarden = createActiveModeWarden();
265         mActiveModeWarden.start();
266         mLooper.dispatchAll();
267 
268         verify(mWifiMetrics).noteWifiEnabledDuringBoot(false);
269 
270         verify(mWifiNative).registerStatusListener(mStatusListenerCaptor.capture());
271         verify(mWifiNative).initialize();
272         mWifiNativeStatusListener = mStatusListenerCaptor.getValue();
273 
274         mActiveModeWarden.registerSoftApCallback(mSoftApStateMachineCallback);
275         mActiveModeWarden.registerLohsCallback(mLohsStateMachineCallback);
276         mActiveModeWarden.registerModeChangeCallback(mModeChangeCallback);
277         mActiveModeWarden.registerPrimaryClientModeManagerChangedCallback(mPrimaryChangedCallback);
278         when(mSubsystemRestartCallback.asBinder()).thenReturn(Mockito.mock(IBinder.class));
279         mActiveModeWarden.registerSubsystemRestartCallback(mSubsystemRestartCallback);
280         mTestSoftApInfo = new SoftApInfo();
281         mTestSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
282         mTestSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
283 
284         ArgumentCaptor<BroadcastReceiver> bcastRxCaptor =
285                 ArgumentCaptor.forClass(BroadcastReceiver.class);
286         verify(mContext).registerReceiver(
287                 bcastRxCaptor.capture(),
288                 argThat(filter ->
289                         filter.hasAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)));
290         mEmergencyCallbackModeChangedBr = bcastRxCaptor.getValue();
291 
292         verify(mContext).registerReceiver(
293                 bcastRxCaptor.capture(),
294                 argThat(filter ->
295                         filter.hasAction(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED)));
296         mEmergencyCallStateChangedBr = bcastRxCaptor.getValue();
297     }
298 
createActiveModeWarden()299     private ActiveModeWarden createActiveModeWarden() {
300         ActiveModeWarden warden = new ActiveModeWarden(
301                 mWifiInjector,
302                 mLooper.getLooper(),
303                 mWifiNative,
304                 mDefaultClientModeManager,
305                 mBatteryStats,
306                 mWifiDiagnostics,
307                 mContext,
308                 mSettingsStore,
309                 mFacade,
310                 mWifiPermissionsUtil,
311                 mWifiMetrics,
312                 mExternalScoreUpdateObserverProxy,
313                 mDppManager);
314         // SelfRecovery is created in WifiInjector after ActiveModeWarden, so getSelfRecovery()
315         // returns null when constructing ActiveModeWarden.
316         when(mWifiInjector.getSelfRecovery()).thenReturn(mSelfRecovery);
317         when(mContext.getPackageManager()).thenReturn(mPackageManager);
318         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)).thenReturn(true);
319         return warden;
320     }
321 
322     /**
323      * Clean up after tests - explicitly set tested object to null.
324      */
325     @After
cleanUp()326     public void cleanUp() throws Exception {
327         mActiveModeWarden = null;
328         mLooper.dispatchAll();
329     }
330 
emergencyCallbackModeChanged(boolean enabled)331     private void emergencyCallbackModeChanged(boolean enabled) {
332         Intent intent = new Intent(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
333         intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, enabled);
334         mEmergencyCallbackModeChangedBr.onReceive(mContext, intent);
335     }
336 
emergencyCallStateChanged(boolean enabled)337     private void emergencyCallStateChanged(boolean enabled) {
338         Intent intent = new Intent(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED);
339         intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, enabled);
340         mEmergencyCallStateChangedBr.onReceive(mContext, intent);
341     }
342 
enterClientModeActiveState()343     private void enterClientModeActiveState() throws Exception {
344         enterClientModeActiveState(false);
345     }
346 
347     /**
348      * Helper method to enter the EnabledState and set ClientModeManager in ConnectMode.
349      * @param isClientModeSwitch true if switching from another mode, false if creating a new one
350      */
enterClientModeActiveState(boolean isClientModeSwitch)351     private void enterClientModeActiveState(boolean isClientModeSwitch) throws Exception {
352         String fromState = mActiveModeWarden.getCurrentMode();
353         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
354         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
355         mLooper.dispatchAll();
356         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
357         when(mClientModeManager.getCurrentNetwork()).thenReturn(mNetwork);
358         when(mWifiNative.getSupportedFeatureSet(WIFI_IFACE_NAME)).thenReturn(TEST_FEATURE_SET);
359         // ClientModeManager starts in SCAN_ONLY role.
360         mClientListener.onRoleChanged(mClientModeManager);
361         mLooper.dispatchAll();
362 
363         assertInEnabledState();
364         if (!isClientModeSwitch) {
365             verify(mWifiInjector).makeClientModeManager(
366                     any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
367         } else {
368             verify(mClientModeManager).setRole(ROLE_CLIENT_PRIMARY, SETTINGS_WORKSOURCE);
369         }
370         verify(mScanRequestProxy, times(1)).enableScanning(true, true);
371         if (fromState.equals(DISABLED_STATE_STRING)) {
372             verify(mBatteryStats).reportWifiOn();
373         }
374         for (int i = 0; i < 3; i++) {
375             mActiveModeWarden.updateClientScanModeAfterCountryCodeUpdate(TEST_COUNTRYCODE);
376         }
377         verify(mClientModeManager, atLeastOnce()).getInterfaceName();
378         verify(mWifiNative, atLeastOnce()).getSupportedFeatureSet(WIFI_IFACE_NAME);
379         assertEquals(TEST_FEATURE_SET, mActiveModeWarden.getSupportedFeatureSet());
380         verify(mScanRequestProxy, times(4)).enableScanning(true, true);
381         assertEquals(mClientModeManager, mActiveModeWarden.getPrimaryClientModeManager());
382         verify(mModeChangeCallback).onActiveModeManagerRoleChanged(mClientModeManager);
383     }
384 
enterScanOnlyModeActiveState()385     private void enterScanOnlyModeActiveState() throws Exception {
386         enterScanOnlyModeActiveState(false);
387     }
388 
389     /**
390      * Helper method to enter the EnabledState and set ClientModeManager in ScanOnlyMode.
391      */
enterScanOnlyModeActiveState(boolean isClientModeSwitch)392     private void enterScanOnlyModeActiveState(boolean isClientModeSwitch) throws Exception {
393         String fromState = mActiveModeWarden.getCurrentMode();
394         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
395         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
396         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
397         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
398         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
399         mLooper.dispatchAll();
400         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SCAN_ONLY);
401         when(mClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
402         when(mClientModeManager.getCurrentNetwork()).thenReturn(null);
403         when(mWifiNative.getSupportedFeatureSet(null)).thenReturn(TEST_FEATURE_SET);
404         if (!isClientModeSwitch) {
405             mClientListener.onStarted(mClientModeManager);
406             mLooper.dispatchAll();
407             verify(mWifiInjector).makeClientModeManager(
408                     any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_SCAN_ONLY), anyBoolean());
409             verify(mModeChangeCallback).onActiveModeManagerAdded(mClientModeManager);
410         } else {
411             mClientListener.onRoleChanged(mClientModeManager);
412             mLooper.dispatchAll();
413             verify(mClientModeManager).setRole(ROLE_CLIENT_SCAN_ONLY, INTERNAL_REQUESTOR_WS);
414             // If switching from client mode back to scan only mode, role change would have been
415             // called once before when transitioning from scan only mode to client mode.
416             // Verify that it was called again.
417             verify(mModeChangeCallback, times(2))
418                     .onActiveModeManagerRoleChanged(mClientModeManager);
419             verify(mWifiNative, atLeastOnce()).getSupportedFeatureSet(null);
420             assertEquals(TEST_FEATURE_SET, mActiveModeWarden.getSupportedFeatureSet());
421         }
422         assertInEnabledState();
423         verify(mScanRequestProxy).enableScanning(true, false);
424         if (fromState.equals(DISABLED_STATE_STRING)) {
425             verify(mBatteryStats).reportWifiOn();
426         }
427         verify(mBatteryStats).reportWifiState(BatteryStatsManager.WIFI_STATE_OFF_SCANNING, null);
428         assertEquals(mClientModeManager, mActiveModeWarden.getScanOnlyClientModeManager());
429     }
430 
enterSoftApActiveMode()431     private void enterSoftApActiveMode() throws Exception {
432         enterSoftApActiveMode(
433                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
434                 mSoftApCapability, TEST_COUNTRYCODE));
435     }
436 
437     private int mTimesCreatedSoftApManager = 1;
438 
439     /**
440      * Helper method to activate SoftApManager.
441      *
442      * This method puts the test object into the correct state and verifies steps along the way.
443      */
enterSoftApActiveMode(SoftApModeConfiguration softApConfig)444     private void enterSoftApActiveMode(SoftApModeConfiguration softApConfig) throws Exception {
445         String fromState = mActiveModeWarden.getCurrentMode();
446         SoftApRole softApRole = softApConfig.getTargetMode() == WifiManager.IFACE_IP_MODE_TETHERED
447                 ? ROLE_SOFTAP_TETHERED : ROLE_SOFTAP_LOCAL_ONLY;
448         mActiveModeWarden.startSoftAp(softApConfig, TEST_WORKSOURCE);
449         mLooper.dispatchAll();
450         when(mSoftApManager.getRole()).thenReturn(softApRole);
451         when(mSoftApManager.getSoftApModeConfiguration()).thenReturn(softApConfig);
452         mSoftApListener.onStarted(mSoftApManager);
453         mLooper.dispatchAll();
454 
455         assertInEnabledState();
456         assertThat(softApConfig).isEqualTo(mSoftApConfig);
457         verify(mWifiInjector, times(mTimesCreatedSoftApManager)).makeSoftApManager(
458                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(softApRole), anyBoolean());
459         mTimesCreatedSoftApManager++;
460         if (fromState.equals(DISABLED_STATE_STRING)) {
461             verify(mBatteryStats).reportWifiOn();
462         }
463         if (softApRole == ROLE_SOFTAP_TETHERED) {
464             assertEquals(mSoftApManager, mActiveModeWarden.getTetheredSoftApManager());
465             assertNull(mActiveModeWarden.getLocalOnlySoftApManager());
466         } else {
467             assertEquals(mSoftApManager, mActiveModeWarden.getLocalOnlySoftApManager());
468             assertNull(mActiveModeWarden.getTetheredSoftApManager());
469         }
470         verify(mModeChangeCallback).onActiveModeManagerAdded(mSoftApManager);
471     }
472 
enterStaDisabledMode(boolean isSoftApModeManagerActive)473     private void enterStaDisabledMode(boolean isSoftApModeManagerActive) {
474         String fromState = mActiveModeWarden.getCurrentMode();
475         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
476         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
477         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
478         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
479         mLooper.dispatchAll();
480         if (mClientListener != null) {
481             mClientListener.onStopped(mClientModeManager);
482             mLooper.dispatchAll();
483             verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
484         }
485 
486         if (isSoftApModeManagerActive) {
487             assertInEnabledState();
488         } else {
489             assertInDisabledState();
490         }
491         if (fromState.equals(ENABLED_STATE_STRING)) {
492             verify(mScanRequestProxy).enableScanning(false, false);
493         }
494         // Ensure we return the default client mode manager when wifi is off.
495         assertEquals(mDefaultClientModeManager, mActiveModeWarden.getPrimaryClientModeManager());
496     }
497 
shutdownWifi()498     private void shutdownWifi() {
499         mActiveModeWarden.recoveryDisableWifi();
500         mLooper.dispatchAll();
501     }
502 
assertInEnabledState()503     private void assertInEnabledState() {
504         assertThat(mActiveModeWarden.getCurrentMode()).isEqualTo(ENABLED_STATE_STRING);
505     }
506 
assertInDisabledState()507     private void assertInDisabledState() {
508         assertThat(mActiveModeWarden.getCurrentMode()).isEqualTo(DISABLED_STATE_STRING);
509     }
510 
511     /**
512      * Emergency mode is a sub-mode within each main state (ScanOnly, Client, DisabledState).
513      */
assertInEmergencyMode()514     private void assertInEmergencyMode() {
515         assertThat(mActiveModeWarden.isInEmergencyMode()).isTrue();
516     }
517 
assertNotInEmergencyMode()518     private void assertNotInEmergencyMode() {
519         assertThat(mActiveModeWarden.isInEmergencyMode()).isFalse();
520     }
521 
522     /**
523      * Counts the number of times a void method was called on a mock.
524      *
525      * Void methods cannot be passed to Mockito.mockingDetails(). Thus we have to use method name
526      * matching instead.
527      */
getMethodInvocationCount(Object mock, String methodName)528     private static int getMethodInvocationCount(Object mock, String methodName) {
529         long count = mockingDetails(mock).getInvocations()
530                 .stream()
531                 .filter(invocation -> methodName.equals(invocation.getMethod().getName()))
532                 .count();
533         return (int) count;
534     }
535 
536     /**
537      * Counts the number of times a non-void method was called on a mock.
538      *
539      * For non-void methods, can pass the method call literal directly:
540      * e.g. getMethodInvocationCount(mock.method());
541      */
getMethodInvocationCount(Object mockMethod)542     private static int getMethodInvocationCount(Object mockMethod) {
543         return mockingDetails(mockMethod).getInvocations().size();
544     }
545 
assertWifiShutDown(Runnable r)546     private void assertWifiShutDown(Runnable r) {
547         assertWifiShutDown(r, 1);
548     }
549 
550     /**
551      * Asserts that the runnable r has shut down wifi properly.
552      *
553      * @param r     runnable that will shut down wifi
554      * @param times expected number of times that <code>r</code> shut down wifi
555      */
assertWifiShutDown(Runnable r, int times)556     private void assertWifiShutDown(Runnable r, int times) {
557         // take snapshot of ActiveModeManagers
558         Collection<ActiveModeManager> activeModeManagers =
559                 mActiveModeWarden.getActiveModeManagers();
560 
561         List<Integer> expectedStopInvocationCounts = activeModeManagers
562                 .stream()
563                 .map(manager -> getMethodInvocationCount(manager, "stop") + times)
564                 .collect(Collectors.toList());
565 
566         r.run();
567 
568         List<Integer> actualStopInvocationCounts = activeModeManagers
569                 .stream()
570                 .map(manager -> getMethodInvocationCount(manager, "stop"))
571                 .collect(Collectors.toList());
572 
573         String managerNames = activeModeManagers.stream()
574                 .map(manager -> manager.getClass().getCanonicalName())
575                 .collect(Collectors.joining(", ", "[", "]"));
576 
577         assertWithMessage(managerNames).that(actualStopInvocationCounts)
578                 .isEqualTo(expectedStopInvocationCounts);
579     }
580 
assertEnteredEcmMode(Runnable r)581     private void assertEnteredEcmMode(Runnable r) {
582         assertEnteredEcmMode(r, 1);
583     }
584 
585     /**
586      * Asserts that the runnable r has entered ECM state properly.
587      *
588      * @param r     runnable that will enter ECM
589      * @param times expected number of times that <code>r</code> shut down wifi
590      */
assertEnteredEcmMode(Runnable r, int times)591     private void assertEnteredEcmMode(Runnable r, int times) {
592         // take snapshot of ActiveModeManagers
593         Collection<ActiveModeManager> activeModeManagers =
594                 mActiveModeWarden.getActiveModeManagers();
595 
596         boolean disableWifiInEcm = mFacade.getConfigWiFiDisableInECBM(mContext);
597 
598         List<Integer> expectedStopInvocationCounts = activeModeManagers.stream()
599                 .map(manager -> {
600                     int initialCount = getMethodInvocationCount(manager, "stop");
601                     // carrier config enabled, all mode managers should have been shut down once
602                     int count = disableWifiInEcm ? initialCount + times : initialCount;
603                     if (manager instanceof SoftApManager) {
604                         // expect SoftApManager.close() to be called
605                         return count + times;
606                     } else {
607                         // don't expect other Managers close() to be called
608                         return count;
609                     }
610                 })
611                 .collect(Collectors.toList());
612 
613         r.run();
614 
615         assertInEmergencyMode();
616 
617         List<Integer> actualStopInvocationCounts = activeModeManagers.stream()
618                 .map(manager -> getMethodInvocationCount(manager, "stop"))
619                 .collect(Collectors.toList());
620 
621         String managerNames = activeModeManagers.stream()
622                 .map(manager -> manager.getClass().getCanonicalName())
623                 .collect(Collectors.joining(", ", "[", "]"));
624 
625         assertWithMessage(managerNames).that(actualStopInvocationCounts)
626                 .isEqualTo(expectedStopInvocationCounts);
627     }
628 
629     /** Test that after starting up, ActiveModeWarden is in the DisabledState State. */
630     @Test
testDisabledStateAtStartup()631     public void testDisabledStateAtStartup() {
632         assertInDisabledState();
633     }
634 
635     /**
636      * Test that ActiveModeWarden properly enters the EnabledState (in ScanOnlyMode) from the
637      * DisabledState state.
638      */
639     @Test
testEnterScanOnlyModeFromDisabled()640     public void testEnterScanOnlyModeFromDisabled() throws Exception {
641         enterScanOnlyModeActiveState();
642     }
643 
644     /**
645      * Test that ActiveModeWarden enables hidden network scanning in scan-only-mode
646      * if configured to do.
647      */
648     @Test
testScanOnlyModeScanHiddenNetworks()649     public void testScanOnlyModeScanHiddenNetworks() throws Exception {
650         when(mResources.getBoolean(R.bool.config_wifiScanHiddenNetworksScanOnlyMode))
651                 .thenReturn(true);
652 
653         mActiveModeWarden = createActiveModeWarden();
654         mActiveModeWarden.start();
655         mLooper.dispatchAll();
656 
657         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SCAN_ONLY);
658         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
659         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
660         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
661         mLooper.dispatchAll();
662         mClientListener.onStarted(mClientModeManager);
663         mLooper.dispatchAll();
664 
665         assertInEnabledState();
666         verify(mWifiInjector).makeClientModeManager(
667                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_SCAN_ONLY), anyBoolean());
668         verify(mScanRequestProxy).enableScanning(true, true);
669     }
670 
671     /**
672      * Test that ActiveModeWarden properly starts the SoftApManager from the
673      * DisabledState state.
674      */
675     @Test
testEnterSoftApModeFromDisabled()676     public void testEnterSoftApModeFromDisabled() throws Exception {
677         enterSoftApActiveMode();
678     }
679 
680     /**
681      * Test that ActiveModeWarden properly starts the SoftApManager from another state.
682      */
683     @Test
testEnterSoftApModeFromDifferentState()684     public void testEnterSoftApModeFromDifferentState() throws Exception {
685         enterClientModeActiveState();
686         assertInEnabledState();
687         reset(mBatteryStats, mScanRequestProxy);
688         enterSoftApActiveMode();
689     }
690 
691     /**
692      * Test that we can disable wifi fully from the EnabledState (in ScanOnlyMode).
693      */
694     @Test
testDisableWifiFromScanOnlyModeActiveState()695     public void testDisableWifiFromScanOnlyModeActiveState() throws Exception {
696         enterScanOnlyModeActiveState();
697 
698         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
699         mActiveModeWarden.scanAlwaysModeChanged();
700         mLooper.dispatchAll();
701         mClientListener.onStopped(mClientModeManager);
702         mLooper.dispatchAll();
703 
704         verify(mClientModeManager).stop();
705         verify(mBatteryStats).reportWifiOff();
706         assertInDisabledState();
707     }
708 
709     /**
710      * Test that we can disable wifi when SoftApManager is active and not impact softap.
711      */
712     @Test
testDisableWifiFromSoftApModeActiveStateDoesNotStopSoftAp()713     public void testDisableWifiFromSoftApModeActiveStateDoesNotStopSoftAp() throws Exception {
714         enterSoftApActiveMode();
715         enterScanOnlyModeActiveState();
716 
717         reset(mDefaultClientModeManager);
718         enterStaDisabledMode(true);
719         verify(mSoftApManager, never()).stop();
720         verify(mBatteryStats, never()).reportWifiOff();
721     }
722 
723     /**
724      * Test that we can switch from the EnabledState (in ScanOnlyMode) to another mode.
725      */
726     @Test
testSwitchModeWhenScanOnlyModeActiveState()727     public void testSwitchModeWhenScanOnlyModeActiveState() throws Exception {
728         enterScanOnlyModeActiveState();
729 
730         reset(mBatteryStats, mScanRequestProxy);
731         enterClientModeActiveState(true);
732         mLooper.dispatchAll();
733     }
734 
735     /**
736      * Test that we can switch from the EnabledState (in ConnectMode) to another mode.
737      */
738     @Test
testSwitchModeWhenConnectModeActiveState()739     public void testSwitchModeWhenConnectModeActiveState() throws Exception {
740         enterClientModeActiveState();
741 
742         verify(mPrimaryChangedCallback).onChange(null, mClientModeManager);
743 
744         reset(mBatteryStats, mScanRequestProxy);
745         enterScanOnlyModeActiveState(true);
746         mLooper.dispatchAll();
747 
748         verify(mPrimaryChangedCallback).onChange(mClientModeManager, null);
749     }
750 
751     /**
752      * Test that wifi toggle switching the primary to scan only mode will also remove the additional
753      * CMMs.
754      */
755     @Test
testSwitchFromConnectModeToScanOnlyModeRemovesAdditionalCMMs()756     public void testSwitchFromConnectModeToScanOnlyModeRemovesAdditionalCMMs() throws Exception {
757         // Ensure that we can create more client ifaces.
758         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
759         when(mResources.getBoolean(
760                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
761                 .thenReturn(true);
762         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
763                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
764 
765         // request for an additional CMM
766         ConcreteClientModeManager additionalClientModeManager =
767                 mock(ConcreteClientModeManager.class);
768         ExternalClientModeManagerRequestListener externalRequestListener = mock(
769                 ExternalClientModeManagerRequestListener.class);
770         Listener<ConcreteClientModeManager> additionalClientListener =
771                 requestAdditionalClientModeManager(ROLE_CLIENT_SECONDARY_TRANSIENT,
772                         additionalClientModeManager, externalRequestListener, TEST_SSID_2,
773                         TEST_BSSID_2);
774 
775         // Verify that there exists both a primary and a secondary transient CMM
776         List<ClientModeManager> currentCMMs = mActiveModeWarden.getClientModeManagers();
777         assertEquals(2, currentCMMs.size());
778         assertTrue(currentCMMs.stream().anyMatch(cmm -> cmm.getRole() == ROLE_CLIENT_PRIMARY));
779         assertTrue(currentCMMs.stream().anyMatch(
780                 cmm -> cmm.getRole() == ROLE_CLIENT_SECONDARY_TRANSIENT));
781 
782         InOrder inOrder = inOrder(additionalClientModeManager, mClientModeManager);
783         // disable wifi and switch primary CMM to scan only mode
784         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
785         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
786         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
787         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
788         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
789         mLooper.dispatchAll();
790 
791         // Verify that we first stop the additional CMM and then switch the primary to scan only
792         // mode
793         inOrder.verify(additionalClientModeManager).stop();
794         inOrder.verify(mClientModeManager).setRole(ROLE_CLIENT_SCAN_ONLY, INTERNAL_REQUESTOR_WS);
795     }
796 
797     /**
798      * Verify that when there are only secondary CMMs available, the user toggling wifi on will
799      * create a new primary CMM.
800      */
801     @Test
testToggleWifiWithOnlySecondaryCmmsCreatesPrimaryOrScanOnlyCmm()802     public void testToggleWifiWithOnlySecondaryCmmsCreatesPrimaryOrScanOnlyCmm() throws Exception {
803         enterClientModeActiveState();
804         verify(mWifiInjector, times(1)).makeClientModeManager(
805                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
806 
807         // toggling wifi on again should be no-op when primary is already available
808         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
809         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
810         mLooper.dispatchAll();
811 
812         verify(mWifiInjector, times(1)).makeClientModeManager(
813                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
814 
815         // Make the primary CMM change to local only secondary role.
816         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
817         mClientListener.onRoleChanged(mClientModeManager);
818         mLooper.dispatchAll();
819 
820         // Verify that there only exists the ROLE_CLIENT_LOCAL_ONLY CMM.
821         List<ClientModeManager> currentCMMs = mActiveModeWarden.getClientModeManagers();
822         assertEquals(1, currentCMMs.size());
823         assertTrue(currentCMMs.get(0).getRole() == ROLE_CLIENT_LOCAL_ONLY);
824 
825         // verify wifi toggling on should recreate the primary CMM
826         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
827         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
828         mLooper.dispatchAll();
829 
830         verify(mWifiInjector, times(2)).makeClientModeManager(
831                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
832     }
833 
834     @Test
testPrimaryNotCreatedTwice()835     public void testPrimaryNotCreatedTwice() throws Exception {
836         enterClientModeActiveState();
837         verify(mWifiInjector).makeClientModeManager(
838                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
839 
840         // toggling wifi on again should be no-op when primary is already available
841         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
842         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
843         mLooper.dispatchAll();
844 
845         verify(mWifiInjector).makeClientModeManager(
846                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
847 
848         // Simulate the primary not fully started by making the role null and targetRole primary.
849         when(mClientModeManager.getRole()).thenReturn(null);
850         when(mClientModeManager.getTargetRole()).thenReturn(ROLE_CLIENT_PRIMARY);
851 
852         // Verify that there is no primary, but there is a CMM with targetRole as primary.
853         List<ClientModeManager> currentCMMs = mActiveModeWarden.getClientModeManagers();
854         assertEquals(1, currentCMMs.size());
855         ConcreteClientModeManager currentCmm = (ConcreteClientModeManager) currentCMMs.get(0);
856         assertTrue(currentCmm.getRole() == null);
857         assertTrue(currentCmm.getTargetRole() == ROLE_CLIENT_PRIMARY);
858 
859         // verify wifi toggling on should not create another primary CMM.
860         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
861         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
862         mLooper.dispatchAll();
863 
864         verify(mWifiInjector).makeClientModeManager(
865                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
866     }
867 
868     /**
869      * Reentering EnabledState should be a NOP.
870      */
871     @Test
testReenterClientModeActiveStateIsNop()872     public void testReenterClientModeActiveStateIsNop() throws Exception {
873         enterClientModeActiveState();
874         verify(mWifiInjector, times(1)).makeClientModeManager(
875                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
876 
877         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
878         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
879         mLooper.dispatchAll();
880         // Should not start again.
881         verify(mWifiInjector, times(1)).makeClientModeManager(
882                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
883     }
884 
885     /**
886      * Test that we can switch mode when SoftApManager is active to another mode.
887      */
888     @Test
testSwitchModeWhenSoftApActiveMode()889     public void testSwitchModeWhenSoftApActiveMode() throws Exception {
890         enterSoftApActiveMode();
891 
892         reset(mWifiNative);
893 
894         enterClientModeActiveState();
895         mLooper.dispatchAll();
896         verify(mSoftApManager, never()).stop();
897         assertInEnabledState();
898         verify(mWifiNative, never()).teardownAllInterfaces();
899     }
900 
901     /**
902      * Test that we activate SoftApModeManager if we are already in DisabledState due to
903      * a failure.
904      */
905     @Test
testEnterSoftApModeActiveWhenAlreadyInSoftApMode()906     public void testEnterSoftApModeActiveWhenAlreadyInSoftApMode() throws Exception {
907         enterSoftApActiveMode();
908         // now inject failure through the SoftApManager.Listener
909         mSoftApListener.onStartFailure(mSoftApManager);
910         mLooper.dispatchAll();
911         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
912         assertInDisabledState();
913         // clear the first call to start SoftApManager
914         reset(mSoftApManager, mBatteryStats, mModeChangeCallback);
915 
916         enterSoftApActiveMode();
917     }
918 
919     /**
920      * Test that we return to the DisabledState after a failure is reported when in the
921      * EnabledState.
922      */
923     @Test
testScanOnlyModeFailureWhenActive()924     public void testScanOnlyModeFailureWhenActive() throws Exception {
925         enterScanOnlyModeActiveState();
926         // now inject a failure through the ScanOnlyModeManager.Listener
927         mClientListener.onStartFailure(mClientModeManager);
928         mLooper.dispatchAll();
929         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
930         assertInDisabledState();
931         verify(mBatteryStats).reportWifiOff();
932     }
933 
934     /**
935      * Test that we return to the DisabledState after a failure is reported when
936      * SoftApManager is active.
937      */
938     @Test
testSoftApFailureWhenActive()939     public void testSoftApFailureWhenActive() throws Exception {
940         enterSoftApActiveMode();
941         // now inject failure through the SoftApManager.Listener
942         mSoftApListener.onStartFailure(mSoftApManager);
943         mLooper.dispatchAll();
944         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
945         verify(mBatteryStats).reportWifiOff();
946     }
947 
948     /**
949      * Test that we return to the DisabledState after the ClientModeManager running in ScanOnlyMode
950      * is stopped.
951      */
952     @Test
testScanOnlyModeDisabledWhenActive()953     public void testScanOnlyModeDisabledWhenActive() throws Exception {
954         enterScanOnlyModeActiveState();
955 
956         // now inject the stop message through the ScanOnlyModeManager.Listener
957         mClientListener.onStopped(mClientModeManager);
958         mLooper.dispatchAll();
959 
960         assertInDisabledState();
961         verify(mBatteryStats).reportWifiOff();
962     }
963 
964     /**
965      * Test that we return to the DisabledState after the SoftApManager is stopped.
966      */
967     @Test
testSoftApDisabledWhenActive()968     public void testSoftApDisabledWhenActive() throws Exception {
969         enterSoftApActiveMode();
970         reset(mWifiNative);
971         // now inject failure through the SoftApManager.Listener
972         mSoftApListener.onStartFailure(mSoftApManager);
973         mLooper.dispatchAll();
974         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
975         verify(mBatteryStats).reportWifiOff();
976         verifyNoMoreInteractions(mWifiNative);
977     }
978 
979     /**
980      * Verifies that SoftApStateChanged event is being passed from SoftApManager to WifiServiceImpl
981      */
982     @Test
callsWifiServiceCallbackOnSoftApStateChanged()983     public void callsWifiServiceCallbackOnSoftApStateChanged() throws Exception {
984         enterSoftApActiveMode();
985 
986         mSoftApListener.onStarted(mSoftApManager);
987         mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0);
988         mLooper.dispatchAll();
989 
990         verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0);
991     }
992 
993     /**
994      * Verifies that SoftApStateChanged event isn't passed to WifiServiceImpl for LOHS,
995      * so the state change for LOHS doesn't affect Wifi Tethering indication.
996      */
997     @Test
doesntCallWifiServiceCallbackOnLOHSStateChanged()998     public void doesntCallWifiServiceCallbackOnLOHSStateChanged() throws Exception {
999         enterSoftApActiveMode(new SoftApModeConfiguration(
1000                 WifiManager.IFACE_IP_MODE_LOCAL_ONLY, null, mSoftApCapability, TEST_COUNTRYCODE));
1001 
1002         mSoftApListener.onStarted(mSoftApManager);
1003         mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0);
1004         mLooper.dispatchAll();
1005 
1006         verify(mSoftApStateMachineCallback, never()).onStateChanged(anyInt(), anyInt());
1007         verify(mSoftApStateMachineCallback, never()).onConnectedClientsOrInfoChanged(any(),
1008                 any(), anyBoolean());
1009     }
1010 
1011     /**
1012      * Verifies that ConnectedClientsOrInfoChanged event is being passed from SoftApManager
1013      * to WifiServiceImpl
1014      */
1015     @Test
callsWifiServiceCallbackOnSoftApConnectedClientsChanged()1016     public void callsWifiServiceCallbackOnSoftApConnectedClientsChanged() throws Exception {
1017         final Map<String, List<WifiClient>> testClients = new HashMap();
1018         final Map<String, SoftApInfo> testInfos = new HashMap();
1019         enterSoftApActiveMode();
1020         mSoftApManagerCallback.onConnectedClientsOrInfoChanged(testInfos, testClients, false);
1021         mLooper.dispatchAll();
1022 
1023         verify(mSoftApStateMachineCallback).onConnectedClientsOrInfoChanged(
1024                 testInfos, testClients, false);
1025     }
1026 
1027     /**
1028      * Test that we remain in the active state when we get a state change update that scan mode is
1029      * active.
1030      */
1031     @Test
testScanOnlyModeStaysActiveOnEnabledUpdate()1032     public void testScanOnlyModeStaysActiveOnEnabledUpdate() throws Exception {
1033         enterScanOnlyModeActiveState();
1034         // now inject success through the Listener
1035         mClientListener.onStarted(mClientModeManager);
1036         mLooper.dispatchAll();
1037         assertInEnabledState();
1038         verify(mClientModeManager, never()).stop();
1039     }
1040 
1041     /**
1042      * Test that a config passed in to the call to enterSoftApMode is used to create the new
1043      * SoftApManager.
1044      */
1045     @Test
testConfigIsPassedToWifiInjector()1046     public void testConfigIsPassedToWifiInjector() throws Exception {
1047         Builder configBuilder = new SoftApConfiguration.Builder();
1048         configBuilder.setSsid("ThisIsAConfig");
1049         SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(
1050                 WifiManager.IFACE_IP_MODE_TETHERED, configBuilder.build(), mSoftApCapability,
1051                 TEST_COUNTRYCODE);
1052         enterSoftApActiveMode(softApConfig);
1053     }
1054 
1055     /**
1056      * Test that when enterSoftAPMode is called with a null config, we pass a null config to
1057      * WifiInjector.makeSoftApManager.
1058      *
1059      * Passing a null config to SoftApManager indicates that the default config should be used.
1060      */
1061     @Test
testNullConfigIsPassedToWifiInjector()1062     public void testNullConfigIsPassedToWifiInjector() throws Exception {
1063         enterSoftApActiveMode();
1064     }
1065 
1066     /**
1067      * Test that two calls to switch to SoftAPMode in succession ends up with the correct config.
1068      *
1069      * Expectation: we should end up in SoftAPMode state configured with the second config.
1070      */
1071     @Test
testStartSoftApModeTwiceWithTwoConfigs()1072     public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception {
1073         when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
1074         Builder configBuilder1 = new SoftApConfiguration.Builder();
1075         configBuilder1.setSsid("ThisIsAConfig");
1076         SoftApModeConfiguration softApConfig1 = new SoftApModeConfiguration(
1077                 WifiManager.IFACE_IP_MODE_TETHERED, configBuilder1.build(),
1078                 mSoftApCapability, TEST_COUNTRYCODE);
1079         Builder configBuilder2 = new SoftApConfiguration.Builder();
1080         configBuilder2.setSsid("ThisIsASecondConfig");
1081         SoftApModeConfiguration softApConfig2 = new SoftApModeConfiguration(
1082                 WifiManager.IFACE_IP_MODE_TETHERED, configBuilder2.build(),
1083                 mSoftApCapability, TEST_COUNTRYCODE);
1084 
1085         doAnswer(new Answer<SoftApManager>() {
1086             public SoftApManager answer(InvocationOnMock invocation) {
1087                 Object[] args = invocation.getArguments();
1088                 mSoftApListener = (Listener<SoftApManager>) args[0];
1089                 return mSoftApManager;
1090             }
1091         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
1092                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(softApConfig1), any(), any(),
1093                 anyBoolean());
1094         // make a second softap manager
1095         SoftApManager softapManager = mock(SoftApManager.class);
1096         Mutable<Listener<SoftApManager>> softApListener =
1097                 new Mutable<>();
1098         doAnswer(new Answer<SoftApManager>() {
1099             public SoftApManager answer(InvocationOnMock invocation) {
1100                 Object[] args = invocation.getArguments();
1101                 softApListener.value = (Listener<SoftApManager>) args[0];
1102                 return softapManager;
1103             }
1104         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
1105                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(softApConfig2), any(), any(),
1106                 anyBoolean());
1107 
1108         mActiveModeWarden.startSoftAp(softApConfig1, TEST_WORKSOURCE);
1109         mLooper.dispatchAll();
1110         mSoftApListener.onStarted(mSoftApManager);
1111         mActiveModeWarden.startSoftAp(softApConfig2, TEST_WORKSOURCE);
1112         mLooper.dispatchAll();
1113         softApListener.value.onStarted(softapManager);
1114 
1115         verify(mWifiInjector, times(2)).makeSoftApManager(
1116                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
1117         verify(mBatteryStats).reportWifiOn();
1118     }
1119 
1120     /**
1121      * Test that we safely disable wifi if it is already disabled.
1122      */
1123     @Test
disableWifiWhenAlreadyOff()1124     public void disableWifiWhenAlreadyOff() throws Exception {
1125         enterStaDisabledMode(false);
1126         verify(mWifiNative).getSupportedFeatureSet(null);
1127         verify(mWifiNative).isStaApConcurrencySupported();
1128         verify(mWifiNative).isStaStaConcurrencySupported();
1129         verifyZeroInteractions(mWifiNative);
1130     }
1131 
1132     /**
1133      * Trigger recovery and a bug report if we see a native failure
1134      * while the device is not shutting down
1135      */
1136     @Test
handleWifiNativeFailureDeviceNotShuttingDown()1137     public void handleWifiNativeFailureDeviceNotShuttingDown() throws Exception {
1138         mWifiNativeStatusListener.onStatusChanged(false);
1139         mLooper.dispatchAll();
1140         verify(mWifiDiagnostics).triggerBugReportDataCapture(
1141                 WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE);
1142         verify(mSelfRecovery).trigger(eq(SelfRecovery.REASON_WIFINATIVE_FAILURE));
1143     }
1144 
1145     /**
1146      * Verify the device shutting down doesn't trigger recovery or bug report.
1147      */
1148     @Test
handleWifiNativeFailureDeviceShuttingDown()1149     public void handleWifiNativeFailureDeviceShuttingDown() throws Exception {
1150         mActiveModeWarden.notifyShuttingDown();
1151         mWifiNativeStatusListener.onStatusChanged(false);
1152         mLooper.dispatchAll();
1153         verify(mWifiDiagnostics, never()).triggerBugReportDataCapture(
1154                 WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE);
1155         verify(mSelfRecovery, never()).trigger(eq(SelfRecovery.REASON_WIFINATIVE_FAILURE));
1156     }
1157 
1158     /**
1159      * Verify an onStatusChanged callback with "true" does not trigger recovery.
1160      */
1161     @Test
handleWifiNativeStatusReady()1162     public void handleWifiNativeStatusReady() throws Exception {
1163         mWifiNativeStatusListener.onStatusChanged(true);
1164         mLooper.dispatchAll();
1165         verify(mWifiDiagnostics, never()).triggerBugReportDataCapture(
1166                 WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE);
1167         verify(mSelfRecovery, never()).trigger(eq(SelfRecovery.REASON_WIFINATIVE_FAILURE));
1168     }
1169 
1170     /**
1171      * Verify that mode stop is safe even if the underlying Client mode exited already.
1172      */
1173     @Test
shutdownWifiDoesNotCrashWhenClientModeExitsOnDestroyed()1174     public void shutdownWifiDoesNotCrashWhenClientModeExitsOnDestroyed() throws Exception {
1175         enterClientModeActiveState();
1176 
1177         mClientListener.onStopped(mClientModeManager);
1178         mLooper.dispatchAll();
1179 
1180         shutdownWifi();
1181 
1182         assertInDisabledState();
1183     }
1184 
1185     /**
1186      * Verify that an interface destruction callback is safe after already having been stopped.
1187      */
1188     @Test
onDestroyedCallbackDoesNotCrashWhenClientModeAlreadyStopped()1189     public void onDestroyedCallbackDoesNotCrashWhenClientModeAlreadyStopped() throws Exception {
1190         enterClientModeActiveState();
1191 
1192         shutdownWifi();
1193 
1194         mClientListener.onStopped(mClientModeManager);
1195         mLooper.dispatchAll();
1196 
1197         assertInDisabledState();
1198     }
1199 
1200     /**
1201      * Verify that mode stop is safe even if the underlying softap mode exited already.
1202      */
1203     @Test
shutdownWifiDoesNotCrashWhenSoftApExitsOnDestroyed()1204     public void shutdownWifiDoesNotCrashWhenSoftApExitsOnDestroyed() throws Exception {
1205         enterSoftApActiveMode();
1206 
1207         mSoftApListener.onStopped(mSoftApManager);
1208         mLooper.dispatchAll();
1209         mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
1210         mLooper.dispatchAll();
1211 
1212         shutdownWifi();
1213 
1214         verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
1215     }
1216 
1217     /**
1218      * Verify that an interface destruction callback is safe after already having been stopped.
1219      */
1220     @Test
onDestroyedCallbackDoesNotCrashWhenSoftApModeAlreadyStopped()1221     public void onDestroyedCallbackDoesNotCrashWhenSoftApModeAlreadyStopped() throws Exception {
1222         enterSoftApActiveMode();
1223 
1224         shutdownWifi();
1225 
1226         mSoftApListener.onStopped(mSoftApManager);
1227         mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
1228         mLooper.dispatchAll();
1229 
1230         verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
1231         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
1232     }
1233 
1234     /**
1235      * Verify that we do not crash when calling dump and wifi is fully disabled.
1236      */
1237     @Test
dumpWhenWifiFullyOffDoesNotCrash()1238     public void dumpWhenWifiFullyOffDoesNotCrash() throws Exception {
1239         ByteArrayOutputStream stream = new ByteArrayOutputStream();
1240         PrintWriter writer = new PrintWriter(stream);
1241         mActiveModeWarden.dump(null, writer, null);
1242     }
1243 
1244     /**
1245      * Verify that we trigger dump on active mode managers.
1246      */
1247     @Test
dumpCallsActiveModeManagers()1248     public void dumpCallsActiveModeManagers() throws Exception {
1249         enterSoftApActiveMode();
1250         enterClientModeActiveState();
1251 
1252         ByteArrayOutputStream stream = new ByteArrayOutputStream();
1253         PrintWriter writer = new PrintWriter(stream);
1254         mActiveModeWarden.dump(null, writer, null);
1255 
1256         verify(mSoftApManager).dump(null, writer, null);
1257         verify(mClientModeManager).dump(null, writer, null);
1258     }
1259 
1260     /**
1261      * Verify that stopping tethering doesn't stop LOHS.
1262      */
1263     @Test
testStopTetheringButNotLOHS()1264     public void testStopTetheringButNotLOHS() throws Exception {
1265         // prepare WiFi configurations
1266         when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
1267         SoftApModeConfiguration tetherConfig =
1268                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
1269                 mSoftApCapability, TEST_COUNTRYCODE);
1270         SoftApConfiguration lohsConfigWC = mWifiApConfigStore.generateLocalOnlyHotspotConfig(
1271                 mContext, null, mSoftApCapability);
1272         SoftApModeConfiguration lohsConfig =
1273                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_LOCAL_ONLY, lohsConfigWC,
1274                 mSoftApCapability, TEST_COUNTRYCODE);
1275 
1276         // mock SoftAPManagers
1277         when(mSoftApManager.getRole()).thenReturn(ROLE_SOFTAP_TETHERED);
1278         doAnswer(new Answer<SoftApManager>() {
1279             public SoftApManager answer(InvocationOnMock invocation) {
1280                 Object[] args = invocation.getArguments();
1281                 mSoftApListener = (Listener<SoftApManager>) args[0];
1282                 return mSoftApManager;
1283             }
1284         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
1285                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(tetherConfig),
1286                 eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
1287         // make a second softap manager
1288         SoftApManager lohsSoftapManager = mock(SoftApManager.class);
1289         when(lohsSoftapManager.getRole()).thenReturn(ROLE_SOFTAP_LOCAL_ONLY);
1290         Mutable<Listener<SoftApManager>> lohsSoftApListener = new Mutable<>();
1291         doAnswer(new Answer<SoftApManager>() {
1292             public SoftApManager answer(InvocationOnMock invocation) {
1293                 Object[] args = invocation.getArguments();
1294                 lohsSoftApListener.value = (Listener<SoftApManager>) args[0];
1295                 return lohsSoftapManager;
1296             }
1297         }).when(mWifiInjector).makeSoftApManager(any(Listener.class),
1298                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(lohsConfig),
1299                 eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_LOCAL_ONLY), anyBoolean());
1300 
1301         // enable tethering and LOHS
1302         mActiveModeWarden.startSoftAp(tetherConfig, TEST_WORKSOURCE);
1303         mLooper.dispatchAll();
1304         mSoftApListener.onStarted(mSoftApManager);
1305         mActiveModeWarden.startSoftAp(lohsConfig, TEST_WORKSOURCE);
1306         mLooper.dispatchAll();
1307         lohsSoftApListener.value.onStarted(lohsSoftapManager);
1308         verify(mWifiInjector).makeSoftApManager(any(Listener.class),
1309                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(tetherConfig),
1310                 eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
1311         verify(mWifiInjector).makeSoftApManager(any(Listener.class),
1312                 any(WifiServiceImpl.SoftApCallbackInternal.class), eq(lohsConfig),
1313                 eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_LOCAL_ONLY), anyBoolean());
1314         verify(mBatteryStats).reportWifiOn();
1315 
1316         // disable tethering
1317         mActiveModeWarden.stopSoftAp(WifiManager.IFACE_IP_MODE_TETHERED);
1318         mLooper.dispatchAll();
1319         verify(mSoftApManager).stop();
1320         verify(lohsSoftapManager, never()).stop();
1321 
1322         mSoftApListener.onStopped(mSoftApManager);
1323         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
1324     }
1325 
1326     /**
1327      * Verify that toggling wifi from disabled starts client mode.
1328      */
1329     @Test
enableWifi()1330     public void enableWifi() throws Exception {
1331         assertInDisabledState();
1332 
1333         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
1334         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
1335         mLooper.dispatchAll();
1336 
1337         verify(mWifiInjector).makeClientModeManager(
1338                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY),
1339                 anyBoolean());
1340         mClientListener.onStarted(mClientModeManager);
1341         mLooper.dispatchAll();
1342 
1343         // always set primary, even with single STA
1344         verify(mWifiNative).setMultiStaPrimaryConnection(WIFI_IFACE_NAME);
1345 
1346         assertInEnabledState();
1347     }
1348 
1349     /**
1350      * Test verifying that we can enter scan mode when the scan mode changes
1351      */
1352     @Test
enableScanMode()1353     public void enableScanMode() throws Exception {
1354         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1355         mActiveModeWarden.scanAlwaysModeChanged();
1356         mLooper.dispatchAll();
1357         verify(mWifiInjector).makeClientModeManager(
1358                 any(), eq(new WorkSource(Process.WIFI_UID)), eq(ROLE_CLIENT_SCAN_ONLY),
1359                 anyBoolean());
1360         assertInEnabledState();
1361         verify(mClientModeManager, never()).stop();
1362     }
1363 
1364     /**
1365      * Test verifying that we ignore scan enable event when wifi is already enabled.
1366      */
1367     @Test
ignoreEnableScanModeWhenWifiEnabled()1368     public void ignoreEnableScanModeWhenWifiEnabled() throws Exception {
1369         // Turn on WIFI
1370         assertInDisabledState();
1371         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
1372         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
1373         mLooper.dispatchAll();
1374         mClientListener.onStarted(mClientModeManager);
1375         mLooper.dispatchAll();
1376         assertInEnabledState();
1377 
1378         // Now toggle scan only change, should be ignored. We should send a role change
1379         // again with PRIMARY & the cached requestorWs.
1380         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1381         mActiveModeWarden.scanAlwaysModeChanged();
1382         mLooper.dispatchAll();
1383         verify(mClientModeManager).setRole(ROLE_CLIENT_PRIMARY, TEST_WORKSOURCE);
1384         assertInEnabledState();
1385         verify(mClientModeManager, never()).stop();
1386     }
1387 
1388     /**
1389      * Verify that if scanning is enabled at startup, we enter scan mode
1390      */
1391     @Test
testEnterScanModeAtStartWhenSet()1392     public void testEnterScanModeAtStartWhenSet() throws Exception {
1393         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1394 
1395         mActiveModeWarden = createActiveModeWarden();
1396         mActiveModeWarden.start();
1397         mLooper.dispatchAll();
1398 
1399         assertInEnabledState();
1400     }
1401 
1402     /**
1403      * Verify that if Wifi is enabled at startup, we enter client mode
1404      */
1405     @Test
testEnterClientModeAtStartWhenSet()1406     public void testEnterClientModeAtStartWhenSet() throws Exception {
1407         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
1408 
1409         mActiveModeWarden = createActiveModeWarden();
1410         mActiveModeWarden.start();
1411         mLooper.dispatchAll();
1412 
1413         verify(mWifiMetrics).noteWifiEnabledDuringBoot(true);
1414 
1415         assertInEnabledState();
1416 
1417         verify(mWifiInjector)
1418                 .makeClientModeManager(any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1419     }
1420 
1421     /**
1422      * Do not enter scan mode if location mode disabled.
1423      */
1424     @Test
testDoesNotEnterScanModeWhenLocationModeDisabled()1425     public void testDoesNotEnterScanModeWhenLocationModeDisabled() throws Exception {
1426         // Start a new WifiController with wifi disabled
1427         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
1428         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
1429         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
1430 
1431         mActiveModeWarden = createActiveModeWarden();
1432         mActiveModeWarden.start();
1433         mLooper.dispatchAll();
1434 
1435         assertInDisabledState();
1436 
1437         // toggling scan always available is not sufficient for scan mode
1438         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1439         mActiveModeWarden.scanAlwaysModeChanged();
1440         mLooper.dispatchAll();
1441 
1442         assertInDisabledState();
1443     }
1444 
1445     /**
1446      * Only enter scan mode if location mode enabled
1447      */
1448     @Test
testEnterScanModeWhenLocationModeEnabled()1449     public void testEnterScanModeWhenLocationModeEnabled() throws Exception {
1450         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1451         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
1452 
1453         reset(mContext);
1454         when(mContext.getResources()).thenReturn(mResources);
1455         mActiveModeWarden = createActiveModeWarden();
1456         mActiveModeWarden.start();
1457         mLooper.dispatchAll();
1458 
1459         ArgumentCaptor<BroadcastReceiver> bcastRxCaptor =
1460                 ArgumentCaptor.forClass(BroadcastReceiver.class);
1461         verify(mContext).registerReceiver(
1462                 bcastRxCaptor.capture(),
1463                 argThat(filter -> filter.hasAction(LocationManager.MODE_CHANGED_ACTION)));
1464         BroadcastReceiver broadcastReceiver = bcastRxCaptor.getValue();
1465 
1466         assertInDisabledState();
1467 
1468         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
1469         Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
1470         broadcastReceiver.onReceive(mContext, intent);
1471         mLooper.dispatchAll();
1472 
1473         assertInEnabledState();
1474     }
1475 
1476     /**
1477      * Do not change Wi-Fi state when airplane mode changes if
1478      * DISALLOW_CHANGE_WIFI_STATE user restriction is set.
1479      */
1480     @Test
testWifiStateUnaffectedByAirplaneMode()1481     public void testWifiStateUnaffectedByAirplaneMode() throws Exception {
1482         assumeTrue(SdkLevel.isAtLeastT());
1483         when(mUserManager.hasUserRestrictionForUser(eq(UserManager.DISALLOW_CHANGE_WIFI_STATE),
1484                 any())).thenReturn(true);
1485         when(mSettingsStore.updateAirplaneModeTracker()).thenReturn(true);
1486 
1487         reset(mContext);
1488         when(mContext.getResources()).thenReturn(mResources);
1489         mActiveModeWarden = createActiveModeWarden();
1490         mActiveModeWarden.start();
1491         mLooper.dispatchAll();
1492 
1493         ArgumentCaptor<BroadcastReceiver> bcastRxCaptor =
1494                 ArgumentCaptor.forClass(BroadcastReceiver.class);
1495         verify(mContext).registerReceiver(
1496                 bcastRxCaptor.capture(),
1497                 argThat(filter -> filter.hasAction(Intent.ACTION_AIRPLANE_MODE_CHANGED)));
1498         BroadcastReceiver broadcastReceiver = bcastRxCaptor.getValue();
1499 
1500         Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
1501         broadcastReceiver.onReceive(mContext, intent);
1502         mLooper.dispatchAll();
1503 
1504         verify(mSettingsStore, never()).handleAirplaneModeToggled();
1505 
1506         when(mUserManager.hasUserRestrictionForUser(eq(UserManager.DISALLOW_CHANGE_WIFI_STATE),
1507                 any())).thenReturn(false);
1508         broadcastReceiver.onReceive(mContext, intent);
1509         mLooper.dispatchAll();
1510 
1511         verify(mSettingsStore).handleAirplaneModeToggled();
1512         verify(mLastCallerInfoManager, never()).put(eq(WifiManager.API_WIFI_ENABLED),
1513                 anyInt(), anyInt(), anyInt(), any(), anyBoolean());
1514     }
1515 
1516     /**
1517      * Wi-Fi remains on when airplane mode changes if airplane mode enhancement is enabled.
1518      */
1519     @Test
testWifiRemainsOnAirplaneModeEnhancement()1520     public void testWifiRemainsOnAirplaneModeEnhancement() throws Exception {
1521         enterClientModeActiveState();
1522         assertInEnabledState();
1523         when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
1524 
1525         // Wi-Fi remains on when APM enhancement enabled
1526         assertWifiShutDown(() -> {
1527             when(mSettingsStore.shouldWifiRemainEnabledWhenApmEnabled()).thenReturn(true);
1528             mActiveModeWarden.airplaneModeToggled();
1529             mLooper.dispatchAll();
1530         }, 0);
1531         verify(mLastCallerInfoManager, never()).put(eq(WifiManager.API_WIFI_ENABLED),
1532                 anyInt(), anyInt(), anyInt(), any(), anyBoolean());
1533 
1534         // Wi-Fi shuts down when APM enhancement disabled
1535         assertWifiShutDown(() -> {
1536             when(mSettingsStore.shouldWifiRemainEnabledWhenApmEnabled()).thenReturn(false);
1537             mActiveModeWarden.airplaneModeToggled();
1538             mLooper.dispatchAll();
1539         });
1540         verify(mLastCallerInfoManager).put(eq(WifiManager.API_WIFI_ENABLED), anyInt(), anyInt(),
1541                 anyInt(), eq("android_apm"), eq(false));
1542     }
1543 
1544     /**
1545      * Disabling location mode when in scan mode will disable wifi
1546      */
1547     @Test
testExitScanModeWhenLocationModeDisabled()1548     public void testExitScanModeWhenLocationModeDisabled() throws Exception {
1549         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1550         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
1551         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
1552 
1553         reset(mContext);
1554         when(mContext.getResources()).thenReturn(mResources);
1555         mActiveModeWarden = createActiveModeWarden();
1556         mActiveModeWarden.start();
1557         mLooper.dispatchAll();
1558         mClientListener.onStarted(mClientModeManager);
1559         mLooper.dispatchAll();
1560 
1561         ArgumentCaptor<BroadcastReceiver> bcastRxCaptor =
1562                 ArgumentCaptor.forClass(BroadcastReceiver.class);
1563         verify(mContext).registerReceiver(
1564                 bcastRxCaptor.capture(),
1565                 argThat(filter -> filter.hasAction(LocationManager.MODE_CHANGED_ACTION)));
1566         BroadcastReceiver broadcastReceiver = bcastRxCaptor.getValue();
1567 
1568         assertInEnabledState();
1569 
1570         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
1571         Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
1572         broadcastReceiver.onReceive(mContext, intent);
1573         mLooper.dispatchAll();
1574 
1575         mClientListener.onStopped(mClientModeManager);
1576         mLooper.dispatchAll();
1577 
1578         assertInDisabledState();
1579     }
1580 
1581     /**
1582      * When in Client mode, make sure ECM triggers wifi shutdown.
1583      */
1584     @Test
testEcmOnFromClientMode()1585     public void testEcmOnFromClientMode() throws Exception {
1586         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
1587         enableWifi();
1588 
1589         // Test with WifiDisableInECBM turned on:
1590         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1591 
1592         assertWifiShutDown(() -> {
1593             // test ecm changed
1594             emergencyCallbackModeChanged(true);
1595             mLooper.dispatchAll();
1596         });
1597     }
1598 
1599     /**
1600      * ECM disabling messages, when in client mode (not expected) do not trigger state changes.
1601      */
1602     @Test
testEcmOffInClientMode()1603     public void testEcmOffInClientMode() throws Exception {
1604         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
1605         enableWifi();
1606 
1607         // Test with WifiDisableInECBM turned off
1608         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
1609 
1610         assertEnteredEcmMode(() -> {
1611             // test ecm changed
1612             emergencyCallbackModeChanged(true);
1613             mLooper.dispatchAll();
1614         });
1615     }
1616 
1617     /**
1618      * When ECM activates and we are in client mode, disabling ECM should return us to client mode.
1619      */
1620     @Test
testEcmDisabledReturnsToClientMode()1621     public void testEcmDisabledReturnsToClientMode() throws Exception {
1622         enableWifi();
1623         assertInEnabledState();
1624 
1625         // Test with WifiDisableInECBM turned on:
1626         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1627 
1628         assertWifiShutDown(() -> {
1629             // test ecm changed
1630             emergencyCallbackModeChanged(true);
1631             mLooper.dispatchAll();
1632         });
1633 
1634         // test ecm changed
1635         emergencyCallbackModeChanged(false);
1636         mLooper.dispatchAll();
1637 
1638         assertInEnabledState();
1639     }
1640 
1641     /**
1642      * When Ecm mode is enabled, we should shut down wifi when we get an emergency mode changed
1643      * update.
1644      */
1645     @Test
testEcmOnFromScanMode()1646     public void testEcmOnFromScanMode() throws Exception {
1647         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1648         mActiveModeWarden.scanAlwaysModeChanged();
1649         mLooper.dispatchAll();
1650 
1651         mClientListener.onStarted(mClientModeManager);
1652         mLooper.dispatchAll();
1653 
1654         assertInEnabledState();
1655 
1656         // Test with WifiDisableInECBM turned on:
1657         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1658 
1659         assertWifiShutDown(() -> {
1660             // test ecm changed
1661             emergencyCallbackModeChanged(true);
1662             mLooper.dispatchAll();
1663         });
1664     }
1665 
1666     /**
1667      * When Ecm mode is disabled, we should not shut down scan mode if we get an emergency mode
1668      * changed update, but we should turn off soft AP
1669      */
1670     @Test
testEcmOffInScanMode()1671     public void testEcmOffInScanMode() throws Exception {
1672         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1673         mActiveModeWarden.scanAlwaysModeChanged();
1674         mLooper.dispatchAll();
1675 
1676         assertInEnabledState();
1677 
1678         // Test with WifiDisableInECBM turned off:
1679         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
1680 
1681         assertEnteredEcmMode(() -> {
1682             // test ecm changed
1683             emergencyCallbackModeChanged(true);
1684             mLooper.dispatchAll();
1685         });
1686     }
1687 
1688     /**
1689      * When ECM is disabled, we should return to scan mode
1690      */
1691     @Test
testEcmDisabledReturnsToScanMode()1692     public void testEcmDisabledReturnsToScanMode() throws Exception {
1693         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
1694         mActiveModeWarden.scanAlwaysModeChanged();
1695         mLooper.dispatchAll();
1696 
1697         assertInEnabledState();
1698 
1699         // Test with WifiDisableInECBM turned on:
1700         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1701 
1702         assertWifiShutDown(() -> {
1703             // test ecm changed
1704             emergencyCallbackModeChanged(true);
1705             mLooper.dispatchAll();
1706         });
1707 
1708         // test ecm changed
1709         emergencyCallbackModeChanged(false);
1710         mLooper.dispatchAll();
1711 
1712         assertInEnabledState();
1713     }
1714 
1715     /**
1716      * When Ecm mode is enabled, we should shut down wifi when we get an emergency mode changed
1717      * update.
1718      */
1719     @Test
testEcmOnFromSoftApMode()1720     public void testEcmOnFromSoftApMode() throws Exception {
1721         enterSoftApActiveMode();
1722 
1723         // Test with WifiDisableInECBM turned on:
1724         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1725 
1726         assertEnteredEcmMode(() -> {
1727             // test ecm changed
1728             emergencyCallbackModeChanged(true);
1729             mLooper.dispatchAll();
1730         });
1731     }
1732 
1733     /**
1734      * When Ecm mode is disabled, we should shut down softap mode if we get an emergency mode
1735      * changed update
1736      */
1737     @Test
testEcmOffInSoftApMode()1738     public void testEcmOffInSoftApMode() throws Exception {
1739         enterSoftApActiveMode();
1740 
1741         // Test with WifiDisableInECBM turned off:
1742         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
1743 
1744         // test ecm changed
1745         emergencyCallbackModeChanged(true);
1746         mLooper.dispatchAll();
1747 
1748         verify(mSoftApManager).stop();
1749     }
1750 
1751     /**
1752      * When ECM is activated and we were in softap mode, we should just return to wifi off when ECM
1753      * ends
1754      */
1755     @Test
testEcmDisabledRemainsDisabledWhenSoftApHadBeenOn()1756     public void testEcmDisabledRemainsDisabledWhenSoftApHadBeenOn() throws Exception {
1757         assertInDisabledState();
1758 
1759         enterSoftApActiveMode();
1760 
1761         // verify Soft AP Manager started
1762         verify(mWifiInjector).makeSoftApManager(
1763                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
1764 
1765         // Test with WifiDisableInECBM turned on:
1766         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1767 
1768         assertEnteredEcmMode(() -> {
1769             // test ecm changed
1770             emergencyCallbackModeChanged(true);
1771             mLooper.dispatchAll();
1772             mSoftApListener.onStopped(mSoftApManager);
1773             mLooper.dispatchAll();
1774         });
1775 
1776         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
1777 
1778         // test ecm changed
1779         emergencyCallbackModeChanged(false);
1780         mLooper.dispatchAll();
1781 
1782         assertInDisabledState();
1783 
1784         // verify no additional calls to enable softap
1785         verify(mWifiInjector).makeSoftApManager(
1786                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
1787     }
1788 
1789     /**
1790      * Wifi should remain off when already disabled and we enter ECM.
1791      */
1792     @Test
testEcmOnFromDisabledMode()1793     public void testEcmOnFromDisabledMode() throws Exception {
1794         assertInDisabledState();
1795         verify(mWifiInjector, never()).makeSoftApManager(
1796                 any(), any(), any(), any(), any(), anyBoolean());
1797         verify(mWifiInjector, never()).makeClientModeManager(
1798                 any(), any(), any(), anyBoolean());
1799 
1800         // Test with WifiDisableInECBM turned on:
1801         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1802 
1803         assertEnteredEcmMode(() -> {
1804             // test ecm changed
1805             emergencyCallbackModeChanged(true);
1806             mLooper.dispatchAll();
1807         });
1808     }
1809 
1810 
1811     /**
1812      * Updates about call state change also trigger entry of ECM mode.
1813      */
1814     @Test
testEnterEcmOnEmergencyCallStateChange()1815     public void testEnterEcmOnEmergencyCallStateChange() throws Exception {
1816         assertInDisabledState();
1817 
1818         enableWifi();
1819         assertInEnabledState();
1820 
1821         // Test with WifiDisableInECBM turned on:
1822         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1823 
1824         assertEnteredEcmMode(() -> {
1825             // test call state changed
1826             emergencyCallStateChanged(true);
1827             mLooper.dispatchAll();
1828             mClientListener.onStopped(mClientModeManager);
1829             mLooper.dispatchAll();
1830         });
1831 
1832         emergencyCallStateChanged(false);
1833         mLooper.dispatchAll();
1834 
1835         assertInEnabledState();
1836     }
1837 
1838     /**
1839      * Verify when both ECM and call state changes arrive, we enter ECM mode
1840      */
1841     @Test
testEnterEcmWithBothSignals()1842     public void testEnterEcmWithBothSignals() throws Exception {
1843         assertInDisabledState();
1844 
1845         enableWifi();
1846         assertInEnabledState();
1847 
1848         // Test with WifiDisableInECBM turned on:
1849         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1850 
1851         assertWifiShutDown(() -> {
1852             emergencyCallStateChanged(true);
1853             mLooper.dispatchAll();
1854             mClientListener.onStopped(mClientModeManager);
1855             mLooper.dispatchAll();
1856         });
1857 
1858         assertWifiShutDown(() -> {
1859             emergencyCallbackModeChanged(true);
1860             mLooper.dispatchAll();
1861         }, 0); // does not cause another shutdown
1862 
1863         // client mode only started once so far
1864         verify(mWifiInjector).makeClientModeManager(
1865                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1866 
1867         emergencyCallStateChanged(false);
1868         mLooper.dispatchAll();
1869 
1870         // stay in ecm, do not send an additional client mode trigger
1871         assertInEmergencyMode();
1872         // assert that the underlying state is in disabled state
1873         assertInDisabledState();
1874 
1875         // client mode still only started once
1876         verify(mWifiInjector).makeClientModeManager(
1877                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1878 
1879         emergencyCallbackModeChanged(false);
1880         mLooper.dispatchAll();
1881 
1882         // now we can re-enable wifi
1883         verify(mWifiInjector, times(2)).makeClientModeManager(
1884                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1885         assertInEnabledState();
1886     }
1887 
1888     /**
1889      * Verify when both ECM and call state changes arrive but out of order, we enter ECM mode
1890      */
1891     @Test
testEnterEcmWithBothSignalsOutOfOrder()1892     public void testEnterEcmWithBothSignalsOutOfOrder() throws Exception {
1893         assertInDisabledState();
1894 
1895         enableWifi();
1896 
1897         assertInEnabledState();
1898         verify(mWifiInjector).makeClientModeManager(
1899                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1900 
1901         // Test with WifiDisableInECBM turned on:
1902         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1903 
1904         assertEnteredEcmMode(() -> {
1905             emergencyCallbackModeChanged(true);
1906             mLooper.dispatchAll();
1907             mClientListener.onStopped(mClientModeManager);
1908             mLooper.dispatchAll();
1909         });
1910         assertInDisabledState();
1911 
1912         assertEnteredEcmMode(() -> {
1913             emergencyCallStateChanged(true);
1914             mLooper.dispatchAll();
1915         }, 0); // does not enter ECM state again
1916 
1917         emergencyCallStateChanged(false);
1918         mLooper.dispatchAll();
1919 
1920         // stay in ecm, do not send an additional client mode trigger
1921         assertInEmergencyMode();
1922         // assert that the underlying state is in disabled state
1923         assertInDisabledState();
1924 
1925         // client mode still only started once
1926         verify(mWifiInjector).makeClientModeManager(
1927                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1928 
1929         emergencyCallbackModeChanged(false);
1930         mLooper.dispatchAll();
1931 
1932         // now we can re-enable wifi
1933         verify(mWifiInjector, times(2)).makeClientModeManager(
1934                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1935         assertInEnabledState();
1936     }
1937 
1938     /**
1939      * Verify when both ECM and call state changes arrive but completely out of order,
1940      * we still enter and properly exit ECM mode
1941      */
1942     @Test
testEnterEcmWithBothSignalsOppositeOrder()1943     public void testEnterEcmWithBothSignalsOppositeOrder() throws Exception {
1944         assertInDisabledState();
1945 
1946         enableWifi();
1947 
1948         assertInEnabledState();
1949         verify(mWifiInjector).makeClientModeManager(
1950                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1951 
1952         // Test with WifiDisableInECBM turned on:
1953         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
1954 
1955         assertEnteredEcmMode(() -> {
1956             emergencyCallStateChanged(true);
1957             mLooper.dispatchAll();
1958             mClientListener.onStopped(mClientModeManager);
1959             mLooper.dispatchAll();
1960         });
1961         assertInDisabledState();
1962 
1963         assertEnteredEcmMode(() -> {
1964             emergencyCallbackModeChanged(true);
1965             mLooper.dispatchAll();
1966         }, 0); // still only 1 shutdown
1967 
1968         emergencyCallbackModeChanged(false);
1969         mLooper.dispatchAll();
1970 
1971         // stay in ecm, do not send an additional client mode trigger
1972         assertInEmergencyMode();
1973         // assert that the underlying state is in disabled state
1974         assertInDisabledState();
1975 
1976         // client mode still only started once
1977         verify(mWifiInjector).makeClientModeManager(
1978                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1979 
1980         emergencyCallStateChanged(false);
1981         mLooper.dispatchAll();
1982 
1983         // now we can re-enable wifi
1984         verify(mWifiInjector, times(2)).makeClientModeManager(
1985                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
1986         assertInEnabledState();
1987     }
1988 
1989     /**
1990      * When ECM is active, we might get addition signals of ECM mode, drop those additional signals,
1991      * we must exit when one of each signal is received.
1992      *
1993      * In any case, duplicate signals indicate a bug from Telephony. Each signal should be turned
1994      * off before it is turned on again.
1995      */
1996     @Test
testProperExitFromEcmModeWithMultipleMessages()1997     public void testProperExitFromEcmModeWithMultipleMessages() throws Exception {
1998         assertInDisabledState();
1999 
2000         enableWifi();
2001 
2002         verify(mWifiInjector).makeClientModeManager(
2003                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2004         assertInEnabledState();
2005 
2006         // Test with WifiDisableInECBM turned on:
2007         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2008 
2009         assertEnteredEcmMode(() -> {
2010             emergencyCallbackModeChanged(true);
2011             emergencyCallStateChanged(true);
2012             emergencyCallStateChanged(true);
2013             emergencyCallbackModeChanged(true);
2014             emergencyCallbackModeChanged(true);
2015             mLooper.dispatchAll();
2016             mClientListener.onStopped(mClientModeManager);
2017             mLooper.dispatchAll();
2018         });
2019         assertInDisabledState();
2020 
2021         assertEnteredEcmMode(() -> {
2022             emergencyCallbackModeChanged(false);
2023             mLooper.dispatchAll();
2024             emergencyCallbackModeChanged(false);
2025             mLooper.dispatchAll();
2026             emergencyCallbackModeChanged(false);
2027             mLooper.dispatchAll();
2028             emergencyCallbackModeChanged(false);
2029             mLooper.dispatchAll();
2030         }, 0);
2031 
2032         // didn't enter client mode again
2033         verify(mWifiInjector).makeClientModeManager(
2034                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2035         assertInDisabledState();
2036 
2037         // now we will exit ECM
2038         emergencyCallStateChanged(false);
2039         mLooper.dispatchAll();
2040 
2041         // now we can re-enable wifi
2042         verify(mWifiInjector, times(2)).makeClientModeManager(
2043                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2044         assertInEnabledState();
2045     }
2046 
2047     /**
2048      * Toggling wifi on when in ECM does not exit ecm mode and enable wifi
2049      */
2050     @Test
testWifiDoesNotToggleOnWhenInEcm()2051     public void testWifiDoesNotToggleOnWhenInEcm() throws Exception {
2052         assertInDisabledState();
2053 
2054         // Test with WifiDisableInECBM turned on:
2055         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2056         // test ecm changed
2057         assertEnteredEcmMode(() -> {
2058             emergencyCallbackModeChanged(true);
2059             mLooper.dispatchAll();
2060         });
2061 
2062         // now toggle wifi and verify we do not start wifi
2063         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
2064         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
2065         mLooper.dispatchAll();
2066 
2067         verify(mWifiInjector, never()).makeClientModeManager(
2068                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2069         assertInDisabledState();
2070         assertInEmergencyMode();
2071 
2072         // now we will exit ECM
2073         emergencyCallbackModeChanged(false);
2074         mLooper.dispatchAll();
2075         assertNotInEmergencyMode();
2076 
2077         // Wifi toggle on now takes effect
2078         verify(mWifiInjector).makeClientModeManager(
2079                 any(), eq(SETTINGS_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2080         assertInEnabledState();
2081     }
2082 
2083     /**
2084      * Toggling wifi off when in ECM does not disable wifi when getConfigWiFiDisableInECBM is
2085      * disabled.
2086      */
2087     @Test
testWifiDoesNotToggleOffWhenInEcmAndConfigDisabled()2088     public void testWifiDoesNotToggleOffWhenInEcmAndConfigDisabled() throws Exception {
2089         enableWifi();
2090         assertInEnabledState();
2091         verify(mWifiInjector).makeClientModeManager(
2092                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2093 
2094         // Test with WifiDisableInECBM turned off
2095         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
2096         // test ecm changed
2097         assertEnteredEcmMode(() -> {
2098             emergencyCallbackModeChanged(true);
2099             mLooper.dispatchAll();
2100         });
2101 
2102         // now toggle wifi and verify we do not start wifi
2103         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
2104         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
2105         mLooper.dispatchAll();
2106 
2107         // still only called once
2108         verify(mWifiInjector).makeClientModeManager(
2109                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2110         verify(mClientModeManager, never()).stop();
2111         assertInEnabledState();
2112         assertInEmergencyMode();
2113 
2114         // now we will exit ECM
2115         emergencyCallbackModeChanged(false);
2116         mLooper.dispatchAll();
2117         assertNotInEmergencyMode();
2118 
2119         // Wifi toggle off now takes effect
2120         verify(mClientModeManager).stop();
2121         mClientListener.onStopped(mClientModeManager);
2122         mLooper.dispatchAll();
2123         assertInDisabledState();
2124     }
2125 
2126     @Test
testAirplaneModeDoesNotToggleOnWhenInEcm()2127     public void testAirplaneModeDoesNotToggleOnWhenInEcm() throws Exception {
2128         // TODO(b/139829963): investigate the expected behavior is when toggling airplane mode in
2129         //  ECM
2130     }
2131 
2132     /**
2133      * Toggling scan mode when in ECM does not exit ecm mode and enable scan mode
2134      */
2135     @Test
testScanModeDoesNotToggleOnWhenInEcm()2136     public void testScanModeDoesNotToggleOnWhenInEcm() throws Exception {
2137         assertInDisabledState();
2138 
2139         // Test with WifiDisableInECBM turned on:
2140         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2141         assertEnteredEcmMode(() -> {
2142             // test ecm changed
2143             emergencyCallbackModeChanged(true);
2144             mLooper.dispatchAll();
2145         });
2146 
2147         // now enable scanning and verify we do not start wifi
2148         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
2149         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
2150         mActiveModeWarden.scanAlwaysModeChanged();
2151         mLooper.dispatchAll();
2152 
2153         verify(mWifiInjector, never()).makeClientModeManager(
2154                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2155         assertInDisabledState();
2156     }
2157 
2158 
2159     /**
2160      * Toggling softap mode when in ECM does not exit ecm mode and enable softap
2161      */
2162     @Test
testSoftApModeDoesNotToggleOnWhenInEcm()2163     public void testSoftApModeDoesNotToggleOnWhenInEcm() throws Exception {
2164         assertInDisabledState();
2165 
2166         // Test with WifiDisableInECBM turned on:
2167         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2168         assertEnteredEcmMode(() -> {
2169             // test ecm changed
2170             emergencyCallbackModeChanged(true);
2171             mLooper.dispatchAll();
2172         });
2173 
2174         // try to start Soft AP
2175         mActiveModeWarden.startSoftAp(
2176                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
2177                 mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE);
2178         mLooper.dispatchAll();
2179 
2180         verify(mWifiInjector, never())
2181                 .makeSoftApManager(any(), any(), any(), eq(TEST_WORKSOURCE), any(), anyBoolean());
2182         assertInDisabledState();
2183 
2184         // verify triggered Soft AP failure callback
2185         verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
2186                 WifiManager.SAP_START_FAILURE_GENERAL);
2187 
2188         // try to start LOHS
2189         mActiveModeWarden.startSoftAp(
2190                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_LOCAL_ONLY, null,
2191                 mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE);
2192         mLooper.dispatchAll();
2193 
2194         verify(mWifiInjector, never())
2195                 .makeSoftApManager(any(), any(), any(), eq(TEST_WORKSOURCE), any(), anyBoolean());
2196         assertInDisabledState();
2197 
2198         // verify triggered LOHS failure callback
2199         verify(mLohsStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
2200                 WifiManager.SAP_START_FAILURE_GENERAL);
2201     }
2202 
2203     /**
2204      * Toggling off softap mode when in ECM does not induce a mode change
2205      */
2206     @Test
testSoftApStoppedDoesNotSwitchModesWhenInEcm()2207     public void testSoftApStoppedDoesNotSwitchModesWhenInEcm() throws Exception {
2208         assertInDisabledState();
2209 
2210         // Test with WifiDisableInECBM turned on:
2211         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2212         assertEnteredEcmMode(() -> {
2213             // test ecm changed
2214             emergencyCallbackModeChanged(true);
2215             mLooper.dispatchAll();
2216         });
2217 
2218         mActiveModeWarden.stopSoftAp(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
2219         mLooper.dispatchAll();
2220 
2221         assertInDisabledState();
2222         verifyNoMoreInteractions(mSoftApManager, mClientModeManager);
2223     }
2224 
2225     /**
2226      * Toggling softap mode when in airplane mode needs to enable softap
2227      */
2228     @Test
testSoftApModeToggleWhenInAirplaneMode()2229     public void testSoftApModeToggleWhenInAirplaneMode() throws Exception {
2230         // Test with airplane mode turned on:
2231         when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
2232 
2233         // Turn on SoftAp.
2234         mActiveModeWarden.startSoftAp(
2235                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
2236                 mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE);
2237         mLooper.dispatchAll();
2238         verify(mWifiInjector)
2239                 .makeSoftApManager(any(), any(), any(), eq(TEST_WORKSOURCE), any(), anyBoolean());
2240 
2241         // Turn off SoftAp.
2242         mActiveModeWarden.stopSoftAp(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
2243         mLooper.dispatchAll();
2244 
2245         verify(mSoftApManager).stop();
2246     }
2247 
2248     /**
2249      * Toggling off scan mode when in ECM does not induce a mode change
2250      */
2251     @Test
testScanModeStoppedSwitchModeToDisabledStateWhenInEcm()2252     public void testScanModeStoppedSwitchModeToDisabledStateWhenInEcm() throws Exception {
2253         enterScanOnlyModeActiveState();
2254         assertInEnabledState();
2255 
2256         // Test with WifiDisableInECBM turned on:
2257         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2258         assertEnteredEcmMode(() -> {
2259             // test ecm changed
2260             emergencyCallbackModeChanged(true);
2261             mLooper.dispatchAll();
2262             mClientListener.onStopped(mClientModeManager);
2263             mLooper.dispatchAll();
2264         });
2265 
2266         // Spurious onStopped
2267         mClientListener.onStopped(mClientModeManager);
2268         mLooper.dispatchAll();
2269 
2270         assertInDisabledState();
2271     }
2272 
2273     /**
2274      * Toggling off client mode when in ECM does not induce a mode change
2275      */
2276     @Test
testClientModeStoppedSwitchModeToDisabledStateWhenInEcm()2277     public void testClientModeStoppedSwitchModeToDisabledStateWhenInEcm() throws Exception {
2278         enterClientModeActiveState();
2279         assertInEnabledState();
2280 
2281         // Test with WifiDisableInECBM turned on:
2282         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2283         assertEnteredEcmMode(() -> {
2284             // test ecm changed
2285             emergencyCallbackModeChanged(true);
2286             mLooper.dispatchAll();
2287             mClientListener.onStopped(mClientModeManager);
2288             mLooper.dispatchAll();
2289         });
2290 
2291         // Spurious onStopped
2292         mClientListener.onStopped(mClientModeManager);
2293         mLooper.dispatchAll();
2294 
2295         assertInDisabledState();
2296     }
2297 
2298     /**
2299      * When AP mode is enabled and wifi was previously in AP mode, we should return to
2300      * EnabledState after the AP is disabled.
2301      * Enter EnabledState, activate AP mode, disable AP mode.
2302      * <p>
2303      * Expected: AP should successfully start and exit, then return to EnabledState.
2304      */
2305     @Test
testReturnToEnabledStateAfterAPModeShutdown()2306     public void testReturnToEnabledStateAfterAPModeShutdown() throws Exception {
2307         enableWifi();
2308         assertInEnabledState();
2309         verify(mWifiInjector).makeClientModeManager(
2310                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2311 
2312         mActiveModeWarden.startSoftAp(
2313                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
2314                 mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE);
2315         // add an "unexpected" sta mode stop to simulate a single interface device
2316         mClientListener.onStopped(mClientModeManager);
2317         mLooper.dispatchAll();
2318         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2319 
2320         // Now stop the AP
2321         mSoftApListener.onStopped(mSoftApManager);
2322         mLooper.dispatchAll();
2323         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
2324 
2325         // We should re-enable client mode
2326         verify(mWifiInjector, times(2)).makeClientModeManager(
2327                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2328         assertInEnabledState();
2329     }
2330 
2331     /**
2332      * When in STA mode and SoftAP is enabled and the device supports STA+AP (i.e. the STA wasn't
2333      * shut down when the AP started), both modes will be running concurrently.
2334      *
2335      * Then when the AP is disabled, we should remain in STA mode.
2336      *
2337      * Enter EnabledState, activate AP mode, toggle WiFi off.
2338      * <p>
2339      * Expected: AP should successfully start and exit, then return to EnabledState.
2340      */
2341     @Test
testReturnToEnabledStateAfterWifiEnabledShutdown()2342     public void testReturnToEnabledStateAfterWifiEnabledShutdown() throws Exception {
2343         enableWifi();
2344         assertInEnabledState();
2345         verify(mWifiInjector).makeClientModeManager(
2346                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2347 
2348         mActiveModeWarden.startSoftAp(
2349                 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null,
2350                 mSoftApCapability, TEST_COUNTRYCODE), TEST_WORKSOURCE);
2351         mLooper.dispatchAll();
2352 
2353         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
2354         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
2355         mSoftApListener.onStopped(mSoftApManager);
2356         mLooper.dispatchAll();
2357 
2358         // wasn't called again
2359         verify(mWifiInjector).makeClientModeManager(
2360                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2361         assertInEnabledState();
2362     }
2363 
2364     @Test
testRestartWifiStackInEnabledStateTriggersBugReport()2365     public void testRestartWifiStackInEnabledStateTriggersBugReport() throws Exception {
2366         enableWifi();
2367 
2368         // note: using a reason that will typical not start a bug report on purpose to guarantee
2369         // that it is the flag and not the reason which controls it.
2370         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_LAST_RESORT_WATCHDOG,
2371                 true);
2372         mLooper.dispatchAll();
2373         verify(mWifiDiagnostics).takeBugReport(anyString(), anyString());
2374         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2375     }
2376 
2377     @Test
testRestartWifiWatchdogDoesNotTriggerBugReport()2378     public void testRestartWifiWatchdogDoesNotTriggerBugReport() throws Exception {
2379         enableWifi();
2380         // note: using a reason that will typical start a bug report on purpose to guarantee that
2381         // it is the flag and not the reason which controls it.
2382         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2383                 false);
2384         mLooper.dispatchAll();
2385         verify(mWifiDiagnostics, never()).takeBugReport(anyString(), anyString());
2386         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2387     }
2388 
2389     /**
2390      * When in sta mode, CMD_RECOVERY_DISABLE_WIFI messages should trigger wifi to disable.
2391      */
2392     @Test
testRecoveryDisabledTurnsWifiOff()2393     public void testRecoveryDisabledTurnsWifiOff() throws Exception {
2394         enableWifi();
2395         assertInEnabledState();
2396         mActiveModeWarden.recoveryDisableWifi();
2397         mLooper.dispatchAll();
2398         verify(mClientModeManager).stop();
2399         mClientListener.onStopped(mClientModeManager);
2400         mLooper.dispatchAll();
2401         assertInDisabledState();
2402         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2403     }
2404 
2405     /**
2406      * When wifi is disabled, CMD_RECOVERY_DISABLE_WIFI should not trigger a state change.
2407      */
2408     @Test
testRecoveryDisabledWhenWifiAlreadyOff()2409     public void testRecoveryDisabledWhenWifiAlreadyOff() throws Exception {
2410         assertInDisabledState();
2411         assertWifiShutDown(() -> {
2412             mActiveModeWarden.recoveryDisableWifi();
2413             mLooper.dispatchAll();
2414         });
2415         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS + 10);
2416         mLooper.dispatchAll();
2417 
2418         // Ensure we did not restart wifi.
2419         assertInDisabledState();
2420     }
2421 
2422     /**
2423      * The command to trigger a WiFi reset should not trigger any action by WifiController if we
2424      * are not in STA mode.
2425      * WiFi is not in connect mode, so any calls to reset the wifi stack due to connection failures
2426      * should be ignored.
2427      * Create and start WifiController in DisabledState, send command to restart WiFi
2428      * <p>
2429      * Expected: WiFiController should not call ActiveModeWarden.disableWifi()
2430      */
2431     @Test
testRestartWifiStackInDisabledState()2432     public void testRestartWifiStackInDisabledState() throws Exception {
2433         assertInDisabledState();
2434 
2435         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2436                 true);
2437         mLooper.dispatchAll();
2438 
2439         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS + 10);
2440         mLooper.dispatchAll();
2441 
2442         assertInDisabledState();
2443         verifyNoMoreInteractions(mClientModeManager, mSoftApManager);
2444     }
2445 
2446     @Test
testNetworkStateChangeListener()2447     public void testNetworkStateChangeListener() throws Exception {
2448         IWifiNetworkStateChangedListener testListener =
2449                 mock(IWifiNetworkStateChangedListener.class);
2450         when(testListener.asBinder()).thenReturn(mock(IBinder.class));
2451 
2452         // register listener and verify results delivered
2453         mActiveModeWarden.addWifiNetworkStateChangedListener(testListener);
2454         mActiveModeWarden.onNetworkStateChanged(
2455                 WifiManager.WifiNetworkStateChangedListener.WIFI_ROLE_CLIENT_PRIMARY,
2456                 WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_CONNECTED);
2457         verify(testListener).onWifiNetworkStateChanged(
2458                 WifiManager.WifiNetworkStateChangedListener.WIFI_ROLE_CLIENT_PRIMARY,
2459                 WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_CONNECTED);
2460 
2461         // unregister listener and verify results no longer delivered
2462         mActiveModeWarden.removeWifiNetworkStateChangedListener(testListener);
2463         mActiveModeWarden.onNetworkStateChanged(
2464                 WifiManager.WifiNetworkStateChangedListener.WIFI_ROLE_CLIENT_PRIMARY,
2465                 WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_DISCONNECTED);
2466         verify(testListener, never()).onWifiNetworkStateChanged(
2467                 WifiManager.WifiNetworkStateChangedListener.WIFI_ROLE_CLIENT_PRIMARY,
2468                 WifiManager.WifiNetworkStateChangedListener.WIFI_NETWORK_STATUS_DISCONNECTED);
2469     }
2470 
2471     /**
2472      * The command to trigger a WiFi reset should trigger a wifi reset in ClientModeImpl through
2473      * the ActiveModeWarden.shutdownWifi() call when in STA mode.
2474      * When WiFi is in scan mode, calls to reset the wifi stack due to native failure
2475      * should trigger a supplicant stop, and subsequently, a driver reload.
2476      * Create and start WifiController in EnabledState, send command to restart WiFi
2477      * <p>
2478      * Expected: WiFiController should call ActiveModeWarden.shutdownWifi() and
2479      * ActiveModeWarden should enter SCAN_ONLY mode and the wifi driver should be started.
2480      */
2481     @Test
testRestartWifiStackInStaScanEnabledState()2482     public void testRestartWifiStackInStaScanEnabledState() throws Exception {
2483         assertInDisabledState();
2484 
2485         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
2486         mActiveModeWarden.scanAlwaysModeChanged();
2487         mLooper.dispatchAll();
2488 
2489         assertInEnabledState();
2490         verify(mWifiInjector).makeClientModeManager(
2491                 any(), eq(new WorkSource(Process.WIFI_UID)), eq(ROLE_CLIENT_SCAN_ONLY),
2492                 anyBoolean());
2493 
2494         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2495                 true);
2496         mLooper.dispatchAll();
2497 
2498         verify(mClientModeManager).stop();
2499         mClientListener.onStopped(mClientModeManager);
2500         mLooper.dispatchAll();
2501         assertInDisabledState();
2502         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2503 
2504         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2505         mLooper.dispatchAll();
2506 
2507         verify(mWifiInjector, times(2)).makeClientModeManager(any(), any(), any(), anyBoolean());
2508         assertInEnabledState();
2509 
2510         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2511         verify(mSubsystemRestartCallback).onSubsystemRestarted();
2512     }
2513 
2514     /**
2515      * The command to trigger a WiFi reset should trigger a wifi reset in ClientModeImpl through
2516      * the ActiveModeWarden.shutdownWifi() call when in STA mode.
2517      * WiFi is in connect mode, calls to reset the wifi stack due to connection failures
2518      * should trigger a supplicant stop, and subsequently, a driver reload.
2519      * Create and start WifiController in EnabledState, send command to restart WiFi
2520      * <p>
2521      * Expected: WiFiController should call ActiveModeWarden.shutdownWifi() and
2522      * ActiveModeWarden should enter CONNECT_MODE and the wifi driver should be started.
2523      */
2524     @Test
testRestartWifiStackInStaConnectEnabledState()2525     public void testRestartWifiStackInStaConnectEnabledState() throws Exception {
2526         enableWifi();
2527         assertInEnabledState();
2528         verify(mWifiInjector).makeClientModeManager(
2529                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2530 
2531         assertWifiShutDown(() -> {
2532             mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2533                     true);
2534             mLooper.dispatchAll();
2535             // Complete the stop
2536             mClientListener.onStopped(mClientModeManager);
2537             mLooper.dispatchAll();
2538         });
2539 
2540         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2541 
2542         // still only started once
2543         verify(mWifiInjector).makeClientModeManager(
2544                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2545 
2546         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2547         mLooper.dispatchAll();
2548 
2549         // started again
2550         verify(mWifiInjector, times(2)).makeClientModeManager(any(), any(), any(), anyBoolean());
2551         assertInEnabledState();
2552 
2553         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2554         verify(mSubsystemRestartCallback).onSubsystemRestarted();
2555     }
2556 
2557     /**
2558      * The command to trigger a WiFi reset should not trigger a reset when in ECM mode.
2559      * Enable wifi and enter ECM state, send command to restart wifi.
2560      * <p>
2561      * Expected: The command to trigger a wifi reset should be ignored and we should remain in ECM
2562      * mode.
2563      */
2564     @Test
testRestartWifiStackDoesNotExitECMMode()2565     public void testRestartWifiStackDoesNotExitECMMode() throws Exception {
2566         enableWifi();
2567         assertInEnabledState();
2568         verify(mWifiInjector).makeClientModeManager(
2569                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), eq(false));
2570 
2571         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2572         assertEnteredEcmMode(() -> {
2573             emergencyCallStateChanged(true);
2574             mLooper.dispatchAll();
2575             mClientListener.onStopped(mClientModeManager);
2576             mLooper.dispatchAll();
2577         });
2578         assertInEmergencyMode();
2579         assertInDisabledState();
2580         verify(mClientModeManager).stop();
2581         verify(mClientModeManager, atLeastOnce()).getRole();
2582         verify(mClientModeManager).clearWifiConnectedNetworkScorer();
2583         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2584 
2585         mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_LAST_RESORT_WATCHDOG,
2586                 false);
2587         mLooper.dispatchAll();
2588 
2589         // wasn't called again
2590         verify(mWifiInjector).makeClientModeManager(
2591                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2592         assertInEmergencyMode();
2593         assertInDisabledState();
2594 
2595         verify(mClientModeManager, atLeastOnce()).getInterfaceName();
2596         verifyNoMoreInteractions(mClientModeManager, mSoftApManager);
2597     }
2598 
2599     /**
2600      * The command to trigger a WiFi reset should trigger a wifi reset in SoftApManager through
2601      * the ActiveModeWarden.shutdownWifi() call when in SAP enabled mode.
2602      */
2603     @Test
testRestartWifiStackInTetheredSoftApEnabledState()2604     public void testRestartWifiStackInTetheredSoftApEnabledState() throws Exception {
2605         enterSoftApActiveMode();
2606         verify(mWifiInjector).makeSoftApManager(
2607                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2608         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
2609         // Return true to indicate Wifi recovery in progress
2610         when(mSelfRecovery.isRecoveryInProgress()).thenReturn(true);
2611         assertWifiShutDown(() -> {
2612             mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2613                     true);
2614             mLooper.dispatchAll();
2615             // Complete the stop
2616             mSoftApListener.onStopped(mSoftApManager);
2617             mLooper.dispatchAll();
2618         });
2619 
2620         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
2621 
2622         // still only started once
2623         verify(mWifiInjector).makeSoftApManager(
2624                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2625         // No client mode manager created
2626         verify(mWifiInjector, never()).makeClientModeManager(
2627                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2628 
2629         verify(mSelfRecovery).isRecoveryInProgress();
2630         verify(mSelfRecovery).onWifiStopped();
2631 
2632         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2633         mLooper.dispatchAll();
2634 
2635         // started again
2636         verify(mWifiInjector, times(2)).makeSoftApManager(
2637                 any(), any(), any(), any(), any(), anyBoolean());
2638         assertInEnabledState();
2639 
2640         verify(mSelfRecovery).onRecoveryCompleted();
2641         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2642         verify(mSubsystemRestartCallback).onSubsystemRestarted();
2643     }
2644 
2645     /**
2646      * The command to trigger a WiFi reset should trigger a wifi reset in SoftApManager through
2647      * the ActiveModeWarden.shutdownWifi() call when in SAP enabled mode.
2648      * If the shutdown isn't done fast enough to transit to disabled state it should still
2649      * bring up soft ap manager later.
2650      */
2651     @Test
testRestartWifiStackInTetheredSoftApEnabledState_SlowDisable()2652     public void testRestartWifiStackInTetheredSoftApEnabledState_SlowDisable() throws Exception {
2653         enterSoftApActiveMode();
2654         verify(mWifiInjector).makeSoftApManager(
2655                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2656 
2657         assertWifiShutDown(() -> {
2658             mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2659                     true);
2660             mLooper.dispatchAll();
2661             mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2662             mLooper.dispatchAll();
2663         });
2664         // Wifi is still not disabled yet.
2665         verify(mModeChangeCallback, never()).onActiveModeManagerRemoved(mSoftApManager);
2666         verify(mWifiInjector).makeSoftApManager(
2667                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2668         assertInEnabledState();
2669 
2670         // Now complete the stop and transit to disabled state
2671         mSoftApListener.onStopped(mSoftApManager);
2672         // mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2673         mLooper.dispatchAll();
2674 
2675         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
2676         // started again
2677         verify(mWifiInjector, times(1)).makeSoftApManager(
2678                 any(), any(), any(), any(), any(), anyBoolean());
2679         assertInDisabledState();
2680 
2681         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2682         mLooper.dispatchAll();
2683 
2684         // started again
2685         verify(mWifiInjector, times(2)).makeSoftApManager(
2686                 any(), any(), any(), any(), any(), anyBoolean());
2687         assertInEnabledState();
2688 
2689         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2690         verify(mSubsystemRestartCallback).onSubsystemRestarted();
2691     }
2692 
2693     /**
2694      * The command to trigger a WiFi reset should trigger a wifi reset in SoftApManager &
2695      * ClientModeManager through the ActiveModeWarden.shutdownWifi() call when in STA + SAP
2696      * enabled mode.
2697      */
2698     @Test
testRestartWifiStackInTetheredSoftApAndStaConnectEnabledState()2699     public void testRestartWifiStackInTetheredSoftApAndStaConnectEnabledState() throws Exception {
2700         enableWifi();
2701         enterSoftApActiveMode();
2702         verify(mWifiInjector).makeClientModeManager(
2703                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2704         verify(mWifiInjector).makeSoftApManager(
2705                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2706 
2707         assertWifiShutDown(() -> {
2708             mActiveModeWarden.recoveryRestartWifi(SelfRecovery.REASON_WIFINATIVE_FAILURE,
2709                     true);
2710             mLooper.dispatchAll();
2711             // Complete the stop
2712             mClientListener.onStopped(mClientModeManager);
2713             mSoftApListener.onStopped(mSoftApManager);
2714             mLooper.dispatchAll();
2715         });
2716 
2717         verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
2718         verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
2719 
2720         // still only started once
2721         verify(mWifiInjector).makeClientModeManager(
2722                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2723         verify(mWifiInjector).makeSoftApManager(
2724                 any(), any(), any(), eq(TEST_WORKSOURCE), eq(ROLE_SOFTAP_TETHERED), anyBoolean());
2725 
2726         mLooper.moveTimeForward(TEST_WIFI_RECOVERY_DELAY_MS);
2727         mLooper.dispatchAll();
2728 
2729         // started again
2730         verify(mWifiInjector, times(2)).makeClientModeManager(any(), any(), any(), anyBoolean());
2731         verify(mWifiInjector, times(2)).makeSoftApManager(
2732                 any(), any(), any(), any(), any(), anyBoolean());
2733         assertInEnabledState();
2734 
2735         verify(mSubsystemRestartCallback).onSubsystemRestarting();
2736         verify(mSubsystemRestartCallback).onSubsystemRestarted();
2737     }
2738 
2739     /**
2740      * Tests that when Wifi is already disabled and another Wifi toggle command arrives,
2741      * don't enter scan mode if {@link WifiSettingsStore#isScanAlwaysAvailable()} is false.
2742      * Note: {@link WifiSettingsStore#isScanAlwaysAvailable()} returns false if either the wifi
2743      * scanning is disabled and airplane mode is on.
2744      */
2745     @Test
staDisabled_toggleWifiOff_scanNotAvailable_dontGoToScanMode()2746     public void staDisabled_toggleWifiOff_scanNotAvailable_dontGoToScanMode() {
2747         assertInDisabledState();
2748 
2749         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
2750         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
2751         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
2752         when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
2753 
2754         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
2755         mLooper.dispatchAll();
2756 
2757         assertInDisabledState();
2758         verify(mWifiInjector, never()).makeClientModeManager(
2759                 any(), eq(TEST_WORKSOURCE), any(), anyBoolean());
2760     }
2761 
2762     /**
2763      * Tests that when Wifi is already disabled and another Wifi toggle command arrives,
2764      * enter scan mode if {@link WifiSettingsStore#isScanAlwaysAvailable()} is true.
2765      * Note: {@link WifiSettingsStore#isScanAlwaysAvailable()} returns true if both the wifi
2766      * scanning is enabled and airplane mode is off.
2767      */
2768     @Test
staDisabled_toggleWifiOff_scanAvailable_goToScanMode()2769     public void staDisabled_toggleWifiOff_scanAvailable_goToScanMode() {
2770         assertInDisabledState();
2771 
2772         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
2773         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true);
2774         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
2775         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
2776 
2777         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
2778         mLooper.dispatchAll();
2779 
2780         assertInEnabledState();
2781         verify(mWifiInjector).makeClientModeManager(
2782                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_SCAN_ONLY), anyBoolean());
2783     }
2784 
2785     /**
2786      * Tests that if the carrier config to disable Wifi is enabled during ECM, Wifi is shut down
2787      * when entering ECM and turned back on when exiting ECM.
2788      */
2789     @Test
ecmDisablesWifi_exitEcm_restartWifi()2790     public void ecmDisablesWifi_exitEcm_restartWifi() throws Exception {
2791         enterClientModeActiveState();
2792 
2793         verify(mWifiInjector).makeClientModeManager(
2794                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2795 
2796         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
2797         assertEnteredEcmMode(() -> {
2798             emergencyCallbackModeChanged(true);
2799             mLooper.dispatchAll();
2800         });
2801         assertInEnabledState();
2802         verify(mClientModeManager).stop();
2803 
2804         mClientListener.onStopped(mClientModeManager);
2805         mLooper.dispatchAll();
2806         assertInDisabledState();
2807 
2808         emergencyCallbackModeChanged(false);
2809         mLooper.dispatchAll();
2810 
2811         assertNotInEmergencyMode();
2812         // client mode restarted
2813         verify(mWifiInjector, times(2)).makeClientModeManager(any(), any(), any(), anyBoolean());
2814         assertInEnabledState();
2815     }
2816 
2817     /**
2818      * Tests that if the carrier config to disable Wifi is not enabled during ECM, Wifi remains on
2819      * during ECM, and nothing happens after exiting ECM.
2820      */
2821     @Test
ecmDoesNotDisableWifi_exitEcm_noOp()2822     public void ecmDoesNotDisableWifi_exitEcm_noOp() throws Exception {
2823         enterClientModeActiveState();
2824 
2825         verify(mWifiInjector).makeClientModeManager(
2826                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2827 
2828         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
2829         assertEnteredEcmMode(() -> {
2830             emergencyCallbackModeChanged(true);
2831             mLooper.dispatchAll();
2832         });
2833         assertInEnabledState();
2834         verify(mClientModeManager, never()).stop();
2835 
2836         emergencyCallbackModeChanged(false);
2837         mLooper.dispatchAll();
2838 
2839         assertNotInEmergencyMode();
2840         // client mode manager not started again
2841         verify(mWifiInjector).makeClientModeManager(
2842                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
2843         assertInEnabledState();
2844     }
2845 
2846     @Test
testUpdateCapabilityInSoftApActiveMode()2847     public void testUpdateCapabilityInSoftApActiveMode() throws Exception {
2848         SoftApCapability testCapability = new SoftApCapability(0);
2849         enterSoftApActiveMode();
2850         mActiveModeWarden.updateSoftApCapability(testCapability,
2851                 WifiManager.IFACE_IP_MODE_TETHERED);
2852         mLooper.dispatchAll();
2853         verify(mSoftApManager).updateCapability(testCapability);
2854     }
2855 
2856     @Test
testUpdateConfigInSoftApActiveMode()2857     public void testUpdateConfigInSoftApActiveMode() throws Exception {
2858         SoftApConfiguration testConfig = new SoftApConfiguration.Builder()
2859                 .setSsid("Test123").build();
2860         enterSoftApActiveMode();
2861         mActiveModeWarden.updateSoftApConfiguration(testConfig);
2862         mLooper.dispatchAll();
2863         verify(mSoftApManager).updateConfiguration(testConfig);
2864     }
2865 
2866     @Test
testUpdateCapabilityInNonSoftApActiveMode()2867     public void testUpdateCapabilityInNonSoftApActiveMode() throws Exception {
2868         SoftApCapability testCapability = new SoftApCapability(0);
2869         enterClientModeActiveState();
2870         mActiveModeWarden.updateSoftApCapability(testCapability,
2871                 WifiManager.IFACE_IP_MODE_TETHERED);
2872         mLooper.dispatchAll();
2873         verify(mSoftApManager, never()).updateCapability(any());
2874     }
2875 
2876     @Test
testUpdateLocalModeSoftApCapabilityInTetheredSoftApActiveMode()2877     public void testUpdateLocalModeSoftApCapabilityInTetheredSoftApActiveMode() throws Exception {
2878         SoftApCapability testCapability = new SoftApCapability(0);
2879         enterSoftApActiveMode(); // Tethered mode
2880         mActiveModeWarden.updateSoftApCapability(testCapability,
2881                 WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
2882         mLooper.dispatchAll();
2883         verify(mSoftApManager, never()).updateCapability(any());
2884     }
2885 
2886     @Test
testUpdateConfigInNonSoftApActiveMode()2887     public void testUpdateConfigInNonSoftApActiveMode() throws Exception {
2888         SoftApConfiguration testConfig = new SoftApConfiguration.Builder()
2889                 .setSsid("Test123").build();
2890         enterClientModeActiveState();
2891         mActiveModeWarden.updateSoftApConfiguration(testConfig);
2892         mLooper.dispatchAll();
2893         verify(mSoftApManager, never()).updateConfiguration(any());
2894     }
2895 
2896     @Test
isStaApConcurrencySupported()2897     public void isStaApConcurrencySupported() throws Exception {
2898         enterClientModeActiveState();
2899         when(mWifiNative.isStaApConcurrencySupported()).thenReturn(false);
2900         mClientListener.onStarted(mClientModeManager);
2901         assertEquals(0L,
2902                 mActiveModeWarden.getSupportedFeatureSet() & WifiManager.WIFI_FEATURE_AP_STA);
2903 
2904         when(mWifiNative.isStaApConcurrencySupported()).thenReturn(true);
2905         mClientListener.onStarted(mClientModeManager);
2906         assertEquals(WifiManager.WIFI_FEATURE_AP_STA,
2907                 mActiveModeWarden.getSupportedFeatureSet() & WifiManager.WIFI_FEATURE_AP_STA);
2908     }
2909 
2910     @Test
isStaStaConcurrencySupported()2911     public void isStaStaConcurrencySupported() throws Exception {
2912         // STA + STA not supported.
2913         when(mWifiNative.isStaStaConcurrencySupported()).thenReturn(false);
2914         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForLocalOnlyConnections());
2915         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForMbb());
2916         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForRestrictedConnections());
2917 
2918         // STA + STA supported, but no use-cases enabled.
2919         when(mWifiNative.isStaStaConcurrencySupported()).thenReturn(true);
2920         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForLocalOnlyConnections());
2921         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForMbb());
2922         assertFalse(mActiveModeWarden.isStaStaConcurrencySupportedForRestrictedConnections());
2923 
2924         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
2925                 .thenReturn(true);
2926         assertTrue(mActiveModeWarden.isStaStaConcurrencySupportedForLocalOnlyConnections());
2927 
2928         when(mResources.getBoolean(
2929                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
2930                 .thenReturn(true);
2931         assertTrue(mActiveModeWarden.isStaStaConcurrencySupportedForMbb());
2932 
2933         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
2934                 .thenReturn(true);
2935         assertTrue(mActiveModeWarden.isStaStaConcurrencySupportedForRestrictedConnections());
2936     }
2937 
requestAdditionalClientModeManager( ClientConnectivityRole additionaClientModeManagerRole, ConcreteClientModeManager additionalClientModeManager, ExternalClientModeManagerRequestListener externalRequestListener, String ssid, String bssid)2938     private Listener<ConcreteClientModeManager> requestAdditionalClientModeManager(
2939             ClientConnectivityRole additionaClientModeManagerRole,
2940             ConcreteClientModeManager additionalClientModeManager,
2941             ExternalClientModeManagerRequestListener externalRequestListener,
2942             String ssid, String bssid)
2943             throws Exception {
2944         enterClientModeActiveState();
2945 
2946         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
2947                 new Mutable<>();
2948 
2949         // Connected to ssid1/bssid1
2950         WifiConfiguration config1 = new WifiConfiguration();
2951         config1.SSID = TEST_SSID_1;
2952         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
2953         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
2954 
2955         doAnswer((invocation) -> {
2956             Object[] args = invocation.getArguments();
2957             additionalClientListener.value =
2958                     (Listener<ConcreteClientModeManager>) args[0];
2959             return additionalClientModeManager;
2960         }).when(mWifiInjector).makeClientModeManager(
2961                 any(Listener.class), any(), any(), anyBoolean());
2962         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
2963         when(additionalClientModeManager.getRole()).thenReturn(additionaClientModeManagerRole);
2964 
2965         // request for ssid2/bssid2
2966         if (additionaClientModeManagerRole == ROLE_CLIENT_LOCAL_ONLY) {
2967             mActiveModeWarden.requestLocalOnlyClientModeManager(
2968                     externalRequestListener, TEST_WORKSOURCE, ssid, bssid, false);
2969         } else if (additionaClientModeManagerRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
2970             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
2971                     externalRequestListener, TEST_WORKSOURCE, ssid, bssid);
2972         } else if (additionaClientModeManagerRole == ROLE_CLIENT_SECONDARY_TRANSIENT) {
2973             mActiveModeWarden.requestSecondaryTransientClientModeManager(
2974                     externalRequestListener, TEST_WORKSOURCE, ssid, bssid);
2975         }
2976         mLooper.dispatchAll();
2977         verify(mWifiInjector)
2978                 .makeClientModeManager(any(), eq(TEST_WORKSOURCE),
2979                         eq(additionaClientModeManagerRole), anyBoolean());
2980         additionalClientListener.value.onStarted(additionalClientModeManager);
2981         mLooper.dispatchAll();
2982         // capture last use case set
2983         ArgumentCaptor<Integer> useCaseCaptor = ArgumentCaptor.forClass(Integer.class);
2984         verify(mWifiNative, atLeastOnce()).setMultiStaUseCase(useCaseCaptor.capture());
2985         int lastUseCaseSet = useCaseCaptor.getValue().intValue();
2986         // Ensure the hardware is correctly configured for STA + STA
2987         if (additionaClientModeManagerRole == ROLE_CLIENT_LOCAL_ONLY
2988                 || additionaClientModeManagerRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
2989             assertEquals(WifiNative.DUAL_STA_NON_TRANSIENT_UNBIASED, lastUseCaseSet);
2990         } else if (additionaClientModeManagerRole == ROLE_CLIENT_SECONDARY_TRANSIENT) {
2991             assertEquals(WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY, lastUseCaseSet);
2992         }
2993 
2994         // verify last set of primary connection is for WIFI_IFACE_NAME
2995         ArgumentCaptor<String> ifaceNameCaptor = ArgumentCaptor.forClass(String.class);
2996         verify(mWifiNative, atLeastOnce()).setMultiStaPrimaryConnection(ifaceNameCaptor.capture());
2997         assertEquals(WIFI_IFACE_NAME, ifaceNameCaptor.getValue());
2998 
2999         // Returns the new local only client mode manager.
3000         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3001                 ArgumentCaptor.forClass(ClientModeManager.class);
3002         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3003         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3004         // the additional CMM never became primary
3005         verify(mPrimaryChangedCallback, never()).onChange(any(), eq(additionalClientModeManager));
3006 
3007         return additionalClientListener.value;
3008     }
3009 
3010     @Test
testRemoveDefaultClientModeManager()3011     public void testRemoveDefaultClientModeManager() throws Exception {
3012         // Ensure that we can create more client ifaces.
3013         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3014         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3015                 .thenReturn(true);
3016         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3017                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3018 
3019         // Verify removing a non DefaultClientModeManager works properly.
3020         requestRemoveAdditionalClientModeManager(ROLE_CLIENT_LOCAL_ONLY);
3021 
3022         // Verify that a request to remove DefaultClientModeManager is ignored.
3023         ClientModeManager defaultClientModeManager = mock(DefaultClientModeManager.class);
3024 
3025         mActiveModeWarden.removeClientModeManager(defaultClientModeManager);
3026         mLooper.dispatchAll();
3027         verify(defaultClientModeManager, never()).stop();
3028     }
3029 
requestRemoveAdditionalClientModeManager( ClientConnectivityRole role)3030     private void requestRemoveAdditionalClientModeManager(
3031             ClientConnectivityRole role) throws Exception {
3032         ConcreteClientModeManager additionalClientModeManager =
3033                 mock(ConcreteClientModeManager.class);
3034         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3035                 ExternalClientModeManagerRequestListener.class);
3036         Listener<ConcreteClientModeManager> additionalClientListener =
3037                 requestAdditionalClientModeManager(role, additionalClientModeManager,
3038                         externalRequestListener, TEST_SSID_2, TEST_BSSID_2);
3039 
3040         mActiveModeWarden.removeClientModeManager(additionalClientModeManager);
3041         mLooper.dispatchAll();
3042         verify(additionalClientModeManager).stop();
3043         additionalClientListener.onStopped(additionalClientModeManager);
3044         mLooper.dispatchAll();
3045         verify(mModeChangeCallback).onActiveModeManagerRemoved(additionalClientModeManager);
3046         // the additional CMM still never became primary
3047         verify(mPrimaryChangedCallback, never()).onChange(any(), eq(additionalClientModeManager));
3048     }
3049 
requestRemoveAdditionalClientModeManagerWhenNotAllowed( ClientConnectivityRole role, boolean clientIsExpected)3050     private void requestRemoveAdditionalClientModeManagerWhenNotAllowed(
3051             ClientConnectivityRole role, boolean clientIsExpected) throws Exception {
3052         enterClientModeActiveState();
3053 
3054         // Connected to ssid1/bssid1
3055         WifiConfiguration config1 = new WifiConfiguration();
3056         config1.SSID = TEST_SSID_1;
3057         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
3058         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
3059 
3060         ConcreteClientModeManager additionalClientModeManager =
3061                 mock(ConcreteClientModeManager.class);
3062         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
3063                 new Mutable<>();
3064         doAnswer((invocation) -> {
3065             Object[] args = invocation.getArguments();
3066             additionalClientListener.value =
3067                     (Listener<ConcreteClientModeManager>) args[0];
3068             return additionalClientModeManager;
3069         }).when(mWifiInjector).makeClientModeManager(
3070                 any(Listener.class), any(), any(), anyBoolean());
3071         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
3072         when(additionalClientModeManager.getRole()).thenReturn(role);
3073 
3074         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3075                 ExternalClientModeManagerRequestListener.class);
3076         // request for ssid2/bssid2
3077         if (role == ROLE_CLIENT_LOCAL_ONLY) {
3078             mActiveModeWarden.requestLocalOnlyClientModeManager(
3079                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2, false);
3080         } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
3081             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
3082                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3083         } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
3084             mActiveModeWarden.requestSecondaryTransientClientModeManager(
3085                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3086         }
3087         mLooper.dispatchAll();
3088         verifyNoMoreInteractions(additionalClientModeManager);
3089         // Returns the existing primary client mode manager.
3090         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3091                 ArgumentCaptor.forClass(ClientModeManager.class);
3092         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3093         if (clientIsExpected) {
3094             assertEquals(mClientModeManager, requestedClientModeManager.getValue());
3095 
3096             mActiveModeWarden.removeClientModeManager(requestedClientModeManager.getValue());
3097         } else {
3098             assertNull(requestedClientModeManager.getValue());
3099         }
3100         mLooper.dispatchAll();
3101         verifyNoMoreInteractions(additionalClientModeManager);
3102     }
3103 
requestAdditionalClientModeManagerWhenWifiIsOff( ClientConnectivityRole role)3104     private void requestAdditionalClientModeManagerWhenWifiIsOff(
3105             ClientConnectivityRole role) throws Exception {
3106         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3107                 ExternalClientModeManagerRequestListener.class);
3108         if (role == ROLE_CLIENT_LOCAL_ONLY) {
3109             mActiveModeWarden.requestLocalOnlyClientModeManager(
3110                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1, false);
3111         } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
3112             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
3113                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
3114         } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
3115             mActiveModeWarden.requestSecondaryTransientClientModeManager(
3116                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
3117         }
3118         mLooper.dispatchAll();
3119 
3120         verify(externalRequestListener).onAnswer(null);
3121     }
3122 
requestAdditionalClientModeManagerWhenAlreadyPresent( ClientConnectivityRole role)3123     public void requestAdditionalClientModeManagerWhenAlreadyPresent(
3124             ClientConnectivityRole role) throws Exception {
3125         ConcreteClientModeManager additionalClientModeManager =
3126                 mock(ConcreteClientModeManager.class);
3127         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3128                 ExternalClientModeManagerRequestListener.class);
3129         requestAdditionalClientModeManager(role, additionalClientModeManager,
3130                 externalRequestListener, TEST_SSID_2, TEST_BSSID_2);
3131 
3132         // set additional CMM connected to ssid2/bssid2
3133         WifiConfiguration config2 = new WifiConfiguration();
3134         config2.SSID = TEST_SSID_2;
3135         when(additionalClientModeManager.getConnectedWifiConfiguration()).thenReturn(config2);
3136         when(additionalClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_2);
3137 
3138         // request for ssid3/bssid3
3139         // request for one more CMM (returns the existing one).
3140         if (role == ROLE_CLIENT_LOCAL_ONLY) {
3141             mActiveModeWarden.requestLocalOnlyClientModeManager(
3142                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_3, TEST_BSSID_3, false);
3143         } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
3144             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
3145                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_3, TEST_BSSID_3);
3146         } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
3147             mActiveModeWarden.requestSecondaryTransientClientModeManager(
3148                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_3, TEST_BSSID_3);
3149         }
3150         mLooper.dispatchAll();
3151 
3152         // Don't make another client mode manager.
3153         verify(mWifiInjector, times(1))
3154                 .makeClientModeManager(any(), any(), eq(role), anyBoolean());
3155         // Returns the existing client mode manager.
3156         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3157                 ArgumentCaptor.forClass(ClientModeManager.class);
3158         verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
3159         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3160     }
3161 
requestAdditionalClientModeManagerWhenAlreadyPresentSameBssid( ClientConnectivityRole role)3162     public void requestAdditionalClientModeManagerWhenAlreadyPresentSameBssid(
3163             ClientConnectivityRole role) throws Exception {
3164         ConcreteClientModeManager additionalClientModeManager =
3165                 mock(ConcreteClientModeManager.class);
3166         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3167                 ExternalClientModeManagerRequestListener.class);
3168         requestAdditionalClientModeManager(role, additionalClientModeManager,
3169                 externalRequestListener, TEST_SSID_2, TEST_BSSID_2);
3170 
3171         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3172                 ArgumentCaptor.forClass(ClientModeManager.class);
3173         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3174         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3175 
3176         // set additional CMM connected to ssid2/bssid2
3177         WifiConfiguration config2 = new WifiConfiguration();
3178         config2.SSID = TEST_SSID_2;
3179         when(additionalClientModeManager.getConnectedWifiConfiguration()).thenReturn(config2);
3180         when(additionalClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_2);
3181 
3182         // request for the same SSID/BSSID and expect the existing CMM to get returned twice.
3183         if (role == ROLE_CLIENT_LOCAL_ONLY) {
3184             mActiveModeWarden.requestLocalOnlyClientModeManager(
3185                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2, false);
3186         } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
3187             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
3188                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3189         } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
3190             mActiveModeWarden.requestSecondaryTransientClientModeManager(
3191                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3192         }
3193         mLooper.dispatchAll();
3194 
3195         // Don't make another client mode manager.
3196         verify(mWifiInjector, times(1))
3197                 .makeClientModeManager(any(), any(), eq(role), anyBoolean());
3198         // Returns the existing client mode manager.
3199         verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
3200         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3201     }
3202 
requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid( ClientConnectivityRole role)3203     private void requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid(
3204             ClientConnectivityRole role) throws Exception {
3205         enterClientModeActiveState();
3206 
3207         // Connected to ssid1/bssid1
3208         WifiConfiguration config1 = new WifiConfiguration();
3209         config1.SSID = TEST_SSID_1;
3210         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
3211         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
3212 
3213         ConcreteClientModeManager additionalClientModeManager =
3214                 mock(ConcreteClientModeManager.class);
3215         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
3216                 new Mutable<>();
3217         doAnswer((invocation) -> {
3218             Object[] args = invocation.getArguments();
3219             additionalClientListener.value =
3220                     (Listener<ConcreteClientModeManager>) args[0];
3221             return additionalClientModeManager;
3222         }).when(mWifiInjector).makeClientModeManager(
3223                 any(Listener.class), any(), any(), anyBoolean());
3224         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
3225         when(additionalClientModeManager.getRole()).thenReturn(role);
3226 
3227         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3228                 ExternalClientModeManagerRequestListener.class);
3229         // request for same ssid1/bssid1
3230         if (role == ROLE_CLIENT_LOCAL_ONLY) {
3231             mActiveModeWarden.requestLocalOnlyClientModeManager(
3232                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1, false);
3233         } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
3234             mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
3235                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
3236         } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
3237             mActiveModeWarden.requestSecondaryTransientClientModeManager(
3238                     externalRequestListener, TEST_WORKSOURCE, TEST_SSID_1, TEST_BSSID_1);
3239         }
3240         mLooper.dispatchAll();
3241         verifyNoMoreInteractions(additionalClientModeManager);
3242         // Returns the existing primary client mode manager.
3243         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3244                 ArgumentCaptor.forClass(ClientModeManager.class);
3245         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3246         assertEquals(mClientModeManager, requestedClientModeManager.getValue());
3247     }
3248 
3249     @Test
requestRemoveLocalOnlyClientModeManager()3250     public void requestRemoveLocalOnlyClientModeManager() throws Exception {
3251         // Ensure that we can create more client ifaces.
3252         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3253         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3254                 .thenReturn(true);
3255         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3256                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3257 
3258         requestRemoveAdditionalClientModeManager(ROLE_CLIENT_LOCAL_ONLY);
3259     }
3260 
3261     @Test
requestRemoveLocalOnlyClientModeManagerWhenStaStaNotSupported()3262     public void requestRemoveLocalOnlyClientModeManagerWhenStaStaNotSupported() throws Exception {
3263         // Ensure that we cannot create more client ifaces.
3264         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
3265         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3266                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3267         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true);
3268     }
3269 
3270     @Test
requestRemoveLocalOnlyClientModeManagerWhenFeatureDisabled()3271     public void requestRemoveLocalOnlyClientModeManagerWhenFeatureDisabled() throws Exception {
3272         // Ensure that we can create more client ifaces.
3273         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3274         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3275                 .thenReturn(false);
3276         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3277                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3278         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true);
3279     }
3280 
3281     @Test
requestLocalOnlyClientModeManagerWhenWifiIsOff()3282     public void requestLocalOnlyClientModeManagerWhenWifiIsOff() throws Exception {
3283         // Ensure that we can create more client ifaces.
3284         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3285         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3286                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3287 
3288         requestAdditionalClientModeManagerWhenWifiIsOff(ROLE_CLIENT_LOCAL_ONLY);
3289     }
3290 
3291     @Test
requestLocalOnlyClientModeManagerWhenAlreadyPresent()3292     public void requestLocalOnlyClientModeManagerWhenAlreadyPresent() throws Exception {
3293         // Ensure that we can create more client ifaces.
3294         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3295         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3296                 .thenReturn(true);
3297         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3298                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3299 
3300         requestAdditionalClientModeManagerWhenAlreadyPresent(ROLE_CLIENT_LOCAL_ONLY);
3301     }
3302 
3303     @Test
requestLocalOnlyClientModeManagerWhenAlreadyPresentSameBssid()3304     public void requestLocalOnlyClientModeManagerWhenAlreadyPresentSameBssid() throws Exception {
3305         // Ensure that we can create more client ifaces.
3306         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3307         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3308                 .thenReturn(true);
3309         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3310                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3311 
3312         requestAdditionalClientModeManagerWhenAlreadyPresentSameBssid(ROLE_CLIENT_LOCAL_ONLY);
3313     }
3314 
3315     @Test
requestLocalOnlyClientModeManagerWhenConnectingToPrimaryBssid()3316     public void requestLocalOnlyClientModeManagerWhenConnectingToPrimaryBssid() throws Exception {
3317         // Ensure that we can create more client ifaces.
3318         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3319         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3320                 .thenReturn(true);
3321         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3322                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3323 
3324         requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid(ROLE_CLIENT_LOCAL_ONLY);
3325     }
3326 
3327     @Test
requestRemoveLocalOnlyClientModeManagerWhenNotSystemAppAndTargetSdkLessThanS()3328     public void requestRemoveLocalOnlyClientModeManagerWhenNotSystemAppAndTargetSdkLessThanS()
3329             throws Exception {
3330         // Ensure that we can create more client ifaces.
3331         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3332         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3333                 .thenReturn(true);
3334 
3335         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(false);
3336         when(mWifiPermissionsUtil.isTargetSdkLessThan(
3337                 TEST_PACKAGE, Build.VERSION_CODES.S, TEST_UID))
3338                 .thenReturn(true);
3339         when(mWifiPermissionsUtil.isTargetSdkLessThan(
3340                 "system-service", Build.VERSION_CODES.S, Process.SYSTEM_UID))
3341                 .thenReturn(false);
3342         // Simulate explicit user approval
3343         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3344                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, true));
3345         WorkSource workSource = new WorkSource(TEST_WORKSOURCE);
3346         workSource.add(SETTINGS_WORKSOURCE);
3347         verify(mWifiNative).isItPossibleToCreateStaIface(eq(workSource));
3348         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true);
3349     }
3350 
3351     @Test
requestRemoveLocalOnlyClientModeManagerWhenNotSystemAppAndTargetSdkEqualToS()3352     public void requestRemoveLocalOnlyClientModeManagerWhenNotSystemAppAndTargetSdkEqualToS()
3353             throws Exception {
3354         // Ensure that we can create more client ifaces.
3355         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3356         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3357                 .thenReturn(true);
3358         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(false);
3359         when(mWifiPermissionsUtil.isTargetSdkLessThan(
3360                 TEST_PACKAGE, Build.VERSION_CODES.S, TEST_UID))
3361                 .thenReturn(false);
3362         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3363                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3364         requestRemoveAdditionalClientModeManager(ROLE_CLIENT_LOCAL_ONLY);
3365     }
3366 
3367     @Test
requestRemoveLoClientModeManagerWhenNotSystemAppAndTargetSdkLessThanSAndCantCreate()3368     public void requestRemoveLoClientModeManagerWhenNotSystemAppAndTargetSdkLessThanSAndCantCreate()
3369             throws Exception {
3370         // Ensure that we can't create more client ifaces - so will attempt to fallback (which we
3371         // should be able to do for <S apps)
3372         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
3373         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3374                 .thenReturn(true);
3375         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(false);
3376         when(mWifiPermissionsUtil.isTargetSdkLessThan(
3377                 TEST_PACKAGE, Build.VERSION_CODES.S, TEST_UID))
3378                 .thenReturn(true);
3379         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3380                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3381         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, true);
3382     }
3383 
3384     @Test
requestRemoveLoClientModeManagerWhenNotSystemAppAndTargetSdkEqualToSAndCantCreate()3385     public void requestRemoveLoClientModeManagerWhenNotSystemAppAndTargetSdkEqualToSAndCantCreate()
3386             throws Exception {
3387         // Ensure that we can't create more client ifaces - so will attempt to fallback (which we
3388         // can't for >=S apps)
3389         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
3390         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3391                 .thenReturn(true);
3392         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(false);
3393         when(mWifiPermissionsUtil.isTargetSdkLessThan(
3394                 TEST_PACKAGE, Build.VERSION_CODES.S, TEST_UID))
3395                 .thenReturn(false);
3396         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3397                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3398         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_LOCAL_ONLY, false);
3399     }
3400 
3401     @Test
requestRemoveSecondaryLongLivedClientModeManager()3402     public void requestRemoveSecondaryLongLivedClientModeManager() throws Exception {
3403         // Ensure that we can create more client ifaces.
3404         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3405         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
3406                 .thenReturn(true);
3407         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3408                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
3409 
3410         requestRemoveAdditionalClientModeManager(ROLE_CLIENT_SECONDARY_LONG_LIVED);
3411     }
3412 
3413     @Test
requestRemoveSecondaryLongLivedClientModeManagerWhenStaStaNotSupported()3414     public void requestRemoveSecondaryLongLivedClientModeManagerWhenStaStaNotSupported()
3415             throws Exception {
3416         // Ensure that we cannot create more client ifaces.
3417         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
3418         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3419                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
3420         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_LONG_LIVED,
3421                 true);
3422     }
3423 
3424     @Test
requestRemoveSecondaryLongLivedClientModeManagerWhenFeatureDisabled()3425     public void requestRemoveSecondaryLongLivedClientModeManagerWhenFeatureDisabled()
3426             throws Exception {
3427         // Ensure that we can create more client ifaces.
3428         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3429         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
3430                 .thenReturn(false);
3431         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3432                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
3433         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_LONG_LIVED,
3434                 true);
3435     }
3436 
3437     @Test
requestSecondaryLongLivedClientModeManagerWhenWifiIsOff()3438     public void requestSecondaryLongLivedClientModeManagerWhenWifiIsOff() throws Exception {
3439         // Ensure that we can create more client ifaces.
3440         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3441         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
3442                 .thenReturn(true);
3443         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3444                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
3445 
3446         requestAdditionalClientModeManagerWhenWifiIsOff(ROLE_CLIENT_SECONDARY_LONG_LIVED);
3447     }
3448 
3449     @Test
requestSecondaryLongLivedClientModeManagerWhenAlreadyPresent()3450     public void requestSecondaryLongLivedClientModeManagerWhenAlreadyPresent() throws Exception {
3451         // Ensure that we can create more client ifaces.
3452         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3453         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
3454                 .thenReturn(true);
3455         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3456                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
3457 
3458         requestAdditionalClientModeManagerWhenAlreadyPresent(ROLE_CLIENT_SECONDARY_LONG_LIVED);
3459     }
3460 
3461     @Test
requestSecondaryLongLivedClientModeManagerWhenAlreadyPresentSameBssid()3462     public void requestSecondaryLongLivedClientModeManagerWhenAlreadyPresentSameBssid()
3463             throws Exception {
3464         // Ensure that we can create more client ifaces.
3465         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3466         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
3467                 .thenReturn(true);
3468         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3469                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
3470 
3471         requestAdditionalClientModeManagerWhenAlreadyPresentSameBssid(
3472                 ROLE_CLIENT_SECONDARY_LONG_LIVED);
3473     }
3474 
3475     @Test
requestSecondaryLongLivedClientModeManagerWhenConnectingToPrimaryBssid()3476     public void requestSecondaryLongLivedClientModeManagerWhenConnectingToPrimaryBssid()
3477             throws Exception {
3478         // Ensure that we can create more client ifaces.
3479         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3480         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
3481                 .thenReturn(true);
3482         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3483                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
3484 
3485         requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid(
3486                 ROLE_CLIENT_SECONDARY_LONG_LIVED);
3487     }
3488 
3489     @Test
requestRemoveSecondaryTransientClientModeManager()3490     public void requestRemoveSecondaryTransientClientModeManager() throws Exception {
3491         // Ensure that we can create more client ifaces.
3492         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3493         when(mResources.getBoolean(
3494                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3495                 .thenReturn(true);
3496         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3497                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3498 
3499         requestRemoveAdditionalClientModeManager(ROLE_CLIENT_SECONDARY_TRANSIENT);
3500     }
3501 
3502     @Test
requestRemoveSecondaryTransientClientModeManagerWhenStaStaNotSupported()3503     public void requestRemoveSecondaryTransientClientModeManagerWhenStaStaNotSupported()
3504             throws Exception {
3505         // Ensure that we cannot create more client ifaces.
3506         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
3507         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3508                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3509         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_TRANSIENT,
3510                 true);
3511     }
3512 
3513     @Test
requestRemoveSecondaryTransientClientModeManagerWhenFeatureDisabled()3514     public void requestRemoveSecondaryTransientClientModeManagerWhenFeatureDisabled()
3515             throws Exception {
3516         // Ensure that we can create more client ifaces.
3517         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3518         when(mResources.getBoolean(
3519                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3520                 .thenReturn(false);
3521         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3522                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3523         requestRemoveAdditionalClientModeManagerWhenNotAllowed(ROLE_CLIENT_SECONDARY_TRANSIENT,
3524                 true);
3525     }
3526 
3527     @Test
requestSecondaryTransientClientModeManagerWhenWifiIsOff()3528     public void requestSecondaryTransientClientModeManagerWhenWifiIsOff() throws Exception {
3529         // Ensure that we can create more client ifaces.
3530         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3531         when(mResources.getBoolean(
3532                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3533                 .thenReturn(true);
3534         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3535                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3536 
3537         requestAdditionalClientModeManagerWhenWifiIsOff(ROLE_CLIENT_SECONDARY_TRANSIENT);
3538     }
3539 
3540     @Test
requestSecondaryTransientClientModeManagerWhenAlreadyPresent()3541     public void requestSecondaryTransientClientModeManagerWhenAlreadyPresent() throws Exception {
3542         // Ensure that we can create more client ifaces.
3543         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3544         when(mResources.getBoolean(
3545                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3546                 .thenReturn(true);
3547         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3548                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3549 
3550         requestAdditionalClientModeManagerWhenAlreadyPresent(ROLE_CLIENT_SECONDARY_TRANSIENT);
3551     }
3552 
3553     @Test
requestSecondaryTransientClientModeManagerWhenAlreadyPresentSameBssid()3554     public void requestSecondaryTransientClientModeManagerWhenAlreadyPresentSameBssid()
3555             throws Exception {
3556         // Ensure that we can create more client ifaces.
3557         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3558         when(mResources.getBoolean(
3559                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3560                 .thenReturn(true);
3561         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3562                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3563 
3564         requestAdditionalClientModeManagerWhenAlreadyPresentSameBssid(
3565                 ROLE_CLIENT_SECONDARY_TRANSIENT);
3566     }
3567 
3568     @Test
requestSecondaryTransientClientModeManagerWhenConnectingToPrimaryBssid()3569     public void requestSecondaryTransientClientModeManagerWhenConnectingToPrimaryBssid()
3570             throws Exception {
3571         // Ensure that we can create more client ifaces.
3572         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3573         when(mResources.getBoolean(
3574                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3575                 .thenReturn(true);
3576         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3577                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3578 
3579         requestAdditionalClientModeManagerWhenConnectingToPrimaryBssid(
3580                 ROLE_CLIENT_SECONDARY_TRANSIENT);
3581     }
3582 
3583     @Test
requestHighPrioSecondaryTransientClientModeManagerWhenConnectedToLocalOnlyBssid()3584     public void requestHighPrioSecondaryTransientClientModeManagerWhenConnectedToLocalOnlyBssid()
3585             throws Exception {
3586         // Ensure that we can create more client ifaces.
3587         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3588         when(mResources.getBoolean(
3589                 R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3590                 .thenReturn(true);
3591         when(mResources.getBoolean(
3592                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3593                 .thenReturn(true);
3594         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3595                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3596         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3597                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3598 
3599         enterClientModeActiveState();
3600 
3601         // Primary Connected to ssid1/bssid1
3602         WifiConfiguration config1 = new WifiConfiguration();
3603         config1.SSID = TEST_SSID_1;
3604         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
3605         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
3606 
3607         ConcreteClientModeManager additionalClientModeManager =
3608                 mock(ConcreteClientModeManager.class);
3609         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener1 =
3610                 new Mutable<>();
3611         doAnswer((invocation) -> {
3612             Object[] args = invocation.getArguments();
3613             additionalClientListener1.value =
3614                     (Listener<ConcreteClientModeManager>) args[0];
3615             return additionalClientModeManager;
3616         }).when(mWifiInjector).makeClientModeManager(
3617                 any(Listener.class), any(), eq(ROLE_CLIENT_LOCAL_ONLY),
3618                 anyBoolean());
3619         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
3620 
3621         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3622                 ExternalClientModeManagerRequestListener.class);
3623         // request for ssid2/bssid2
3624         mActiveModeWarden.requestLocalOnlyClientModeManager(
3625                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2, false);
3626         mLooper.dispatchAll();
3627         verify(mWifiInjector).makeClientModeManager(
3628                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_LOCAL_ONLY), anyBoolean());
3629         additionalClientListener1.value.onStarted(additionalClientModeManager);
3630         mLooper.dispatchAll();
3631         // Returns the new client mode manager.
3632         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3633                 ArgumentCaptor.forClass(ClientModeManager.class);
3634         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3635         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3636 
3637         // set additional CMM connected to ssid2/bssid2
3638         WifiConfiguration config2 = new WifiConfiguration();
3639         config2.SSID = TEST_SSID_2;
3640         when(additionalClientModeManager.getConnectedWifiConfiguration()).thenReturn(config2);
3641         when(additionalClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_2);
3642 
3643         // request for same ssid2/bssid2 for a different role.
3644         // request for one more CMM (should return the existing local only one).
3645         mActiveModeWarden.requestSecondaryTransientClientModeManager(
3646                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3647         mLooper.dispatchAll();
3648 
3649         // Don't make another client mode manager, but should switch role of existing client mode
3650         // manager.
3651         verify(mWifiInjector, never())
3652                 .makeClientModeManager(any(), any(), eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3653                         anyBoolean());
3654         ArgumentCaptor<Listener<ConcreteClientModeManager>>
3655                 additionalClientListener2 = ArgumentCaptor.forClass(
3656                         Listener.class);
3657         verify(additionalClientModeManager).setRole(eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3658                 eq(TEST_WORKSOURCE), additionalClientListener2.capture());
3659 
3660         // Simulate completion of role switch.
3661         additionalClientListener2.getValue().onRoleChanged(additionalClientModeManager);
3662 
3663         // Returns the existing client mode manager.
3664         verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
3665         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3666     }
3667 
3668     @Test
requestLowPrioSecondaryTransientClientModeManagerWhenConnectedToLocalOnlyBssid()3669     public void requestLowPrioSecondaryTransientClientModeManagerWhenConnectedToLocalOnlyBssid()
3670             throws Exception {
3671         // Ensure that we can create more client ifaces.
3672         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3673         when(mResources.getBoolean(
3674                 R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3675                 .thenReturn(true);
3676         when(mResources.getBoolean(
3677                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3678                 .thenReturn(true);
3679         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3680                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3681         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3682                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3683 
3684         enterClientModeActiveState();
3685 
3686         // Primary Connected to ssid1/bssid1
3687         WifiConfiguration config1 = new WifiConfiguration();
3688         config1.SSID = TEST_SSID_1;
3689         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
3690         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
3691 
3692         ConcreteClientModeManager additionalClientModeManager =
3693                 mock(ConcreteClientModeManager.class);
3694         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener1 =
3695                 new Mutable<>();
3696         doAnswer((invocation) -> {
3697             Object[] args = invocation.getArguments();
3698             additionalClientListener1.value =
3699                     (Listener<ConcreteClientModeManager>) args[0];
3700             return additionalClientModeManager;
3701         }).when(mWifiInjector).makeClientModeManager(
3702                 any(Listener.class), any(), eq(ROLE_CLIENT_LOCAL_ONLY),
3703                 anyBoolean());
3704         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
3705 
3706         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3707                 ExternalClientModeManagerRequestListener.class);
3708         // request for ssid2/bssid2
3709         mActiveModeWarden.requestLocalOnlyClientModeManager(
3710                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2, false);
3711         mLooper.dispatchAll();
3712         verify(mWifiInjector).makeClientModeManager(
3713                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_LOCAL_ONLY), anyBoolean());
3714         additionalClientListener1.value.onStarted(additionalClientModeManager);
3715         mLooper.dispatchAll();
3716         // Returns the new client mode manager.
3717         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3718                 ArgumentCaptor.forClass(ClientModeManager.class);
3719         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3720         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3721 
3722         // set additional CMM connected to ssid2/bssid2
3723         WifiConfiguration config2 = new WifiConfiguration();
3724         config2.SSID = TEST_SSID_2;
3725         when(additionalClientModeManager.getConnectedWifiConfiguration()).thenReturn(config2);
3726         when(additionalClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_2);
3727 
3728         // Now, deny the creation of STA for the new request
3729         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(false);
3730 
3731         // request for same ssid2/bssid2 for a different role.
3732         // request for one more CMM (should return null).
3733         mActiveModeWarden.requestSecondaryTransientClientModeManager(
3734                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3735         mLooper.dispatchAll();
3736 
3737         // Don't make another client mode manager or change role
3738         verify(mWifiInjector, never())
3739                 .makeClientModeManager(any(), any(), eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3740                         anyBoolean());
3741         verify(additionalClientModeManager, never()).setRole(eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3742                 eq(TEST_WORKSOURCE), any());
3743 
3744         // Ensure the request is rejected.
3745         verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
3746         assertNull(requestedClientModeManager.getValue());
3747     }
3748 
3749     @Test
requestSecondaryTransientClientModeManagerWhenDppInProgress()3750     public void requestSecondaryTransientClientModeManagerWhenDppInProgress()
3751             throws Exception {
3752         // Ensure that we can create more client ifaces.
3753         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3754         when(mResources.getBoolean(
3755                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3756                 .thenReturn(true);
3757         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3758                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3759 
3760         // Create primary STA.
3761         enterClientModeActiveState();
3762 
3763         // Start DPP session
3764         when(mDppManager.isSessionInProgress()).thenReturn(true);
3765 
3766         // request secondary transient CMM creation.
3767         ConcreteClientModeManager additionalClientModeManager =
3768                 mock(ConcreteClientModeManager.class);
3769         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
3770                 new Mutable<>();
3771         doAnswer((invocation) -> {
3772             Object[] args = invocation.getArguments();
3773             additionalClientListener.value =
3774                     (Listener<ConcreteClientModeManager>) args[0];
3775             return additionalClientModeManager;
3776         }).when(mWifiInjector).makeClientModeManager(
3777                 any(Listener.class), any(), eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
3778                 anyBoolean());
3779         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
3780 
3781         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3782                 ExternalClientModeManagerRequestListener.class);
3783         mActiveModeWarden.requestSecondaryTransientClientModeManager(
3784                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3785         mLooper.dispatchAll();
3786 
3787         // verify that we did not create a secondary CMM.
3788         verifyNoMoreInteractions(additionalClientModeManager);
3789         // Returns the existing primary client mode manager.
3790         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3791                 ArgumentCaptor.forClass(ClientModeManager.class);
3792         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3793         assertEquals(mClientModeManager, requestedClientModeManager.getValue());
3794 
3795         // Stop ongoing DPP session.
3796         when(mDppManager.isSessionInProgress()).thenReturn(false);
3797 
3798         // request secondary transient CMM creation again, now it should be allowed.
3799         mActiveModeWarden.requestSecondaryTransientClientModeManager(
3800                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3801         mLooper.dispatchAll();
3802         verify(mWifiInjector)
3803                 .makeClientModeManager(any(), eq(TEST_WORKSOURCE),
3804                         eq(ROLE_CLIENT_SECONDARY_TRANSIENT), anyBoolean());
3805         additionalClientListener.value.onStarted(additionalClientModeManager);
3806         mLooper.dispatchAll();
3807         // Returns the new secondary client mode manager.
3808         verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
3809         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
3810     }
3811 
3812     @Test
testRequestForSecondaryLocalOnlyForEnterCarModePrioritized()3813     public void testRequestForSecondaryLocalOnlyForEnterCarModePrioritized() throws Exception {
3814         // mock caller to have ENTER_CAR_MODE_PRIORITIZED
3815         when(mWifiPermissionsUtil.checkEnterCarModePrioritized(anyInt())).thenReturn(true);
3816         // Ensure that we can create more client ifaces.
3817         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3818         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3819                 .thenReturn(true);
3820         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
3821                 .thenReturn(true);
3822         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3823                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3824         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3825                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
3826 
3827         enterClientModeActiveState();
3828         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3829                 ArgumentCaptor.forClass(ClientModeManager.class);
3830         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3831                 ExternalClientModeManagerRequestListener.class);
3832         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
3833                 new Mutable<>();
3834         ConcreteClientModeManager additionalClientModeManager =
3835                 mock(ConcreteClientModeManager.class);
3836         doAnswer((invocation) -> {
3837             Object[] args = invocation.getArguments();
3838             additionalClientListener.value =
3839                     (Listener<ConcreteClientModeManager>) args[0];
3840             return additionalClientModeManager;
3841         }).when(mWifiInjector).makeClientModeManager(
3842                 any(Listener.class), any(), any(), anyBoolean());
3843         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
3844         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
3845 
3846         // mock requesting local only secondary
3847         mActiveModeWarden.requestLocalOnlyClientModeManager(
3848                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2, false);
3849         mLooper.dispatchAll();
3850         // Verify the primary is given to the externalRequestListener
3851         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3852         verify(mWifiInjector, never()).makeClientModeManager(
3853                 any(), any(), eq(ROLE_CLIENT_LOCAL_ONLY), anyBoolean());
3854         assertEquals(ROLE_CLIENT_PRIMARY, requestedClientModeManager.getValue().getRole());
3855 
3856         // Request for non local-only STA and verify the secondary STA is provided instead.
3857         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_LONG_LIVED);
3858         mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
3859                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
3860         mLooper.dispatchAll();
3861         verify(mWifiInjector).makeClientModeManager(any(), any(),
3862                 eq(ROLE_CLIENT_SECONDARY_LONG_LIVED), anyBoolean());
3863 
3864         additionalClientListener.value.onStarted(additionalClientModeManager);
3865         mLooper.dispatchAll();
3866         verify(externalRequestListener, times(2)).onAnswer(
3867                 requestedClientModeManager.capture());
3868         assertEquals(ROLE_CLIENT_SECONDARY_LONG_LIVED,
3869                 requestedClientModeManager.getValue().getRole());
3870     }
3871 
3872     @Test
testRequestForSecondaryLocalOnlyForShell()3873     public void testRequestForSecondaryLocalOnlyForShell() throws Exception {
3874         // mock caller to have ENTER_CAR_MODE_PRIORITIZED
3875         when(mWifiPermissionsUtil.checkEnterCarModePrioritized(anyInt())).thenReturn(true);
3876         // Ensure that we can create more client ifaces.
3877         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3878         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
3879                 .thenReturn(true);
3880         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
3881                 .thenReturn(true);
3882         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3883                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, false));
3884         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3885                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
3886 
3887         enterClientModeActiveState();
3888         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
3889                 ArgumentCaptor.forClass(ClientModeManager.class);
3890         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3891                 ExternalClientModeManagerRequestListener.class);
3892         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
3893                 new Mutable<>();
3894         ConcreteClientModeManager additionalClientModeManager =
3895                 mock(ConcreteClientModeManager.class);
3896         doAnswer((invocation) -> {
3897             Object[] args = invocation.getArguments();
3898             additionalClientListener.value =
3899                     (Listener<ConcreteClientModeManager>) args[0];
3900             return additionalClientModeManager;
3901         }).when(mWifiInjector).makeClientModeManager(
3902                 any(Listener.class), any(), any(), anyBoolean());
3903         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
3904         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
3905 
3906         // Request will shell uid for local-only STA and verify the secondary is provided instead.
3907         WorkSource shellWs = new WorkSource(0, "shell");
3908         mActiveModeWarden.requestLocalOnlyClientModeManager(
3909                 externalRequestListener, shellWs, TEST_SSID_2, TEST_BSSID_2, false);
3910         mLooper.dispatchAll();
3911         verify(mWifiInjector).makeClientModeManager(any(), any(),
3912                 eq(ROLE_CLIENT_LOCAL_ONLY), anyBoolean());
3913         additionalClientListener.value.onStarted(additionalClientModeManager);
3914         mLooper.dispatchAll();
3915         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
3916         verify(mWifiInjector).makeClientModeManager(
3917                 any(), any(), eq(ROLE_CLIENT_LOCAL_ONLY), anyBoolean());
3918         assertEquals(ROLE_CLIENT_LOCAL_ONLY, requestedClientModeManager.getValue().getRole());
3919     }
3920 
3921     @Test
configureHwOnMbbSwitch()3922     public void configureHwOnMbbSwitch()
3923             throws Exception {
3924         // Ensure that we can create more client ifaces.
3925         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
3926         when(mResources.getBoolean(
3927                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
3928                 .thenReturn(true);
3929         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
3930                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
3931 
3932         ConcreteClientModeManager additionalClientModeManager =
3933                 mock(ConcreteClientModeManager.class);
3934         ExternalClientModeManagerRequestListener externalRequestListener = mock(
3935                 ExternalClientModeManagerRequestListener.class);
3936         Listener<ConcreteClientModeManager> additionalClientListener =
3937                 requestAdditionalClientModeManager(ROLE_CLIENT_SECONDARY_TRANSIENT,
3938                         additionalClientModeManager, externalRequestListener, TEST_SSID_2,
3939                         TEST_BSSID_2);
3940 
3941         // Now simulate the MBB role switch.
3942         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
3943         mClientListener.onRoleChanged(mClientModeManager);
3944 
3945         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
3946         additionalClientListener.onRoleChanged(additionalClientModeManager);
3947 
3948         // verify last use case set is PREFER_PRIMARY
3949         ArgumentCaptor<Integer> useCaseCaptor = ArgumentCaptor.forClass(Integer.class);
3950         verify(mWifiNative, atLeastOnce()).setMultiStaUseCase(useCaseCaptor.capture());
3951         int lastUseCaseSet = useCaseCaptor.getValue().intValue();
3952         assertEquals(WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY, lastUseCaseSet);
3953 
3954         // verify last set of primary connection is for WIFI_IFACE_NAME_1
3955         ArgumentCaptor<String> ifaceNameCaptor = ArgumentCaptor.forClass(String.class);
3956         verify(mWifiNative, atLeastOnce()).setMultiStaPrimaryConnection(ifaceNameCaptor.capture());
3957         assertEquals(WIFI_IFACE_NAME_1, ifaceNameCaptor.getValue());
3958     }
3959 
3960     @Test
airplaneModeToggleOnDisablesWifi()3961     public void airplaneModeToggleOnDisablesWifi() throws Exception {
3962         enterClientModeActiveState();
3963         assertInEnabledState();
3964 
3965         assertWifiShutDown(() -> {
3966             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
3967             mActiveModeWarden.airplaneModeToggled();
3968             mLooper.dispatchAll();
3969         });
3970         verify(mLastCallerInfoManager).put(eq(WifiManager.API_WIFI_ENABLED), anyInt(), anyInt(),
3971                 anyInt(), eq("android_apm"), eq(false));
3972 
3973         mClientListener.onStopped(mClientModeManager);
3974         mLooper.dispatchAll();
3975         assertInDisabledState();
3976     }
3977 
3978     @Test
airplaneModeToggleOnDisablesSoftAp()3979     public void airplaneModeToggleOnDisablesSoftAp() throws Exception {
3980         enterSoftApActiveMode();
3981         assertInEnabledState();
3982 
3983         assertWifiShutDown(() -> {
3984             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
3985             mActiveModeWarden.airplaneModeToggled();
3986             mLooper.dispatchAll();
3987         });
3988 
3989         mSoftApListener.onStopped(mSoftApManager);
3990         mLooper.dispatchAll();
3991         assertInDisabledState();
3992     }
3993 
3994     @Test
airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager()3995     public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager()
3996             throws Exception {
3997         enterClientModeActiveState();
3998         assertInEnabledState();
3999 
4000         // APM toggle on
4001         assertWifiShutDown(() -> {
4002             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
4003             mActiveModeWarden.airplaneModeToggled();
4004             mLooper.dispatchAll();
4005         });
4006 
4007 
4008         // APM toggle off before the stop is complete.
4009         assertInEnabledState();
4010         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
4011         mActiveModeWarden.airplaneModeToggled();
4012         mLooper.dispatchAll();
4013 
4014         mClientListener.onStopped(mClientModeManager);
4015         mLooper.dispatchAll();
4016 
4017         verify(mWifiInjector, times(2)).makeClientModeManager(
4018                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
4019 
4020         mClientListener.onStarted(mClientModeManager);
4021         mLooper.dispatchAll();
4022 
4023         // We should be back to enabled state.
4024         assertInEnabledState();
4025     }
4026 
4027     @Test
airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager2()4028     public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager2()
4029             throws Exception {
4030         enterClientModeActiveState();
4031         assertInEnabledState();
4032 
4033         // APM toggle on
4034         assertWifiShutDown(() -> {
4035             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
4036             mActiveModeWarden.airplaneModeToggled();
4037             mLooper.dispatchAll();
4038         });
4039 
4040 
4041         // APM toggle off before the stop is complete.
4042         assertInEnabledState();
4043         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
4044         mActiveModeWarden.airplaneModeToggled();
4045         // This test is identical to
4046         // airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithOneModeManager, except the
4047         // dispatchAll() here is removed. There could be a race between airplaneModeToggled and
4048         // mClientListener.onStopped(). See b/160105640#comment5.
4049 
4050         mClientListener.onStopped(mClientModeManager);
4051         mLooper.dispatchAll();
4052 
4053         verify(mWifiInjector, times(2)).makeClientModeManager(
4054                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
4055 
4056         mClientListener.onStarted(mClientModeManager);
4057         mLooper.dispatchAll();
4058 
4059         // We should be back to enabled state.
4060         assertInEnabledState();
4061     }
4062 
4063     @Test
airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithTwoModeManager()4064     public void airplaneModeToggleOffIsDeferredWhileProcessingToggleOnWithTwoModeManager()
4065             throws Exception {
4066         enterClientModeActiveState();
4067         enterSoftApActiveMode();
4068         assertInEnabledState();
4069 
4070         // APM toggle on
4071         assertWifiShutDown(() -> {
4072             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
4073             mActiveModeWarden.airplaneModeToggled();
4074             mLooper.dispatchAll();
4075         });
4076 
4077 
4078         // APM toggle off before the stop is complete.
4079         assertInEnabledState();
4080         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
4081         mActiveModeWarden.airplaneModeToggled();
4082         mLooper.dispatchAll();
4083 
4084         // AP stopped, should not process APM toggle.
4085         mSoftApListener.onStopped(mSoftApManager);
4086         mLooper.dispatchAll();
4087         verify(mWifiInjector, times(1)).makeClientModeManager(
4088                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
4089 
4090         // STA also stopped, should process APM toggle.
4091         mClientListener.onStopped(mClientModeManager);
4092         mLooper.dispatchAll();
4093         verify(mWifiInjector, times(2)).makeClientModeManager(
4094                 any(), any(), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
4095 
4096         mClientListener.onStarted(mClientModeManager);
4097         mLooper.dispatchAll();
4098 
4099         // We should be back to enabled state.
4100         assertInEnabledState();
4101     }
4102 
4103     @Test
propagateVerboseLoggingFlagToClientModeManager()4104     public void propagateVerboseLoggingFlagToClientModeManager() throws Exception {
4105         mActiveModeWarden.enableVerboseLogging(true);
4106         enterClientModeActiveState();
4107         assertInEnabledState();
4108         verify(mWifiInjector).makeClientModeManager(any(), any(), any(), eq(true));
4109 
4110         mActiveModeWarden.enableVerboseLogging(false);
4111         verify(mClientModeManager).enableVerboseLogging(false);
4112     }
4113 
4114     @Test
propagateConnectedWifiScorerToPrimaryClientModeManager()4115     public void propagateConnectedWifiScorerToPrimaryClientModeManager() throws Exception {
4116         IBinder iBinder = mock(IBinder.class);
4117         IWifiConnectedNetworkScorer iScorer = mock(IWifiConnectedNetworkScorer.class);
4118         mActiveModeWarden.setWifiConnectedNetworkScorer(iBinder, iScorer);
4119         verify(iScorer).onSetScoreUpdateObserver(mExternalScoreUpdateObserverProxy);
4120         enterClientModeActiveState();
4121         assertInEnabledState();
4122         verify(mClientModeManager).setWifiConnectedNetworkScorer(iBinder, iScorer);
4123 
4124         mActiveModeWarden.clearWifiConnectedNetworkScorer();
4125         verify(mClientModeManager).clearWifiConnectedNetworkScorer();
4126 
4127         mActiveModeWarden.setWifiConnectedNetworkScorer(iBinder, iScorer);
4128         verify(mClientModeManager, times(2)).setWifiConnectedNetworkScorer(iBinder, iScorer);
4129     }
4130 
4131     @Test
propagateConnectedWifiScorerToPrimaryClientModeManager_enterScanOnlyState()4132     public void propagateConnectedWifiScorerToPrimaryClientModeManager_enterScanOnlyState()
4133             throws Exception {
4134         IBinder iBinder = mock(IBinder.class);
4135         IWifiConnectedNetworkScorer iScorer = mock(IWifiConnectedNetworkScorer.class);
4136         mActiveModeWarden.setWifiConnectedNetworkScorer(iBinder, iScorer);
4137         verify(iScorer).onSetScoreUpdateObserver(mExternalScoreUpdateObserverProxy);
4138         enterClientModeActiveState();
4139         assertInEnabledState();
4140         verify(mClientModeManager).setWifiConnectedNetworkScorer(iBinder, iScorer);
4141 
4142         enterScanOnlyModeActiveState(true);
4143 
4144         verify(mClientModeManager).clearWifiConnectedNetworkScorer();
4145     }
4146 
4147     @Test
handleWifiScorerSetScoreUpdateObserverFailure()4148     public void handleWifiScorerSetScoreUpdateObserverFailure() throws Exception {
4149         IBinder iBinder = mock(IBinder.class);
4150         IWifiConnectedNetworkScorer iScorer = mock(IWifiConnectedNetworkScorer.class);
4151         doThrow(new RemoteException()).when(iScorer).onSetScoreUpdateObserver(any());
4152         mActiveModeWarden.setWifiConnectedNetworkScorer(iBinder, iScorer);
4153         verify(iScorer).onSetScoreUpdateObserver(mExternalScoreUpdateObserverProxy);
4154         enterClientModeActiveState();
4155         assertInEnabledState();
4156         // Ensure we did not propagate the scorer.
4157         verify(mClientModeManager, never()).setWifiConnectedNetworkScorer(iBinder, iScorer);
4158     }
4159 
4160     /** Verify that the primary changed callback is triggered when entering client mode. */
4161     @Test
testAddPrimaryClientModeManager()4162     public void testAddPrimaryClientModeManager() throws Exception {
4163         enterClientModeActiveState();
4164 
4165         verify(mPrimaryChangedCallback).onChange(null, mClientModeManager);
4166     }
4167 
4168     /** Verify the primary changed callback is not triggered when there is no primary. */
4169     @Test
testNoAddPrimaryClientModeManager()4170     public void testNoAddPrimaryClientModeManager() throws Exception {
4171         enterScanOnlyModeActiveState();
4172 
4173         verify(mPrimaryChangedCallback, never()).onChange(any(), any());
4174     }
4175 
4176     /**
4177      * Verify the primary changed callback is triggered when changing the primary from one
4178      * ClientModeManager to another.
4179      */
4180     @Test
testSwitchPrimaryClientModeManager()4181     public void testSwitchPrimaryClientModeManager() throws Exception {
4182         // Ensure that we can create more client ifaces.
4183         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
4184         when(mResources.getBoolean(
4185                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
4186                 .thenReturn(true);
4187         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
4188                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_TRANSIENT, false));
4189 
4190         enterClientModeActiveState();
4191 
4192         verify(mPrimaryChangedCallback).onChange(null, mClientModeManager);
4193 
4194         // Connected to ssid1/bssid1
4195         WifiConfiguration config1 = new WifiConfiguration();
4196         config1.SSID = TEST_SSID_1;
4197         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
4198         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
4199 
4200         ConcreteClientModeManager additionalClientModeManager =
4201                 mock(ConcreteClientModeManager.class);
4202         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
4203                 new Mutable<>();
4204         doAnswer((invocation) -> {
4205             Object[] args = invocation.getArguments();
4206             additionalClientListener.value =
4207                     (Listener<ConcreteClientModeManager>) args[0];
4208             return additionalClientModeManager;
4209         }).when(mWifiInjector).makeClientModeManager(
4210                 any(Listener.class), any(), eq(ROLE_CLIENT_SECONDARY_TRANSIENT),
4211                 anyBoolean());
4212         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
4213 
4214         ExternalClientModeManagerRequestListener externalRequestListener = mock(
4215                 ExternalClientModeManagerRequestListener.class);
4216         // request for ssid2/bssid2
4217         mActiveModeWarden.requestSecondaryTransientClientModeManager(
4218                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
4219         mLooper.dispatchAll();
4220         verify(mWifiInjector).makeClientModeManager(
4221                 any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_SECONDARY_TRANSIENT), anyBoolean());
4222         additionalClientListener.value.onStarted(additionalClientModeManager);
4223         mLooper.dispatchAll();
4224         // Returns the new client mode manager.
4225         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
4226                 ArgumentCaptor.forClass(ClientModeManager.class);
4227         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
4228         assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
4229 
4230         // primary didn't change yet
4231         verify(mPrimaryChangedCallback, never()).onChange(any(), eq(additionalClientModeManager));
4232 
4233         // change primary
4234         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
4235         mClientListener.onRoleChanged(mClientModeManager);
4236         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
4237         additionalClientListener.value.onRoleChanged(additionalClientModeManager);
4238 
4239         // verify callback triggered
4240         verify(mPrimaryChangedCallback).onChange(mClientModeManager, null);
4241         verify(mPrimaryChangedCallback).onChange(null, additionalClientModeManager);
4242     }
4243 
4244     @Test
testRegisterPrimaryCmmChangedCallbackWhenConnectModeActiveState()4245     public void testRegisterPrimaryCmmChangedCallbackWhenConnectModeActiveState() throws Exception {
4246         enterClientModeActiveState();
4247 
4248         // register a new primary cmm change callback.
4249         ActiveModeWarden.PrimaryClientModeManagerChangedCallback primarCmmCallback = mock(
4250                 ActiveModeWarden.PrimaryClientModeManagerChangedCallback.class);
4251         mActiveModeWarden.registerPrimaryClientModeManagerChangedCallback(primarCmmCallback);
4252         // Ensure we get the callback immediately.
4253         verify(primarCmmCallback).onChange(null, mClientModeManager);
4254     }
4255 
4256     @Test
testGetCmmInRolesWithNullRoleInOneCmm()4257     public void testGetCmmInRolesWithNullRoleInOneCmm() throws Exception {
4258         enterClientModeActiveState();
4259 
4260         // Ensure that we can create more client ifaces.
4261         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
4262         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
4263                 .thenReturn(true);
4264 
4265         ConcreteClientModeManager additionalClientModeManager =
4266                 mock(ConcreteClientModeManager.class);
4267         when(mWifiInjector.makeClientModeManager(
4268                 any(), any(), any(), anyBoolean())).thenReturn(additionalClientModeManager);
4269 
4270         mActiveModeWarden.requestLocalOnlyClientModeManager(
4271                 mock(ExternalClientModeManagerRequestListener.class),
4272                 TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2, false);
4273         mLooper.dispatchAll();
4274 
4275         // No role set, should be ignored.
4276         when(additionalClientModeManager.getRole()).thenReturn(null);
4277         assertEquals(1, mActiveModeWarden.getClientModeManagersInRoles(
4278                 ROLE_CLIENT_PRIMARY, ROLE_CLIENT_LOCAL_ONLY).size());
4279 
4280         // Role set, should be included.
4281         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
4282         assertEquals(2, mActiveModeWarden.getClientModeManagersInRoles(
4283                 ROLE_CLIENT_PRIMARY, ROLE_CLIENT_LOCAL_ONLY).size());
4284     }
4285 
4286     /**
4287      * Helper method to enter the EnabledState and set ClientModeManager in ScanOnlyMode during
4288      * emergency scan processing.
4289      */
indicateStartOfEmergencyScan( boolean hasAnyOtherStaToggleEnabled, @Nullable ActiveModeManager.ClientRole expectedRole)4290     private void indicateStartOfEmergencyScan(
4291             boolean hasAnyOtherStaToggleEnabled,
4292             @Nullable ActiveModeManager.ClientRole expectedRole)
4293             throws Exception {
4294         String fromState = mActiveModeWarden.getCurrentMode();
4295         mActiveModeWarden.setEmergencyScanRequestInProgress(true);
4296         mLooper.dispatchAll();
4297 
4298         if (!hasAnyOtherStaToggleEnabled) {
4299             when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SCAN_ONLY);
4300             mClientListener.onStarted(mClientModeManager);
4301             mLooper.dispatchAll();
4302             verify(mWifiInjector).makeClientModeManager(
4303                     any(), eq(SETTINGS_WORKSOURCE), eq(ROLE_CLIENT_SCAN_ONLY), anyBoolean());
4304             verify(mModeChangeCallback).onActiveModeManagerAdded(mClientModeManager);
4305             verify(mScanRequestProxy).enableScanning(true, false);
4306             verify(mBatteryStats).reportWifiOn();
4307             verify(mBatteryStats).reportWifiState(
4308                     BatteryStatsManager.WIFI_STATE_OFF_SCANNING, null);
4309         } else {
4310             verify(mClientModeManager).setRole(eq(expectedRole), any());
4311             verify(mClientModeManager, never()).stop();
4312             assertEquals(fromState, mActiveModeWarden.getCurrentMode());
4313         }
4314         assertInEnabledState();
4315     }
4316 
indicateEndOfEmergencyScan( boolean hasAnyOtherStaToggleEnabled, @Nullable ActiveModeManager.ClientRole expectedRole)4317     private void indicateEndOfEmergencyScan(
4318             boolean hasAnyOtherStaToggleEnabled,
4319             @Nullable ActiveModeManager.ClientRole expectedRole) {
4320         String fromState = mActiveModeWarden.getCurrentMode();
4321         mActiveModeWarden.setEmergencyScanRequestInProgress(false);
4322         mLooper.dispatchAll();
4323         if (!hasAnyOtherStaToggleEnabled) {
4324             mClientListener.onStopped(mClientModeManager);
4325             mLooper.dispatchAll();
4326             verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
4327             verify(mScanRequestProxy).enableScanning(false, false);
4328             assertInDisabledState();
4329         } else {
4330             // Nothing changes.
4331             verify(mClientModeManager).setRole(eq(expectedRole), any());
4332             verify(mClientModeManager, never()).stop();
4333             assertEquals(fromState, mActiveModeWarden.getCurrentMode());
4334         }
4335     }
4336 
4337     @Test
testEmergencyScanWhenWifiDisabled()4338     public void testEmergencyScanWhenWifiDisabled() throws Exception {
4339         // Wifi fully disabled.
4340         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
4341         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
4342         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
4343         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
4344 
4345         indicateStartOfEmergencyScan(false, null);
4346 
4347         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
4348         clearInvocations(mClientModeManager);
4349 
4350         indicateEndOfEmergencyScan(false, null);
4351     }
4352 
4353     @Test
testEmergencyScanWhenWifiEnabled()4354     public void testEmergencyScanWhenWifiEnabled() throws Exception {
4355         // Wifi enabled.
4356         enterClientModeActiveState();
4357 
4358         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4359 
4360         indicateStartOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
4361 
4362         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
4363         clearInvocations(mClientModeManager);
4364 
4365         indicateEndOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
4366     }
4367 
4368     @Test
testEmergencyScanWhenScanOnlyModeEnabled()4369     public void testEmergencyScanWhenScanOnlyModeEnabled() throws Exception {
4370         // Scan only enabled.
4371         enterScanOnlyModeActiveState();
4372 
4373         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4374 
4375         indicateStartOfEmergencyScan(true, ROLE_CLIENT_SCAN_ONLY);
4376 
4377         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
4378         clearInvocations(mClientModeManager);
4379 
4380         indicateEndOfEmergencyScan(true, ROLE_CLIENT_SCAN_ONLY);
4381     }
4382 
4383     @Test
testEmergencyScanWhenEcmOnWithWifiDisableInEcbm()4384     public void testEmergencyScanWhenEcmOnWithWifiDisableInEcbm() throws Exception {
4385         // Wifi enabled.
4386         enterClientModeActiveState();
4387 
4388         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4389 
4390         // Test with WifiDisableInECBM turned on
4391         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
4392 
4393         assertWifiShutDown(() -> {
4394             // test ecm changed
4395             emergencyCallbackModeChanged(true);
4396             mLooper.dispatchAll();
4397             // fully shutdown
4398             mClientListener.onStopped(mClientModeManager);
4399             mLooper.dispatchAll();
4400         });
4401         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4402 
4403         indicateStartOfEmergencyScan(false, null);
4404 
4405         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
4406         clearInvocations(mClientModeManager);
4407 
4408         indicateEndOfEmergencyScan(false, null);
4409     }
4410 
4411     @Test
testEmergencyScanWhenEcmOnWithoutWifiDisableInEcbm()4412     public void testEmergencyScanWhenEcmOnWithoutWifiDisableInEcbm() throws Exception {
4413         // Wifi enabled.
4414         enterClientModeActiveState();
4415 
4416         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4417 
4418         // Test with WifiDisableInECBM turned off
4419         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
4420 
4421         assertEnteredEcmMode(() -> {
4422             // test ecm changed
4423             emergencyCallbackModeChanged(true);
4424             mLooper.dispatchAll();
4425         });
4426 
4427         indicateStartOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
4428 
4429         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
4430         clearInvocations(mClientModeManager);
4431 
4432         indicateEndOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
4433     }
4434 
4435     @Test
testWifiDisableDuringEmergencyScan()4436     public void testWifiDisableDuringEmergencyScan() throws Exception {
4437         // Wifi enabled.
4438         enterClientModeActiveState();
4439 
4440         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4441 
4442         indicateStartOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
4443 
4444         // Toggle off wifi
4445         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
4446         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
4447         mLooper.dispatchAll();
4448 
4449         // Ensure that we switched the role to scan only state because of the emergency scan.
4450         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SCAN_ONLY);
4451         mClientListener.onRoleChanged(mClientModeManager);
4452         mLooper.dispatchAll();
4453         verify(mClientModeManager).setRole(ROLE_CLIENT_SCAN_ONLY, INTERNAL_REQUESTOR_WS);
4454         verify(mClientModeManager, never()).stop();
4455         assertInEnabledState();
4456 
4457         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
4458         clearInvocations(mClientModeManager);
4459 
4460         indicateEndOfEmergencyScan(false, null);
4461     }
4462 
4463     @Test
testScanOnlyModeDisableDuringEmergencyScan()4464     public void testScanOnlyModeDisableDuringEmergencyScan() throws Exception {
4465         // Scan only enabled.
4466         enterScanOnlyModeActiveState();
4467 
4468         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4469 
4470         indicateStartOfEmergencyScan(true, ROLE_CLIENT_SCAN_ONLY);
4471 
4472         // To reset setRole invocation above which is checked below.
4473         clearInvocations(mClientModeManager);
4474 
4475         // Toggle off scan only mode
4476         when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false);
4477         when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(false);
4478         mActiveModeWarden.scanAlwaysModeChanged();
4479         mLooper.dispatchAll();
4480 
4481         // Ensure that we remained in scan only state because of the emergency scan.
4482         verify(mClientModeManager).setRole(eq(ROLE_CLIENT_SCAN_ONLY), any());
4483         verify(mClientModeManager, never()).stop();
4484         assertInEnabledState();
4485 
4486         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
4487         clearInvocations(mClientModeManager);
4488 
4489         indicateEndOfEmergencyScan(false, null);
4490     }
4491 
4492     @Test
testEcmOffWithWifiDisabledStateDuringEmergencyScan()4493     public void testEcmOffWithWifiDisabledStateDuringEmergencyScan() throws Exception {
4494         // Wifi enabled.
4495         enterClientModeActiveState();
4496 
4497         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4498 
4499         // Test with WifiDisableInECBM turned on
4500         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
4501 
4502         assertWifiShutDown(() -> {
4503             // test ecm changed
4504             emergencyCallbackModeChanged(true);
4505             mLooper.dispatchAll();
4506             // fully shutdown
4507             mClientListener.onStopped(mClientModeManager);
4508             mLooper.dispatchAll();
4509         });
4510         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4511 
4512         indicateStartOfEmergencyScan(false, null);
4513 
4514         // Now turn off ECM
4515         emergencyCallbackModeChanged(false);
4516         mLooper.dispatchAll();
4517 
4518         // Ensure we turned wifi back on.
4519         verify(mClientModeManager).setRole(eq(ROLE_CLIENT_PRIMARY), any());
4520         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_PRIMARY);
4521         mClientListener.onRoleChanged(mClientModeManager);
4522         verify(mScanRequestProxy).enableScanning(true, true);
4523         assertInEnabledState();
4524 
4525         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
4526         clearInvocations(mClientModeManager);
4527 
4528         indicateEndOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
4529     }
4530 
4531     @Test
testEcmOffWithoutWifiDisabledStateDuringEmergencyScan()4532     public void testEcmOffWithoutWifiDisabledStateDuringEmergencyScan() throws Exception {
4533         // Wifi enabled.
4534         enterClientModeActiveState();
4535 
4536         reset(mBatteryStats, mScanRequestProxy, mModeChangeCallback);
4537 
4538         // Test with WifiDisableInECBM turned off
4539         when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
4540 
4541         assertEnteredEcmMode(() -> {
4542             // test ecm changed
4543             emergencyCallbackModeChanged(true);
4544             mLooper.dispatchAll();
4545         });
4546 
4547         // Now turn off ECM
4548         emergencyCallbackModeChanged(false);
4549         mLooper.dispatchAll();
4550 
4551         // Ensure that we remained in connected state.
4552         verify(mClientModeManager).setRole(eq(ROLE_CLIENT_PRIMARY), any());
4553         verify(mClientModeManager, never()).stop();
4554         assertInEnabledState();
4555 
4556         // To reset setRole invocation above which is checked inside |indicateEndOfEmergencyScan|
4557         clearInvocations(mClientModeManager);
4558 
4559         indicateEndOfEmergencyScan(true, ROLE_CLIENT_PRIMARY);
4560     }
4561 
4562     @Test
testRequestForSecondaryLocalOnlyForPreSAppWithUserConnect()4563     public void testRequestForSecondaryLocalOnlyForPreSAppWithUserConnect() throws Exception {
4564         // Ensure that we can create more client ifaces.
4565         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
4566         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
4567                 .thenReturn(true);
4568         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
4569                 .thenReturn(true);
4570         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(false);
4571         when(mWifiPermissionsUtil.isTargetSdkLessThan(
4572                 TEST_PACKAGE, Build.VERSION_CODES.S, TEST_UID))
4573                 .thenReturn(true);
4574         when(mWifiPermissionsUtil.isTargetSdkLessThan(
4575                 "system-service", Build.VERSION_CODES.S, Process.SYSTEM_UID))
4576                 .thenReturn(false);
4577         assertFalse(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
4578                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, true));
4579         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
4580                 TEST_WORKSOURCE, ROLE_CLIENT_SECONDARY_LONG_LIVED, false));
4581 
4582         enterClientModeActiveState();
4583         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
4584                 ArgumentCaptor.forClass(ClientModeManager.class);
4585         ExternalClientModeManagerRequestListener externalRequestListener = mock(
4586                 ExternalClientModeManagerRequestListener.class);
4587         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
4588                 new Mutable<>();
4589         ConcreteClientModeManager additionalClientModeManager =
4590                 mock(ConcreteClientModeManager.class);
4591         doAnswer((invocation) -> {
4592             Object[] args = invocation.getArguments();
4593             additionalClientListener.value =
4594                     (Listener<ConcreteClientModeManager>) args[0];
4595             return additionalClientModeManager;
4596         }).when(mWifiInjector).makeClientModeManager(
4597                 any(Listener.class), any(), any(), anyBoolean());
4598         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
4599         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
4600 
4601         // mock requesting local only secondary
4602         mActiveModeWarden.requestLocalOnlyClientModeManager(
4603                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2, true);
4604         mLooper.dispatchAll();
4605         // Verify the primary is given to the externalRequestListener
4606         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
4607         verify(mWifiInjector, never()).makeClientModeManager(
4608                 any(), any(), eq(ROLE_CLIENT_LOCAL_ONLY), anyBoolean());
4609         assertEquals(ROLE_CLIENT_PRIMARY, requestedClientModeManager.getValue().getRole());
4610 
4611         // Request for non local-only STA and verify the secondary STA is provided instead.
4612         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_LONG_LIVED);
4613         mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
4614                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2);
4615         mLooper.dispatchAll();
4616         verify(mWifiInjector).makeClientModeManager(any(), any(),
4617                 eq(ROLE_CLIENT_SECONDARY_LONG_LIVED), anyBoolean());
4618 
4619         additionalClientListener.value.onStarted(additionalClientModeManager);
4620         mLooper.dispatchAll();
4621         verify(externalRequestListener, times(2)).onAnswer(
4622                 requestedClientModeManager.capture());
4623         assertEquals(ROLE_CLIENT_SECONDARY_LONG_LIVED,
4624                 requestedClientModeManager.getValue().getRole());
4625     }
4626 
4627     @Test
testRequestForSecondaryLocalOnlyForAppWithUserConnect()4628     public void testRequestForSecondaryLocalOnlyForAppWithUserConnect() throws Exception {
4629         // Ensure that we can create more client ifaces.
4630         when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
4631         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
4632                 .thenReturn(true);
4633         when(mWifiPermissionsUtil.isSystem(TEST_PACKAGE, TEST_UID)).thenReturn(false);
4634         when(mWifiPermissionsUtil.isTargetSdkLessThan(
4635                 TEST_PACKAGE, Build.VERSION_CODES.S, TEST_UID))
4636                 .thenReturn(false);
4637         assertTrue(mActiveModeWarden.canRequestMoreClientModeManagersInRole(
4638                 TEST_WORKSOURCE, ROLE_CLIENT_LOCAL_ONLY, true));
4639 
4640         enterClientModeActiveState();
4641         ArgumentCaptor<ClientModeManager> requestedClientModeManager =
4642                 ArgumentCaptor.forClass(ClientModeManager.class);
4643         ExternalClientModeManagerRequestListener externalRequestListener = mock(
4644                 ExternalClientModeManagerRequestListener.class);
4645         Mutable<Listener<ConcreteClientModeManager>> additionalClientListener =
4646                 new Mutable<>();
4647         ConcreteClientModeManager additionalClientModeManager =
4648                 mock(ConcreteClientModeManager.class);
4649         doAnswer((invocation) -> {
4650             Object[] args = invocation.getArguments();
4651             additionalClientListener.value =
4652                     (Listener<ConcreteClientModeManager>) args[0];
4653             return additionalClientModeManager;
4654         }).when(mWifiInjector).makeClientModeManager(
4655                 any(Listener.class), any(), any(), anyBoolean());
4656         when(additionalClientModeManager.getInterfaceName()).thenReturn(WIFI_IFACE_NAME_1);
4657         when(additionalClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
4658 
4659         // mock requesting local only secondary
4660         mActiveModeWarden.requestLocalOnlyClientModeManager(
4661                 externalRequestListener, TEST_WORKSOURCE, TEST_SSID_2, TEST_BSSID_2, true);
4662         mLooper.dispatchAll();
4663         WorkSource ws = new WorkSource(TEST_WORKSOURCE);
4664         ws.add(SETTINGS_WORKSOURCE);
4665         verify(mWifiInjector).makeClientModeManager(
4666                 any(), eq(ws), eq(ROLE_CLIENT_LOCAL_ONLY), anyBoolean());
4667         additionalClientListener.value.onStarted(additionalClientModeManager);
4668         mLooper.dispatchAll();
4669         // Verify the primary is given to the externalRequestListener
4670         verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
4671 
4672         assertEquals(ROLE_CLIENT_LOCAL_ONLY, requestedClientModeManager.getValue().getRole());
4673     }
4674 
4675     @Test
testSetAndGetWifiState()4676     public void testSetAndGetWifiState() {
4677         int invalidState = 5;
4678         mActiveModeWarden.setWifiStateForApiCalls(WIFI_STATE_ENABLED);
4679         assertEquals(WIFI_STATE_ENABLED, mActiveModeWarden.getWifiState());
4680         mActiveModeWarden.setWifiStateForApiCalls(invalidState);
4681         assertEquals(WIFI_STATE_ENABLED, mActiveModeWarden.getWifiState());
4682     }
4683 
4684     /**
4685      * Verifies that getSupportedFeatureSet() adds capabilities based on interface
4686      * combination.
4687      */
4688     @Test
testGetSupportedFeaturesForStaApConcurrency()4689     public void testGetSupportedFeaturesForStaApConcurrency() throws Exception {
4690         enterScanOnlyModeActiveState();
4691         long supportedFeaturesFromWifiNative = WifiManager.WIFI_FEATURE_OWE;
4692         when(mWifiNative.getSupportedFeatureSet(null)).thenReturn(
4693                 supportedFeaturesFromWifiNative);
4694         when(mWifiNative.isStaApConcurrencySupported()).thenReturn(false);
4695         mClientListener.onStarted(mClientModeManager);
4696 
4697         assertEquals(supportedFeaturesFromWifiNative,
4698                 mActiveModeWarden.getSupportedFeatureSet());
4699 
4700         when(mWifiNative.isStaApConcurrencySupported()).thenReturn(true);
4701         mClientListener.onStarted(mClientModeManager);
4702 
4703         assertEquals(supportedFeaturesFromWifiNative | WifiManager.WIFI_FEATURE_AP_STA,
4704                 mActiveModeWarden.getSupportedFeatureSet());
4705     }
4706 
4707     /**
4708      * Verifies that getSupportedFeatureSet() adds capabilities based on interface
4709      * combination.
4710      */
4711     @Test
testGetSupportedFeaturesForStaStaConcurrency()4712     public void testGetSupportedFeaturesForStaStaConcurrency() throws Exception {
4713         assumeTrue(SdkLevel.isAtLeastS());
4714         enterScanOnlyModeActiveState();
4715         long supportedFeaturesFromWifiNative = WifiManager.WIFI_FEATURE_OWE;
4716         when(mWifiNative.getSupportedFeatureSet(null)).thenReturn(
4717                 supportedFeaturesFromWifiNative);
4718 
4719         mClientListener.onStarted(mClientModeManager);
4720         assertEquals(supportedFeaturesFromWifiNative, mActiveModeWarden.getSupportedFeatureSet());
4721 
4722         when(mWifiNative.isStaStaConcurrencySupported()).thenReturn(true);
4723         when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
4724                 .thenReturn(true);
4725         mClientListener.onStarted(mClientModeManager);
4726         assertEquals(supportedFeaturesFromWifiNative
4727                         | WifiManager.WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY,
4728                 mActiveModeWarden.getSupportedFeatureSet());
4729 
4730         when(mResources.getBoolean(
4731                 R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled))
4732                 .thenReturn(true);
4733         mClientListener.onStarted(mClientModeManager);
4734         assertEquals(supportedFeaturesFromWifiNative
4735                         | WifiManager.WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY
4736                         | WifiManager.WIFI_FEATURE_ADDITIONAL_STA_MBB,
4737                 mActiveModeWarden.getSupportedFeatureSet());
4738 
4739         when(mResources.getBoolean(R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled))
4740                 .thenReturn(true);
4741         when(mResources.getBoolean(R.bool.config_wifiMultiStaMultiInternetConcurrencyEnabled))
4742                 .thenReturn(true);
4743         mClientListener.onStarted(mClientModeManager);
4744         assertEquals(supportedFeaturesFromWifiNative
4745                         | WifiManager.WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY
4746                         | WifiManager.WIFI_FEATURE_ADDITIONAL_STA_MBB
4747                         | WifiManager.WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED
4748                         | WifiManager.WIFI_FEATURE_ADDITIONAL_STA_MULTI_INTERNET,
4749                 mActiveModeWarden.getSupportedFeatureSet());
4750     }
4751 
testGetSupportedFeaturesCaseForMacRandomization( long supportedFeaturesFromWifiNative, boolean apMacRandomizationEnabled, boolean staConnectedMacRandomizationEnabled, boolean p2pMacRandomizationEnabled)4752     private long testGetSupportedFeaturesCaseForMacRandomization(
4753             long supportedFeaturesFromWifiNative, boolean apMacRandomizationEnabled,
4754             boolean staConnectedMacRandomizationEnabled, boolean p2pMacRandomizationEnabled) {
4755         when(mResources.getBoolean(
4756                 R.bool.config_wifi_connected_mac_randomization_supported))
4757                 .thenReturn(staConnectedMacRandomizationEnabled);
4758         when(mResources.getBoolean(
4759                 R.bool.config_wifi_ap_mac_randomization_supported))
4760                 .thenReturn(apMacRandomizationEnabled);
4761         when(mResources.getBoolean(
4762                 R.bool.config_wifi_p2p_mac_randomization_supported))
4763                 .thenReturn(p2pMacRandomizationEnabled);
4764         when(mWifiNative.getSupportedFeatureSet(anyString()))
4765                 .thenReturn(supportedFeaturesFromWifiNative);
4766         mClientListener.onStarted(mClientModeManager);
4767         mLooper.dispatchAll();
4768         return mActiveModeWarden.getSupportedFeatureSet();
4769     }
4770 
4771     /** Verifies that syncGetSupportedFeatures() masks out capabilities based on system flags. */
4772     @Test
syncGetSupportedFeaturesForMacRandomization()4773     public void syncGetSupportedFeaturesForMacRandomization() throws Exception {
4774         final long featureStaConnectedMacRandomization =
4775                 WifiManager.WIFI_FEATURE_CONNECTED_RAND_MAC;
4776         final long featureApMacRandomization =
4777                 WifiManager.WIFI_FEATURE_AP_RAND_MAC;
4778         final long featureP2pMacRandomization =
4779                 WifiManager.WIFI_FEATURE_CONNECTED_RAND_MAC;
4780 
4781         enterClientModeActiveState();
4782         assertEquals(featureStaConnectedMacRandomization | featureApMacRandomization
4783                         | featureP2pMacRandomization,
4784                 testGetSupportedFeaturesCaseForMacRandomization(
4785                         featureP2pMacRandomization, true, true, true));
4786         // p2p supported by HAL, but disabled by overlay.
4787         assertEquals(featureStaConnectedMacRandomization | featureApMacRandomization,
4788                 testGetSupportedFeaturesCaseForMacRandomization(
4789                         featureP2pMacRandomization, true, true, false));
4790         assertEquals(featureStaConnectedMacRandomization | featureApMacRandomization,
4791                 testGetSupportedFeaturesCaseForMacRandomization(0, true, true, false));
4792     }
4793 
testGetSupportedFeaturesCaseForRtt( long supportedFeaturesFromWifiNative, boolean rttDisabled)4794     private long testGetSupportedFeaturesCaseForRtt(
4795             long supportedFeaturesFromWifiNative, boolean rttDisabled) {
4796         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)).thenReturn(
4797                 !rttDisabled);
4798         when(mWifiNative.getSupportedFeatureSet(anyString())).thenReturn(
4799                 supportedFeaturesFromWifiNative);
4800         mClientListener.onStarted(mClientModeManager);
4801         mLooper.dispatchAll();
4802         return mActiveModeWarden.getSupportedFeatureSet();
4803     }
4804 
4805     /** Verifies that syncGetSupportedFeatures() masks out capabilities based on system flags. */
4806     @Test
syncGetSupportedFeaturesForRtt()4807     public void syncGetSupportedFeaturesForRtt() throws Exception {
4808         final long featureAware = WifiManager.WIFI_FEATURE_AWARE;
4809         final long featureInfra = WifiManager.WIFI_FEATURE_INFRA;
4810         final long featureD2dRtt = WifiManager.WIFI_FEATURE_D2D_RTT;
4811         final long featureD2apRtt = WifiManager.WIFI_FEATURE_D2AP_RTT;
4812         final long featureLongBits = 0x1000000000L;
4813         enterClientModeActiveState();
4814         assertEquals(0, testGetSupportedFeaturesCaseForRtt(0, false));
4815         assertEquals(0, testGetSupportedFeaturesCaseForRtt(0, true));
4816         assertEquals(featureAware | featureInfra,
4817                 testGetSupportedFeaturesCaseForRtt(featureAware | featureInfra, false));
4818         assertEquals(featureAware | featureInfra,
4819                 testGetSupportedFeaturesCaseForRtt(featureAware | featureInfra, true));
4820         assertEquals(featureInfra | featureD2dRtt,
4821                 testGetSupportedFeaturesCaseForRtt(featureInfra | featureD2dRtt, false));
4822         assertEquals(featureInfra,
4823                 testGetSupportedFeaturesCaseForRtt(featureInfra | featureD2dRtt, true));
4824         assertEquals(featureInfra | featureD2apRtt,
4825                 testGetSupportedFeaturesCaseForRtt(featureInfra | featureD2apRtt, false));
4826         assertEquals(featureInfra,
4827                 testGetSupportedFeaturesCaseForRtt(featureInfra | featureD2apRtt, true));
4828         assertEquals(featureInfra | featureD2dRtt | featureD2apRtt,
4829                 testGetSupportedFeaturesCaseForRtt(
4830                         featureInfra | featureD2dRtt | featureD2apRtt, false));
4831         assertEquals(featureInfra,
4832                 testGetSupportedFeaturesCaseForRtt(
4833                         featureInfra | featureD2dRtt | featureD2apRtt, true));
4834 
4835         assertEquals(featureLongBits | featureInfra | featureD2dRtt | featureD2apRtt,
4836                 testGetSupportedFeaturesCaseForRtt(
4837                         featureLongBits | featureInfra | featureD2dRtt | featureD2apRtt, false));
4838         assertEquals(featureLongBits | featureInfra,
4839                 testGetSupportedFeaturesCaseForRtt(
4840                         featureLongBits | featureInfra | featureD2dRtt | featureD2apRtt, true));
4841     }
4842 
4843     @Test
testGetCurrentNetworkScanOnly()4844     public void testGetCurrentNetworkScanOnly() throws Exception {
4845         enterScanOnlyModeActiveState();
4846         assertNull(mActiveModeWarden.getCurrentNetwork());
4847     }
4848 
testGetCurrentNetworkClientMode()4849     @Test public void testGetCurrentNetworkClientMode() throws Exception {
4850         mActiveModeWarden.setCurrentNetwork(mNetwork);
4851         assertEquals(mNetwork, mActiveModeWarden.getCurrentNetwork());
4852     }
4853 
4854     /**
4855      *  Verifies that isClientModeManagerConnectedOrConnectingToBssid() checks for Affiliated link
4856      *  BSSID, if exists.
4857      */
4858     @Test
testClientModeManagerConnectedOrConnectingToBssid()4859     public void testClientModeManagerConnectedOrConnectingToBssid() {
4860 
4861         WifiConfiguration config1 = new WifiConfiguration();
4862         config1.SSID = TEST_SSID_1;
4863         MacAddress bssid2 = MacAddress.fromString(TEST_BSSID_2);
4864         when(mClientModeManager.getConnectedWifiConfiguration()).thenReturn(config1);
4865         when(mClientModeManager.getConnectedBssid()).thenReturn(TEST_BSSID_1);
4866         when(mClientModeManager.isAffiliatedLinkBssid(eq(bssid2))).thenReturn(true);
4867 
4868         assertTrue(mActiveModeWarden.isClientModeManagerConnectedOrConnectingToBssid(
4869                 mClientModeManager, TEST_SSID_1, TEST_BSSID_2));
4870     }
4871 
4872     @Test
syncGetSupportedBands()4873     public void syncGetSupportedBands() throws Exception {
4874         enterClientModeActiveState();
4875         when(mWifiNative.getSupportedBandsForSta(anyString())).thenReturn(11);
4876         mClientListener.onStarted(mClientModeManager);
4877         mLooper.dispatchAll();
4878         verify(mSettingsConfigStore).put(WIFI_NATIVE_SUPPORTED_STA_BANDS, 11);
4879         assertTrue(mActiveModeWarden.isBandSupportedForSta(WifiScanner.WIFI_BAND_24_GHZ));
4880         assertTrue(mActiveModeWarden.isBandSupportedForSta(WifiScanner.WIFI_BAND_5_GHZ));
4881         assertFalse(mActiveModeWarden.isBandSupportedForSta(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY));
4882         assertTrue(mActiveModeWarden.isBandSupportedForSta(WifiScanner.WIFI_BAND_6_GHZ));
4883     }
4884 
4885     @Test
testSatelliteModeOnDisableWifi()4886     public void testSatelliteModeOnDisableWifi() throws Exception {
4887         // Wifi is enabled
4888         enterClientModeActiveState();
4889         assertInEnabledState();
4890 
4891         // Satellite mode is ON, disable Wifi
4892         assertWifiShutDown(() -> {
4893             when(mSettingsStore.isSatelliteModeOn()).thenReturn(true);
4894             mActiveModeWarden.handleSatelliteModeChange();
4895             mLooper.dispatchAll();
4896         });
4897         mClientListener.onStopped(mClientModeManager);
4898         mLooper.dispatchAll();
4899         assertInDisabledState();
4900     }
4901 
4902     @Test
testSatelliteModeOffEnableWifi()4903     public void testSatelliteModeOffEnableWifi() throws Exception {
4904         // Wifi is enabled
4905         enterClientModeActiveState();
4906         assertInEnabledState();
4907 
4908         // Satellite mode is ON, disable Wifi
4909         assertWifiShutDown(() -> {
4910             when(mSettingsStore.isSatelliteModeOn()).thenReturn(true);
4911             mActiveModeWarden.handleSatelliteModeChange();
4912             mLooper.dispatchAll();
4913         });
4914         mClientListener.onStopped(mClientModeManager);
4915         mLooper.dispatchAll();
4916         assertInDisabledState();
4917 
4918         // Satellite mode is off, enable Wifi
4919         when(mSettingsStore.isSatelliteModeOn()).thenReturn(false);
4920         mActiveModeWarden.handleSatelliteModeChange();
4921         mLooper.dispatchAll();
4922         assertInEnabledState();
4923     }
4924 
4925 
4926     @Test
testSatelliteModeOnAirplaneModeOn()4927     public void testSatelliteModeOnAirplaneModeOn() throws Exception {
4928         // Sequence: Satellite ON -> APM ON -> Satellite OFF -> APM OFF
4929 
4930         // Wifi is enabled
4931         enterClientModeActiveState();
4932         assertInEnabledState();
4933 
4934         // Satellite mode is ON, disable Wifi
4935         assertWifiShutDown(() -> {
4936             when(mSettingsStore.isSatelliteModeOn()).thenReturn(true);
4937             mActiveModeWarden.handleSatelliteModeChange();
4938             mLooper.dispatchAll();
4939         });
4940         mClientListener.onStopped(mClientModeManager);
4941         mLooper.dispatchAll();
4942         assertInDisabledState();
4943 
4944         // APM toggle on, no change to Wifi state
4945         when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
4946         mActiveModeWarden.airplaneModeToggled();
4947         mLooper.dispatchAll();
4948         assertInDisabledState();
4949 
4950         // Satellite mode is off, no change to Wifi state as APM is on
4951         when(mSettingsStore.isSatelliteModeOn()).thenReturn(false);
4952         mActiveModeWarden.handleSatelliteModeChange();
4953         mLooper.dispatchAll();
4954         assertInDisabledState();
4955 
4956         // APM toggle off, enable Wifi
4957         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
4958         mActiveModeWarden.airplaneModeToggled();
4959         mLooper.dispatchAll();
4960         assertInEnabledState();
4961     }
4962 
4963     @Test
testAirplaneModeOnSatelliteModeOn()4964     public void testAirplaneModeOnSatelliteModeOn() throws Exception {
4965         // Sequence: APM ON -> Satellite ON -> APM OFF -> Satellite OFF
4966 
4967         // Wifi is enabled
4968         enterClientModeActiveState();
4969         assertInEnabledState();
4970 
4971         // APM toggle on, Wifi disabled
4972         assertWifiShutDown(() -> {
4973             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
4974             mActiveModeWarden.airplaneModeToggled();
4975             mLooper.dispatchAll();
4976         });
4977         mClientListener.onStopped(mClientModeManager);
4978         mLooper.dispatchAll();
4979         assertInDisabledState();
4980 
4981         // Satellite mode is on, no change to Wifi state
4982         when(mSettingsStore.isSatelliteModeOn()).thenReturn(true);
4983         mActiveModeWarden.handleSatelliteModeChange();
4984         mLooper.dispatchAll();
4985         assertInDisabledState();
4986 
4987         // APM toggle off, no change to Wifi state
4988         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
4989         mActiveModeWarden.airplaneModeToggled();
4990         mLooper.dispatchAll();
4991         assertInDisabledState();
4992 
4993         // Satellite mode is off, enable Wifi
4994         when(mSettingsStore.isSatelliteModeOn()).thenReturn(false);
4995         mActiveModeWarden.handleSatelliteModeChange();
4996         mLooper.dispatchAll();
4997         assertInEnabledState();
4998     }
4999 
5000     @Test
testToggleSatelliteModeBeforeAirplaneMode()5001     public void testToggleSatelliteModeBeforeAirplaneMode() throws Exception {
5002         // Sequence: APM ON -> Satellite ON -> Satellite OFF -> APM OFF
5003 
5004         // Wifi is enabled
5005         enterClientModeActiveState();
5006         assertInEnabledState();
5007 
5008         // APM toggle on, Wifi disabled
5009         assertWifiShutDown(() -> {
5010             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
5011             mActiveModeWarden.airplaneModeToggled();
5012             mLooper.dispatchAll();
5013         });
5014         verify(mLastCallerInfoManager).put(eq(WifiManager.API_WIFI_ENABLED), anyInt(), anyInt(),
5015                 anyInt(), eq("android_apm"), eq(false));
5016         verify(mLastCallerInfoManager, never()).put(eq(WifiManager.API_WIFI_ENABLED), anyInt(),
5017                 anyInt(), anyInt(), eq("android_apm"), eq(true));
5018         mClientListener.onStopped(mClientModeManager);
5019         mLooper.dispatchAll();
5020         assertInDisabledState();
5021 
5022         // Satellite mode is on, no change to Wifi state
5023         when(mSettingsStore.isSatelliteModeOn()).thenReturn(true);
5024         mActiveModeWarden.handleSatelliteModeChange();
5025         mLooper.dispatchAll();
5026         assertInDisabledState();
5027 
5028         // Satellite mode is off, no change to Wifi state
5029         when(mSettingsStore.isSatelliteModeOn()).thenReturn(false);
5030         mActiveModeWarden.handleSatelliteModeChange();
5031         mLooper.dispatchAll();
5032         assertInDisabledState();
5033 
5034         // APM toggle off, enable Wifi
5035         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
5036         mActiveModeWarden.airplaneModeToggled();
5037         mLooper.dispatchAll();
5038         assertInEnabledState();
5039         verify(mLastCallerInfoManager).put(eq(WifiManager.API_WIFI_ENABLED), anyInt(), anyInt(),
5040                 anyInt(), eq("android_apm"), eq(true));
5041     }
5042 
5043     @Test
testToggleAirplaneModeBeforeSatelliteMode()5044     public void testToggleAirplaneModeBeforeSatelliteMode() throws Exception {
5045         // Sequence: Satellite ON -> APM ON -> APM OFF -> Satellite OFF
5046 
5047         // Wifi is enabled
5048         enterClientModeActiveState();
5049         assertInEnabledState();
5050 
5051         // Satellite mode is ON, disable Wifi
5052         assertWifiShutDown(() -> {
5053             when(mSettingsStore.isSatelliteModeOn()).thenReturn(true);
5054             mActiveModeWarden.handleSatelliteModeChange();
5055             mLooper.dispatchAll();
5056         });
5057         mClientListener.onStopped(mClientModeManager);
5058         mLooper.dispatchAll();
5059         assertInDisabledState();
5060 
5061         // APM toggle on, no change to Wifi state
5062         when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
5063         mActiveModeWarden.airplaneModeToggled();
5064         mLooper.dispatchAll();
5065         assertInDisabledState();
5066 
5067         // APM toggle off, no change to Wifi state
5068         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
5069         mActiveModeWarden.airplaneModeToggled();
5070         mLooper.dispatchAll();
5071         assertInDisabledState();
5072 
5073         // Satellite mode is off, enable Wifi
5074         when(mSettingsStore.isSatelliteModeOn()).thenReturn(false);
5075         mActiveModeWarden.handleSatelliteModeChange();
5076         mLooper.dispatchAll();
5077         assertInEnabledState();
5078     }
5079 
5080     @Test
testToggleWifiWithSatelliteAndAirplaneMode()5081     public void testToggleWifiWithSatelliteAndAirplaneMode() throws Exception {
5082         // Sequence: APM ON -> Wifi ON -> Satellite ON -> APM OFF -> Satellite OFF
5083 
5084         // Wifi is enabled
5085         enterClientModeActiveState();
5086         assertInEnabledState();
5087 
5088         // APM toggle on, Wifi disabled
5089         assertWifiShutDown(() -> {
5090             when(mSettingsStore.isAirplaneModeOn()).thenReturn(true);
5091             mActiveModeWarden.airplaneModeToggled();
5092             mLooper.dispatchAll();
5093         });
5094         mClientListener.onStopped(mClientModeManager);
5095         mLooper.dispatchAll();
5096         assertInDisabledState();
5097 
5098         // Wifi on
5099         when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
5100         mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
5101         mLooper.dispatchAll();
5102         assertInEnabledState();
5103 
5104         // Satellite mode is ON, disable Wifi
5105         assertWifiShutDown(() -> {
5106             when(mSettingsStore.isSatelliteModeOn()).thenReturn(true);
5107             mActiveModeWarden.handleSatelliteModeChange();
5108             mLooper.dispatchAll();
5109         });
5110         mClientListener.onStopped(mClientModeManager);
5111         mLooper.dispatchAll();
5112         assertInDisabledState();
5113 
5114         // APM toggle off, no change to Wifi state
5115         when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
5116         mActiveModeWarden.airplaneModeToggled();
5117         mLooper.dispatchAll();
5118         assertInDisabledState();
5119 
5120         // Satellite mode is off, enable Wifi
5121         when(mSettingsStore.isSatelliteModeOn()).thenReturn(false);
5122         mActiveModeWarden.handleSatelliteModeChange();
5123         mLooper.dispatchAll();
5124         assertInEnabledState();
5125     }
5126 
5127 }
5128