| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.wifi; |
| |
| import static android.net.wifi.WifiConfiguration.KeyMgmt.WPA_PSK; |
| import static android.net.wifi.WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE; |
| import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_FAILURE_REASON; |
| import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; |
| import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; |
| import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; |
| |
| import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.mockito.Mockito.*; |
| |
| import android.app.test.TestAlarmManager; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.res.Resources; |
| import android.database.ContentObserver; |
| import android.net.Uri; |
| import android.net.wifi.IApInterfaceEventCallback; |
| import android.net.wifi.WifiConfiguration; |
| import android.net.wifi.WifiManager; |
| import android.net.wifi.WifiScanner; |
| import android.os.UserHandle; |
| import android.os.test.TestLooper; |
| import android.provider.Settings; |
| import android.support.test.filters.SmallTest; |
| |
| import com.android.internal.R; |
| import com.android.internal.util.WakeupMessage; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.InOrder; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| |
| import java.util.List; |
| import java.util.Locale; |
| |
| /** Unit tests for {@link SoftApManager}. */ |
| @SmallTest |
| public class SoftApManagerTest { |
| |
| private static final String TAG = "SoftApManagerTest"; |
| |
| private static final String DEFAULT_SSID = "DefaultTestSSID"; |
| private static final String TEST_SSID = "TestSSID"; |
| private static final String TEST_PASSWORD = "TestPassword"; |
| private static final String TEST_COUNTRY_CODE = "TestCountry"; |
| private static final String TEST_INTERFACE_NAME = "testif0"; |
| private static final String OTHER_INTERFACE_NAME = "otherif"; |
| private static final int TEST_NUM_CONNECTED_CLIENTS = 4; |
| private static final int[] ALLOWED_2G_CHANNELS = {2412, 2417, 2437}; |
| private static final int[] ALLOWED_5G_CHANNELS = {5180, 5190, 5240}; |
| |
| private final WifiConfiguration mDefaultApConfig = createDefaultApConfig(); |
| |
| private ContentObserver mContentObserver; |
| private TestLooper mLooper; |
| private TestAlarmManager mAlarmManager; |
| |
| @Mock Context mContext; |
| @Mock Resources mResources; |
| @Mock WifiNative mWifiNative; |
| @Mock WifiManager.SoftApCallback mCallback; |
| @Mock FrameworkFacade mFrameworkFacade; |
| @Mock WifiApConfigStore mWifiApConfigStore; |
| @Mock WifiMetrics mWifiMetrics; |
| @Mock SarManager mSarManager; |
| final ArgumentCaptor<WifiNative.InterfaceCallback> mWifiNativeInterfaceCallbackCaptor = |
| ArgumentCaptor.forClass(WifiNative.InterfaceCallback.class); |
| final ArgumentCaptor<WifiNative.SoftApListener> mSoftApListenerCaptor = |
| ArgumentCaptor.forClass(WifiNative.SoftApListener.class); |
| |
| SoftApManager mSoftApManager; |
| |
| /** Sets up test. */ |
| @Before |
| public void setUp() throws Exception { |
| MockitoAnnotations.initMocks(this); |
| mLooper = new TestLooper(); |
| |
| when(mWifiNative.startSoftAp(eq(TEST_INTERFACE_NAME), any(), any())).thenReturn(true); |
| |
| when(mFrameworkFacade.getIntegerSetting( |
| mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(1); |
| mAlarmManager = new TestAlarmManager(); |
| when(mContext.getSystemService(Context.ALARM_SERVICE)) |
| .thenReturn(mAlarmManager.getAlarmManager()); |
| when(mContext.getResources()).thenReturn(mResources); |
| when(mResources.getInteger(R.integer.config_wifi_framework_soft_ap_timeout_delay)) |
| .thenReturn(600000); |
| when(mWifiNative.setCountryCodeHal( |
| TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT))) |
| .thenReturn(true); |
| } |
| |
| private WifiConfiguration createDefaultApConfig() { |
| WifiConfiguration defaultConfig = new WifiConfiguration(); |
| defaultConfig.SSID = DEFAULT_SSID; |
| return defaultConfig; |
| } |
| |
| private SoftApManager createSoftApManager(SoftApModeConfiguration config, String countryCode) { |
| if (config.getWifiConfiguration() == null) { |
| when(mWifiApConfigStore.getApConfiguration()).thenReturn(mDefaultApConfig); |
| } |
| SoftApManager newSoftApManager = new SoftApManager(mContext, |
| mLooper.getLooper(), |
| mFrameworkFacade, |
| mWifiNative, |
| countryCode, |
| mCallback, |
| mWifiApConfigStore, |
| config, |
| mWifiMetrics, |
| mSarManager); |
| mLooper.dispatchAll(); |
| |
| return newSoftApManager; |
| } |
| |
| /** Verifies startSoftAp will use default config if AP configuration is not provided. */ |
| @Test |
| public void startSoftApWithoutConfig() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| } |
| |
| /** Verifies startSoftAp will use provided config and start AP. */ |
| @Test |
| public void startSoftApWithConfig() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = WifiConfiguration.AP_BAND_2GHZ; |
| config.SSID = TEST_SSID; |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| startSoftApAndVerifyEnabled(apConfig); |
| } |
| |
| /** |
| * Verifies startSoftAp will start with the hiddenSSID param set when it is set to true in the |
| * supplied config. |
| */ |
| @Test |
| public void startSoftApWithHiddenSsidTrueInConfig() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = WifiConfiguration.AP_BAND_2GHZ; |
| config.SSID = TEST_SSID; |
| config.hiddenSSID = true; |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| startSoftApAndVerifyEnabled(apConfig); |
| } |
| |
| /** |
| * Verifies startSoftAp will start with the password param set in the |
| * supplied config. |
| */ |
| @Test |
| public void startSoftApWithPassphraseInConfig() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = WifiConfiguration.AP_BAND_5GHZ; |
| config.SSID = TEST_SSID; |
| config.allowedKeyManagement.set(WPA_PSK); |
| config.preSharedKey = TEST_PASSWORD; |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| startSoftApAndVerifyEnabled(apConfig); |
| } |
| |
| /** Tests softap startup if default config fails to load. **/ |
| @Test |
| public void startSoftApDefaultConfigFailedToLoad() throws Exception { |
| when(mWifiNative.setupInterfaceForSoftApMode(any())).thenReturn(TEST_INTERFACE_NAME); |
| |
| when(mWifiApConfigStore.getApConfiguration()).thenReturn(null); |
| SoftApModeConfiguration nullApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| SoftApManager newSoftApManager = new SoftApManager(mContext, |
| mLooper.getLooper(), |
| mFrameworkFacade, |
| mWifiNative, |
| TEST_COUNTRY_CODE, |
| mCallback, |
| mWifiApConfigStore, |
| nullApConfig, |
| mWifiMetrics, |
| mSarManager); |
| mLooper.dispatchAll(); |
| newSoftApManager.start(); |
| mLooper.dispatchAll(); |
| verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, |
| WifiManager.SAP_START_FAILURE_GENERAL); |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| |
| List<Intent> capturedIntents = intentCaptor.getAllValues(); |
| checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING, |
| WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| nullApConfig.getTargetMode()); |
| checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED, |
| WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME, |
| nullApConfig.getTargetMode()); |
| } |
| |
| /** |
| * Test that failure to retrieve the SoftApInterface name increments the corresponding metrics |
| * and proper state updates are sent out. |
| */ |
| @Test |
| public void testSetupForSoftApModeNullApInterfaceNameFailureIncrementsMetrics() |
| throws Exception { |
| when(mWifiNative.setupInterfaceForSoftApMode(any())).thenReturn(null); |
| |
| SoftApModeConfiguration config = new SoftApModeConfiguration( |
| WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration()); |
| |
| when(mWifiApConfigStore.getApConfiguration()).thenReturn(null); |
| SoftApModeConfiguration nullApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| SoftApManager newSoftApManager = new SoftApManager(mContext, |
| mLooper.getLooper(), |
| mFrameworkFacade, |
| mWifiNative, |
| TEST_COUNTRY_CODE, |
| mCallback, |
| mWifiApConfigStore, |
| nullApConfig, |
| mWifiMetrics, |
| mSarManager); |
| mLooper.dispatchAll(); |
| newSoftApManager.start(); |
| mLooper.dispatchAll(); |
| verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, |
| WifiManager.SAP_START_FAILURE_GENERAL); |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| |
| checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED, |
| WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, null, |
| nullApConfig.getTargetMode()); |
| |
| verify(mWifiMetrics).incrementSoftApStartResult(false, |
| WifiManager.SAP_START_FAILURE_GENERAL); |
| } |
| |
| /** |
| * Test that an empty SoftApInterface name is detected as a failure and increments the |
| * corresponding metrics and proper state updates are sent out. |
| */ |
| @Test |
| public void testSetupForSoftApModeEmptyInterfaceNameFailureIncrementsMetrics() |
| throws Exception { |
| when(mWifiNative.setupInterfaceForSoftApMode(any())).thenReturn(""); |
| |
| SoftApModeConfiguration config = new SoftApModeConfiguration( |
| WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration()); |
| |
| when(mWifiApConfigStore.getApConfiguration()).thenReturn(null); |
| SoftApModeConfiguration nullApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| SoftApManager newSoftApManager = new SoftApManager(mContext, |
| mLooper.getLooper(), |
| mFrameworkFacade, |
| mWifiNative, |
| TEST_COUNTRY_CODE, |
| mCallback, |
| mWifiApConfigStore, |
| nullApConfig, |
| mWifiMetrics, |
| mSarManager); |
| mLooper.dispatchAll(); |
| newSoftApManager.start(); |
| mLooper.dispatchAll(); |
| verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, |
| WifiManager.SAP_START_FAILURE_GENERAL); |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| |
| checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED, |
| WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, "", |
| nullApConfig.getTargetMode()); |
| |
| verify(mWifiMetrics).incrementSoftApStartResult(false, |
| WifiManager.SAP_START_FAILURE_GENERAL); |
| } |
| |
| /** |
| * Tests that the generic error is propagated and properly reported when starting softap and no |
| * country code is provided. |
| */ |
| @Test |
| public void startSoftApOn5GhzFailGeneralErrorForNoCountryCode() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = WifiConfiguration.AP_BAND_5GHZ; |
| config.SSID = TEST_SSID; |
| SoftApModeConfiguration softApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| |
| when(mWifiNative.setupInterfaceForSoftApMode(any())).thenReturn(TEST_INTERFACE_NAME); |
| |
| SoftApManager newSoftApManager = new SoftApManager(mContext, |
| mLooper.getLooper(), |
| mFrameworkFacade, |
| mWifiNative, |
| null, |
| mCallback, |
| mWifiApConfigStore, |
| softApConfig, |
| mWifiMetrics, |
| mSarManager); |
| mLooper.dispatchAll(); |
| newSoftApManager.start(); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiNative, never()).setCountryCodeHal(eq(TEST_INTERFACE_NAME), any()); |
| |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| |
| List<Intent> capturedIntents = intentCaptor.getAllValues(); |
| checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING, |
| WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApConfig.getTargetMode()); |
| checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED, |
| WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME, |
| softApConfig.getTargetMode()); |
| } |
| |
| /** |
| * Tests that the generic error is propagated and properly reported when starting softap and the |
| * country code cannot be set. |
| */ |
| @Test |
| public void startSoftApOn5GhzFailGeneralErrorForCountryCodeSetFailure() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = WifiConfiguration.AP_BAND_5GHZ; |
| config.SSID = TEST_SSID; |
| SoftApModeConfiguration softApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| |
| when(mWifiNative.setupInterfaceForSoftApMode(any())).thenReturn(TEST_INTERFACE_NAME); |
| when(mWifiNative.setCountryCodeHal( |
| TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT))) |
| .thenReturn(false); |
| |
| SoftApManager newSoftApManager = new SoftApManager(mContext, |
| mLooper.getLooper(), |
| mFrameworkFacade, |
| mWifiNative, |
| TEST_COUNTRY_CODE, |
| mCallback, |
| mWifiApConfigStore, |
| softApConfig, |
| mWifiMetrics, |
| mSarManager); |
| mLooper.dispatchAll(); |
| newSoftApManager.start(); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiNative).setCountryCodeHal( |
| TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT)); |
| |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| |
| List<Intent> capturedIntents = intentCaptor.getAllValues(); |
| checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING, |
| WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApConfig.getTargetMode()); |
| checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED, |
| WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME, |
| softApConfig.getTargetMode()); |
| } |
| |
| /** |
| * Tests that there is no failure in starting softap in 2Ghz band when no country code is |
| * provided. |
| */ |
| @Test |
| public void startSoftApOn24GhzNoFailForNoCountryCode() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = WifiConfiguration.AP_BAND_2GHZ; |
| config.SSID = TEST_SSID; |
| SoftApModeConfiguration softApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| |
| startSoftApAndVerifyEnabled(softApConfig, null); |
| verify(mWifiNative, never()).setCountryCodeHal(eq(TEST_INTERFACE_NAME), any()); |
| } |
| |
| /** |
| * Tests that there is no failure in starting softap in ANY band when no country code is |
| * provided. |
| */ |
| @Test |
| public void startSoftApOnAnyGhzNoFailForNoCountryCode() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = WifiConfiguration.AP_BAND_ANY; |
| config.SSID = TEST_SSID; |
| SoftApModeConfiguration softApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| |
| startSoftApAndVerifyEnabled(softApConfig, null); |
| verify(mWifiNative, never()).setCountryCodeHal(eq(TEST_INTERFACE_NAME), any()); |
| } |
| |
| /** |
| * Tests that there is no failure in starting softap in 2Ghz band when country code cannot be |
| * set. |
| */ |
| @Test |
| public void startSoftApOn2GhzNoFailForCountryCodeSetFailure() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = WifiConfiguration.AP_BAND_2GHZ; |
| config.SSID = TEST_SSID; |
| SoftApModeConfiguration softApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| |
| when(mWifiNative.setCountryCodeHal(eq(TEST_INTERFACE_NAME), any())).thenReturn(false); |
| |
| startSoftApAndVerifyEnabled(softApConfig, TEST_COUNTRY_CODE); |
| verify(mWifiNative).setCountryCodeHal( |
| TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT)); |
| } |
| |
| /** |
| * Tests that there is no failure in starting softap in ANY band when country code cannot be |
| * set. |
| */ |
| @Test |
| public void startSoftApOnAnyNoFailForCountryCodeSetFailure() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = WifiConfiguration.AP_BAND_ANY; |
| config.SSID = TEST_SSID; |
| SoftApModeConfiguration softApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| |
| when(mWifiNative.setCountryCodeHal(eq(TEST_INTERFACE_NAME), any())).thenReturn(false); |
| |
| startSoftApAndVerifyEnabled(softApConfig, TEST_COUNTRY_CODE); |
| verify(mWifiNative).setCountryCodeHal( |
| TEST_INTERFACE_NAME, TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT)); |
| } |
| |
| /** |
| * Tests that the NO_CHANNEL error is propagated and properly reported when starting softap and |
| * a valid channel cannot be determined. |
| */ |
| @Test |
| public void startSoftApFailNoChannel() throws Exception { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.apBand = -2; |
| config.apChannel = 0; |
| config.SSID = TEST_SSID; |
| SoftApModeConfiguration softApConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| |
| when(mWifiNative.setupInterfaceForSoftApMode(any())).thenReturn(TEST_INTERFACE_NAME); |
| when(mWifiNative.isHalStarted()).thenReturn(true); |
| |
| SoftApManager newSoftApManager = new SoftApManager(mContext, |
| mLooper.getLooper(), |
| mFrameworkFacade, |
| mWifiNative, |
| TEST_COUNTRY_CODE, |
| mCallback, |
| mWifiApConfigStore, |
| softApConfig, |
| mWifiMetrics, |
| mSarManager); |
| mLooper.dispatchAll(); |
| newSoftApManager.start(); |
| mLooper.dispatchAll(); |
| |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| |
| List<Intent> capturedIntents = intentCaptor.getAllValues(); |
| checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING, |
| WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApConfig.getTargetMode()); |
| checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED, |
| WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_NO_CHANNEL, |
| TEST_INTERFACE_NAME, softApConfig.getTargetMode()); |
| } |
| |
| /** |
| * Tests startup when Ap Interface fails to start successfully. |
| */ |
| @Test |
| public void startSoftApApInterfaceFailedToStart() throws Exception { |
| when(mWifiNative.setupInterfaceForSoftApMode(any())).thenReturn(TEST_INTERFACE_NAME); |
| when(mWifiNative.startSoftAp(eq(TEST_INTERFACE_NAME), any(), any())).thenReturn(false); |
| |
| SoftApModeConfiguration softApModeConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, mDefaultApConfig); |
| |
| SoftApManager newSoftApManager = new SoftApManager(mContext, |
| mLooper.getLooper(), |
| mFrameworkFacade, |
| mWifiNative, |
| TEST_COUNTRY_CODE, |
| mCallback, |
| mWifiApConfigStore, |
| softApModeConfig, |
| mWifiMetrics, |
| mSarManager); |
| |
| mLooper.dispatchAll(); |
| newSoftApManager.start(); |
| mLooper.dispatchAll(); |
| verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, |
| WifiManager.SAP_START_FAILURE_GENERAL); |
| verify(mWifiNative).teardownInterface(TEST_INTERFACE_NAME); |
| } |
| |
| /** |
| * Tests the handling of stop command when soft AP is not started. |
| */ |
| @Test |
| public void stopWhenNotStarted() throws Exception { |
| mSoftApManager = createSoftApManager( |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null), |
| TEST_COUNTRY_CODE); |
| mSoftApManager.stop(); |
| mLooper.dispatchAll(); |
| /* Verify no state changes. */ |
| verify(mCallback, never()).onStateChanged(anyInt(), anyInt()); |
| verify(mSarManager, never()).setSapWifiState(anyInt()); |
| verify(mContext, never()).sendStickyBroadcastAsUser(any(), any()); |
| verify(mWifiNative, never()).teardownInterface(anyString()); |
| } |
| |
| /** |
| * Tests the handling of stop command when soft AP is started. |
| */ |
| @Test |
| public void stopWhenStarted() throws Exception { |
| SoftApModeConfiguration softApModeConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(softApModeConfig); |
| |
| // reset to clear verified Intents for ap state change updates |
| reset(mContext); |
| |
| InOrder order = inOrder(mCallback, mContext); |
| |
| mSoftApManager.stop(); |
| mLooper.dispatchAll(); |
| |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); |
| order.verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_DISABLING, |
| WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApModeConfig.getTargetMode()); |
| |
| order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); |
| verify(mSarManager).setSapWifiState(WifiManager.WIFI_AP_STATE_DISABLED); |
| order.verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_DISABLED, |
| WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApModeConfig.getTargetMode()); |
| } |
| |
| /** |
| * Verify that onDestroyed properly reports softap stop. |
| */ |
| @Test |
| public void cleanStopOnInterfaceDestroyed() throws Exception { |
| SoftApModeConfiguration softApModeConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(softApModeConfig); |
| |
| // reset to clear verified Intents for ap state change updates |
| reset(mContext); |
| |
| InOrder order = inOrder(mCallback, mContext); |
| |
| mWifiNativeInterfaceCallbackCaptor.getValue().onDestroyed(TEST_INTERFACE_NAME); |
| |
| mLooper.dispatchAll(); |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); |
| order.verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_DISABLING, |
| WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApModeConfig.getTargetMode()); |
| |
| order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); |
| order.verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_DISABLED, |
| WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, null, |
| softApModeConfig.getTargetMode()); |
| } |
| |
| /** |
| * Verify that onDestroyed after softap is stopped doesn't trigger a callback. |
| */ |
| @Test |
| public void noCallbackOnInterfaceDestroyedWhenAlreadyStopped() throws Exception { |
| SoftApModeConfiguration softApModeConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(softApModeConfig); |
| |
| mSoftApManager.stop(); |
| mLooper.dispatchAll(); |
| |
| verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); |
| verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); |
| |
| reset(mCallback); |
| |
| // now trigger interface destroyed and make sure callback doesn't get called |
| mWifiNativeInterfaceCallbackCaptor.getValue().onDestroyed(TEST_INTERFACE_NAME); |
| mLooper.dispatchAll(); |
| |
| verifyNoMoreInteractions(mCallback); |
| } |
| |
| /** |
| * Verify that onDown is handled by SoftApManager. |
| */ |
| @Test |
| public void testInterfaceOnDownHandled() throws Exception { |
| SoftApModeConfiguration softApModeConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(softApModeConfig); |
| |
| // reset to clear verified Intents for ap state change updates |
| reset(mContext, mCallback, mWifiNative); |
| |
| InOrder order = inOrder(mCallback, mContext); |
| |
| mWifiNativeInterfaceCallbackCaptor.getValue().onDown(TEST_INTERFACE_NAME); |
| |
| mLooper.dispatchAll(); |
| |
| order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, |
| WifiManager.SAP_START_FAILURE_GENERAL); |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| verify(mContext, times(3)).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| |
| List<Intent> capturedIntents = intentCaptor.getAllValues(); |
| checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_FAILED, |
| WIFI_AP_STATE_ENABLED, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME, |
| softApModeConfig.getTargetMode()); |
| checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_DISABLING, |
| WIFI_AP_STATE_FAILED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApModeConfig.getTargetMode()); |
| checkApStateChangedBroadcast(capturedIntents.get(2), WIFI_AP_STATE_DISABLED, |
| WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApModeConfig.getTargetMode()); |
| } |
| |
| /** |
| * Verify that onDown for a different interface name does not stop SoftApManager. |
| */ |
| @Test |
| public void testInterfaceOnDownForDifferentInterfaceDoesNotTriggerStop() throws Exception { |
| SoftApModeConfiguration softApModeConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(softApModeConfig); |
| |
| // reset to clear verified Intents for ap state change updates |
| reset(mContext, mCallback, mWifiNative); |
| |
| InOrder order = inOrder(mCallback, mContext); |
| |
| mWifiNativeInterfaceCallbackCaptor.getValue().onDown(OTHER_INTERFACE_NAME); |
| |
| mLooper.dispatchAll(); |
| |
| verifyNoMoreInteractions(mContext, mCallback, mWifiNative); |
| } |
| |
| @Test |
| public void updatesMetricsOnChannelSwitchedEvent() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| final int channelFrequency = 2437; |
| final int channelBandwidth = IApInterfaceEventCallback.BANDWIDTH_20; |
| mSoftApListenerCaptor.getValue().onSoftApChannelSwitched(channelFrequency, |
| channelBandwidth); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiMetrics).addSoftApChannelSwitchedEvent(channelFrequency, channelBandwidth, |
| apConfig.getTargetMode()); |
| } |
| |
| @Test |
| public void updatesMetricsOnChannelSwitchedEventDetectsBandUnsatisfiedOnBand2Ghz() |
| throws Exception { |
| WifiConfiguration config = createDefaultApConfig(); |
| config.apBand = WifiConfiguration.AP_BAND_2GHZ; |
| |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| final int channelFrequency = 2437; |
| final int channelBandwidth = IApInterfaceEventCallback.BANDWIDTH_20; |
| when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ)) |
| .thenReturn(ALLOWED_5G_CHANNELS); |
| mSoftApListenerCaptor.getValue().onSoftApChannelSwitched(channelFrequency, |
| channelBandwidth); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiNative).getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ); |
| verify(mWifiMetrics).addSoftApChannelSwitchedEvent(channelFrequency, channelBandwidth, |
| apConfig.getTargetMode()); |
| verify(mWifiMetrics).incrementNumSoftApUserBandPreferenceUnsatisfied(); |
| } |
| |
| @Test |
| public void updatesMetricsOnChannelSwitchedEventDetectsBandUnsatisfiedOnBand5Ghz() |
| throws Exception { |
| WifiConfiguration config = createDefaultApConfig(); |
| config.apBand = WifiConfiguration.AP_BAND_5GHZ; |
| |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| final int channelFrequency = 5180; |
| final int channelBandwidth = IApInterfaceEventCallback.BANDWIDTH_20; |
| when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ)) |
| .thenReturn(ALLOWED_2G_CHANNELS); |
| mSoftApListenerCaptor.getValue().onSoftApChannelSwitched(channelFrequency, |
| channelBandwidth); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiNative).getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ); |
| verify(mWifiMetrics).addSoftApChannelSwitchedEvent(channelFrequency, channelBandwidth, |
| apConfig.getTargetMode()); |
| verify(mWifiMetrics).incrementNumSoftApUserBandPreferenceUnsatisfied(); |
| } |
| |
| @Test |
| public void updatesMetricsOnChannelSwitchedEventDetectsBandUnsatisfiedOnBandAny() |
| throws Exception { |
| WifiConfiguration config = createDefaultApConfig(); |
| config.apBand = WifiConfiguration.AP_BAND_ANY; |
| |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| final int channelFrequency = 2437; |
| final int channelBandwidth = IApInterfaceEventCallback.BANDWIDTH_20; |
| when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ)) |
| .thenReturn(new int[0]); |
| when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ)) |
| .thenReturn(new int[0]); |
| mSoftApListenerCaptor.getValue().onSoftApChannelSwitched(channelFrequency, |
| channelBandwidth); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiNative).getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ); |
| verify(mWifiNative).getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ); |
| verify(mWifiMetrics).addSoftApChannelSwitchedEvent(channelFrequency, channelBandwidth, |
| apConfig.getTargetMode()); |
| verify(mWifiMetrics).incrementNumSoftApUserBandPreferenceUnsatisfied(); |
| } |
| |
| @Test |
| public void updatesMetricsOnChannelSwitchedEventDetectsBandUnsatisfiedOnlyWhenRequired() |
| throws Exception { |
| WifiConfiguration config = createDefaultApConfig(); |
| config.apBand = WifiConfiguration.AP_BAND_2GHZ; |
| |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| final int channelFrequency = 2437; |
| final int channelBandwidth = IApInterfaceEventCallback.BANDWIDTH_20; |
| when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ)) |
| .thenReturn(ALLOWED_2G_CHANNELS); |
| mSoftApListenerCaptor.getValue().onSoftApChannelSwitched(channelFrequency, |
| channelBandwidth); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiNative).getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ); |
| verify(mWifiMetrics).addSoftApChannelSwitchedEvent(channelFrequency, channelBandwidth, |
| apConfig.getTargetMode()); |
| verify(mWifiMetrics, never()).incrementNumSoftApUserBandPreferenceUnsatisfied(); |
| } |
| |
| @Test |
| public void updatesNumAssociatedStations() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged( |
| TEST_NUM_CONNECTED_CLIENTS); |
| mLooper.dispatchAll(); |
| |
| verify(mCallback).onNumClientsChanged(TEST_NUM_CONNECTED_CLIENTS); |
| verify(mWifiMetrics).addSoftApNumAssociatedStationsChangedEvent(TEST_NUM_CONNECTED_CLIENTS, |
| apConfig.getTargetMode()); |
| } |
| |
| /** |
| * If SoftApManager gets an update for the number of connected clients that is the same, do not |
| * trigger callbacks a second time. |
| */ |
| @Test |
| public void testDoesNotTriggerCallbackForSameNumberClientUpdate() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged( |
| TEST_NUM_CONNECTED_CLIENTS); |
| mLooper.dispatchAll(); |
| |
| // now trigger callback again, but we should have each method only called once |
| mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged( |
| TEST_NUM_CONNECTED_CLIENTS); |
| mLooper.dispatchAll(); |
| |
| verify(mCallback).onNumClientsChanged(TEST_NUM_CONNECTED_CLIENTS); |
| verify(mWifiMetrics).addSoftApNumAssociatedStationsChangedEvent(TEST_NUM_CONNECTED_CLIENTS, |
| apConfig.getTargetMode()); |
| } |
| |
| @Test |
| public void handlesInvalidNumAssociatedStations() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| /* Invalid values should be ignored */ |
| final int mInvalidNumClients = -1; |
| mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(mInvalidNumClients); |
| mLooper.dispatchAll(); |
| verify(mCallback, never()).onNumClientsChanged(mInvalidNumClients); |
| verify(mWifiMetrics, never()).addSoftApNumAssociatedStationsChangedEvent(anyInt(), |
| anyInt()); |
| } |
| |
| @Test |
| public void schedulesTimeoutTimerOnStart() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| // Verify timer is scheduled |
| verify(mAlarmManager.getAlarmManager()).setExact(anyInt(), anyLong(), |
| eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any()); |
| } |
| |
| @Test |
| public void cancelsTimeoutTimerOnStop() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| mSoftApManager.stop(); |
| mLooper.dispatchAll(); |
| |
| // Verify timer is canceled |
| verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class)); |
| } |
| |
| @Test |
| public void cancelsTimeoutTimerOnNewClientsConnect() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged( |
| TEST_NUM_CONNECTED_CLIENTS); |
| mLooper.dispatchAll(); |
| |
| // Verify timer is canceled |
| verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class)); |
| } |
| |
| @Test |
| public void schedulesTimeoutTimerWhenAllClientsDisconnect() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged( |
| TEST_NUM_CONNECTED_CLIENTS); |
| mLooper.dispatchAll(); |
| verify(mCallback).onNumClientsChanged(TEST_NUM_CONNECTED_CLIENTS); |
| // Verify timer is canceled at this point |
| verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class)); |
| |
| mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(0); |
| mLooper.dispatchAll(); |
| verify(mCallback, times(2)).onNumClientsChanged(0); |
| // Verify timer is scheduled again |
| verify(mAlarmManager.getAlarmManager(), times(2)).setExact(anyInt(), anyLong(), |
| eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any()); |
| } |
| |
| @Test |
| public void stopsSoftApOnTimeoutMessage() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| mAlarmManager.dispatch(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiNative).teardownInterface(TEST_INTERFACE_NAME); |
| } |
| |
| @Test |
| public void cancelsTimeoutTimerOnTimeoutToggleChangeWhenNoClients() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| when(mFrameworkFacade.getIntegerSetting( |
| mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0); |
| mContentObserver.onChange(false); |
| mLooper.dispatchAll(); |
| |
| // Verify timer is canceled |
| verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class)); |
| } |
| |
| @Test |
| public void schedulesTimeoutTimerOnTimeoutToggleChangeWhenNoClients() throws Exception { |
| // start with timeout toggle disabled |
| when(mFrameworkFacade.getIntegerSetting( |
| mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0); |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| when(mFrameworkFacade.getIntegerSetting( |
| mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(1); |
| mContentObserver.onChange(false); |
| mLooper.dispatchAll(); |
| |
| // Verify timer is scheduled |
| verify(mAlarmManager.getAlarmManager()).setExact(anyInt(), anyLong(), |
| eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any()); |
| } |
| |
| @Test |
| public void doesNotScheduleTimeoutTimerOnStartWhenTimeoutIsDisabled() throws Exception { |
| // start with timeout toggle disabled |
| when(mFrameworkFacade.getIntegerSetting( |
| mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0); |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| |
| // Verify timer is not scheduled |
| verify(mAlarmManager.getAlarmManager(), never()).setExact(anyInt(), anyLong(), |
| eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any()); |
| } |
| |
| @Test |
| public void doesNotScheduleTimeoutTimerWhenAllClientsDisconnectButTimeoutIsDisabled() |
| throws Exception { |
| // start with timeout toggle disabled |
| when(mFrameworkFacade.getIntegerSetting( |
| mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0); |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| // add some clients |
| mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged( |
| TEST_NUM_CONNECTED_CLIENTS); |
| mLooper.dispatchAll(); |
| // remove all clients |
| mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(0); |
| mLooper.dispatchAll(); |
| // Verify timer is not scheduled |
| verify(mAlarmManager.getAlarmManager(), never()).setExact(anyInt(), anyLong(), |
| eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any()); |
| } |
| |
| @Test |
| public void unregistersSettingsObserverOnStop() throws Exception { |
| SoftApModeConfiguration apConfig = |
| new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null); |
| startSoftApAndVerifyEnabled(apConfig); |
| mSoftApManager.stop(); |
| mLooper.dispatchAll(); |
| |
| verify(mFrameworkFacade).unregisterContentObserver(eq(mContext), eq(mContentObserver)); |
| } |
| |
| /** Starts soft AP and verifies that it is enabled successfully. */ |
| protected void startSoftApAndVerifyEnabled( |
| SoftApModeConfiguration softApConfig) throws Exception { |
| startSoftApAndVerifyEnabled(softApConfig, TEST_COUNTRY_CODE); |
| } |
| |
| /** Starts soft AP and verifies that it is enabled successfully. */ |
| protected void startSoftApAndVerifyEnabled( |
| SoftApModeConfiguration softApConfig, String countryCode) throws Exception { |
| WifiConfiguration expectedConfig; |
| InOrder order = inOrder(mCallback, mWifiNative); |
| |
| mSoftApManager = createSoftApManager(softApConfig, countryCode); |
| WifiConfiguration config = softApConfig.getWifiConfiguration(); |
| if (config == null) { |
| when(mWifiApConfigStore.getApConfiguration()).thenReturn(mDefaultApConfig); |
| expectedConfig = new WifiConfiguration(mDefaultApConfig); |
| } else { |
| expectedConfig = new WifiConfiguration(config); |
| } |
| |
| ArgumentCaptor<ContentObserver> observerCaptor = ArgumentCaptor.forClass( |
| ContentObserver.class); |
| ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); |
| |
| when(mWifiNative.setupInterfaceForSoftApMode(any())) |
| .thenReturn(TEST_INTERFACE_NAME); |
| |
| mSoftApManager.start(); |
| mLooper.dispatchAll(); |
| order.verify(mWifiNative).setupInterfaceForSoftApMode( |
| mWifiNativeInterfaceCallbackCaptor.capture()); |
| ArgumentCaptor<WifiConfiguration> configCaptor = |
| ArgumentCaptor.forClass(WifiConfiguration.class); |
| order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); |
| order.verify(mWifiNative).startSoftAp(eq(TEST_INTERFACE_NAME), |
| configCaptor.capture(), mSoftApListenerCaptor.capture()); |
| WifiConfigurationTestUtil.assertConfigurationEqual(expectedConfig, configCaptor.getValue()); |
| mWifiNativeInterfaceCallbackCaptor.getValue().onUp(TEST_INTERFACE_NAME); |
| mLooper.dispatchAll(); |
| order.verify(mCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0); |
| order.verify(mCallback).onNumClientsChanged(0); |
| verify(mSarManager).setSapWifiState(WifiManager.WIFI_AP_STATE_ENABLED); |
| verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(), |
| eq(UserHandle.ALL)); |
| List<Intent> capturedIntents = intentCaptor.getAllValues(); |
| checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING, |
| WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApConfig.getTargetMode()); |
| checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_ENABLED, |
| WIFI_AP_STATE_ENABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME, |
| softApConfig.getTargetMode()); |
| verify(mWifiMetrics).addSoftApUpChangedEvent(true, softApConfig.mTargetMode); |
| verify(mFrameworkFacade).registerContentObserver(eq(mContext), any(Uri.class), eq(true), |
| observerCaptor.capture()); |
| mContentObserver = observerCaptor.getValue(); |
| } |
| |
| private void checkApStateChangedBroadcast(Intent intent, int expectedCurrentState, |
| int expectedPrevState, int expectedErrorCode, |
| String expectedIfaceName, int expectedMode) { |
| int currentState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED); |
| int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED); |
| int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON, HOTSPOT_NO_ERROR); |
| String ifaceName = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME); |
| int mode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, WifiManager.IFACE_IP_MODE_UNSPECIFIED); |
| assertEquals(expectedCurrentState, currentState); |
| assertEquals(expectedPrevState, prevState); |
| assertEquals(expectedErrorCode, errorCode); |
| assertEquals(expectedIfaceName, ifaceName); |
| assertEquals(expectedMode, mode); |
| } |
| } |