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