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