summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRebecca Silberstein <silberst@google.com>2017-05-16 10:51:51 -0700
committerRebecca Silberstein <silberst@google.com>2017-05-18 01:39:55 -0700
commit878e0cccd652ea556680b9cc101b01142e9ad919 (patch)
tree12e01b58157572d060bf2fec4e2f96d7257d08f9
parentcd1587091a7a9c0b175fc64f33b6f17e62215829 (diff)
downloadandroid_frameworks_opt_net_wifi-878e0cccd652ea556680b9cc101b01142e9ad919.tar.gz
android_frameworks_opt_net_wifi-878e0cccd652ea556680b9cc101b01142e9ad919.tar.bz2
android_frameworks_opt_net_wifi-878e0cccd652ea556680b9cc101b01142e9ad919.zip
WifiServiceImpl: listen and act on softap changes
The registered callers of LocalOnlyHotspot need to be updated when the hotspot fails or stops. This is currently implemented by having WifiServiceImpl listen for WIFI_AP_STATE_CHANGE broadcasts. When updates about softap failures or stopping (disabling or disabled) are received, appropriate messages are constructed and sent to registered callers. This CL additionally adds tests confirming this behavior. An additional helper methods were added to aid testing for sending the broadcasts and sending messages to the registered LOHS requestors. Bug: 31466854 Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I5ade861423c7ea25690a084e9e4c7c9861f1dbcd
-rw-r--r--service/java/com/android/server/wifi/LocalOnlyHotspotRequestInfo.java48
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java132
-rw-r--r--tests/wifitests/src/com/android/server/wifi/LocalOnlyHotspotRequestInfoTest.java48
-rw-r--r--tests/wifitests/src/com/android/server/wifi/TestUtil.java15
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java241
5 files changed, 456 insertions, 28 deletions
diff --git a/service/java/com/android/server/wifi/LocalOnlyHotspotRequestInfo.java b/service/java/com/android/server/wifi/LocalOnlyHotspotRequestInfo.java
index 2925d966b..9e3b4fb2c 100644
--- a/service/java/com/android/server/wifi/LocalOnlyHotspotRequestInfo.java
+++ b/service/java/com/android/server/wifi/LocalOnlyHotspotRequestInfo.java
@@ -17,6 +17,8 @@
package com.android.server.wifi;
import android.annotation.NonNull;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.Message;
@@ -31,7 +33,9 @@ import com.android.internal.util.Preconditions;
* @hide
*/
public class LocalOnlyHotspotRequestInfo implements IBinder.DeathRecipient {
- private final int mUid;
+ static final int HOTSPOT_NO_ERROR = -1;
+
+ private final int mPid;
private final IBinder mBinder;
private final RequestingApplicationDeathCallback mCallback;
private final Messenger mMessenger;
@@ -48,7 +52,7 @@ public class LocalOnlyHotspotRequestInfo implements IBinder.DeathRecipient {
LocalOnlyHotspotRequestInfo(@NonNull IBinder binder, @NonNull Messenger messenger,
@NonNull RequestingApplicationDeathCallback callback) {
- mUid = Binder.getCallingUid();
+ mPid = Binder.getCallingPid();
mBinder = Preconditions.checkNotNull(binder);
mMessenger = Preconditions.checkNotNull(messenger);
mCallback = Preconditions.checkNotNull(callback);
@@ -76,21 +80,45 @@ public class LocalOnlyHotspotRequestInfo implements IBinder.DeathRecipient {
}
/**
- * Send a message to WifiManager for the calling application.
+ * Send a HOTSPOT_FAILED message to WifiManager for the calling application with the error code.
+ *
+ * @param reasonCode error code for the message
+ *
+ * @throws RemoteException
+ */
+ public void sendHotspotFailedMessage(int reasonCode) throws RemoteException {
+ Message message = Message.obtain();
+ message.what = WifiManager.HOTSPOT_FAILED;
+ message.arg1 = reasonCode;
+ mMessenger.send(message);
+ }
+
+ /**
+ * Send a HOTSPOT_STARTED message to WifiManager for the calling application with the config.
+ *
+ * @param config WifiConfiguration for the callback
*
- * @param what Message type to send
- * @param arg1 arg1 for the message
+ * @throws RemoteException
+ */
+ public void sendHotspotStartedMessage(WifiConfiguration config) throws RemoteException {
+ Message message = Message.obtain();
+ message.what = WifiManager.HOTSPOT_STARTED;
+ message.obj = config;
+ mMessenger.send(message);
+ }
+
+ /**
+ * Send a HOTSPOT_STOPPED message to WifiManager for the calling application.
*
* @throws RemoteException
*/
- public void sendMessage(int what, int arg1) throws RemoteException {
+ public void sendHotspotStoppedMessage() throws RemoteException {
Message message = Message.obtain();
- message.what = what;
- message.arg1 = arg1;
+ message.what = WifiManager.HOTSPOT_STOPPED;
mMessenger.send(message);
}
- public int getUid() {
- return mUid;
+ public int getPid() {
+ return mPid;
}
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 6a5c6d2f5..ce9784d2e 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -16,7 +16,18 @@
package com.android.server.wifi;
+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_STATE;
+import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
+import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
+import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL;
+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_FAILED;
+
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
+import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR;
import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED;
import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED;
@@ -475,6 +486,21 @@ public class WifiServiceImpl extends IWifiManager.Stub {
},
new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int currentState = intent.getIntExtra(EXTRA_WIFI_AP_STATE,
+ WIFI_AP_STATE_DISABLED);
+ final int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE,
+ WIFI_AP_STATE_DISABLED);
+ final int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON,
+ HOTSPOT_NO_ERROR);
+ handleWifiApStateChange(currentState, prevState, errorCode);
+ }
+ },
+ new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION));
+
// Adding optimizations of only receiving broadcasts when wifi is enabled
// can result in race conditions when apps toggle wifi in the background
// without active user involvement. Always receive broadcasts.
@@ -907,6 +933,108 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
/**
+ * Private method to handle SoftAp state changes
+ */
+ private void handleWifiApStateChange(int currentState, int previousState, int errorCode) {
+ // The AP state update from WifiStateMachine for softap
+ Slog.d(TAG, "handleWifiApStateChange: currentState=" + currentState
+ + " previousState=" + previousState + " errorCode= " + errorCode);
+
+ // check if we have a failure - since it is possible (worst case scenario where
+ // WifiController and WifiStateMachine are out of sync wrt modes) to get two FAILED
+ // notifications in a row, we need to handle this first.
+ if (currentState == WIFI_AP_STATE_FAILED) {
+ // update registered LOHS callbacks if we see a failure
+ synchronized (mLocalOnlyHotspotRequests) {
+ int errorToReport = ERROR_GENERIC;
+ if (errorCode == SAP_START_FAILURE_NO_CHANNEL) {
+ errorToReport = ERROR_NO_CHANNEL;
+ }
+ // holding the required lock: send message to requestors and clear the list
+ sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
+ errorToReport);
+ }
+ return;
+ }
+
+ if (currentState == WIFI_AP_STATE_DISABLING || currentState == WIFI_AP_STATE_DISABLED) {
+ // softap is shutting down or is down... let requestors know via the onStopped call
+ synchronized (mLocalOnlyHotspotRequests) {
+ // holding the required lock: send message to requestors and clear the list
+ sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked();
+ }
+ return;
+ }
+
+ // remaining states are enabling or enabled... those are not used for the callbacks
+ }
+
+ /**
+ * Helper method to send a HOTSPOT_FAILED message to all registered LocalOnlyHotspotRequest
+ * callers and clear the registrations.
+ *
+ * Callers should already hold the mLocalOnlyHotspotRequests lock.
+ */
+ private void sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int arg1) {
+ for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
+ try {
+ requestor.sendHotspotFailedMessage(arg1);
+ } catch (RemoteException e) {
+ // This will be cleaned up by binder death handling
+ }
+ }
+
+ // Since all callers were notified, now clear the registrations.
+ mLocalOnlyHotspotRequests.clear();
+ }
+
+ /**
+ * Helper method to send a HOTSPOT_STOPPED message to all registered LocalOnlyHotspotRequest
+ * callers and clear the registrations.
+ *
+ * Callers should already hold the mLocalOnlyHotspotRequests lock.
+ */
+ private void sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked() {
+ for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
+ try {
+ requestor.sendHotspotStoppedMessage();
+ } catch (RemoteException e) {
+ // This will be cleaned up by binder death handling
+ }
+ }
+
+ // Since all callers were notified, now clear the registrations.
+ mLocalOnlyHotspotRequests.clear();
+ }
+
+ /**
+ * Helper method to send a HOTSPOT_STARTED message to all registered LocalOnlyHotspotRequest
+ * callers.
+ *
+ * Callers should already hold the mLocalOnlyHotspotRequests lock.
+ */
+ private void sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked() {
+ for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
+ try {
+ requestor.sendHotspotStartedMessage(mLocalOnlyHotspotConfig);
+ } catch (RemoteException e) {
+ // This will be cleaned up by binder death handling
+ }
+ }
+ }
+
+ /**
+ * Temporary method used for testing while startLocalOnlyHotspot is not fully implemented. This
+ * method allows unit tests to register callbacks directly for testing mechanisms triggered by
+ * softap mode changes.
+ * TODO: remove when startLocalOnlyHotspot is implemented.
+ */
+ @VisibleForTesting
+ void registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request) {
+ mLocalOnlyHotspotRequests.put(pid, request);
+ }
+
+ /**
* Method to start LocalOnlyHotspot. In this method, permissions, settings and modes are
* checked to verify that we can enter softapmode. This method returns
* {@link LocalOnlyHotspotCallback#REQUEST_REGISTERED} if we will attempt to start, otherwise,
@@ -980,10 +1108,10 @@ public class WifiServiceImpl extends IWifiManager.Stub {
* Helper method to unregister LocalOnlyHotspot requestors and stop the hotspot if needed.
*/
private void unregisterCallingAppAndStopLocalOnlyHotspot(LocalOnlyHotspotRequestInfo request) {
- mLog.trace("unregisterCallingAppAndStopLocalOnlyHotspot uid=%").c(request.getUid()).flush();
+ mLog.trace("unregisterCallingAppAndStopLocalOnlyHotspot pid=%").c(request.getPid()).flush();
synchronized (mLocalOnlyHotspotRequests) {
- if (mLocalOnlyHotspotRequests.remove(request.getUid()) == null) {
+ if (mLocalOnlyHotspotRequests.remove(request.getPid()) == null) {
mLog.trace("LocalOnlyHotspotRequestInfo not found to remove");
return;
}
diff --git a/tests/wifitests/src/com/android/server/wifi/LocalOnlyHotspotRequestInfoTest.java b/tests/wifitests/src/com/android/server/wifi/LocalOnlyHotspotRequestInfoTest.java
index 0e8ead2e6..5f170b8f3 100644
--- a/tests/wifitests/src/com/android/server/wifi/LocalOnlyHotspotRequestInfoTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/LocalOnlyHotspotRequestInfoTest.java
@@ -17,11 +17,10 @@
package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.*;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -129,23 +128,48 @@ public class LocalOnlyHotspotRequestInfoTest {
}
/**
- * Verify the uid is properly set.
+ * Verify the pid is properly set.
*/
@Test
- public void verifyUid() {
+ public void verifyPid() {
mLOHSRequestInfo = new LocalOnlyHotspotRequestInfo(mAppBinder, mMessenger, mCallback);
- assertEquals(Process.myUid(), mLOHSRequestInfo.getUid());
+ assertEquals(Process.myPid(), mLOHSRequestInfo.getPid());
}
/**
- * Verify that sendMessage does send a Message properly
+ * Verify that sendHotspotFailedMessage does send a Message properly
*/
@Test
- public void verifySendMessenger() throws Exception {
+ public void verifySendFailedMessage() throws Exception {
mLOHSRequestInfo = new LocalOnlyHotspotRequestInfo(mAppBinder, mMessenger, mCallback);
- mLOHSRequestInfo.sendMessage(1, 1);
+ mLOHSRequestInfo.sendHotspotFailedMessage(
+ WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC);
Message message = mTestLooper.nextMessage();
- assertEquals(1, message.what);
- assertEquals(1, message.arg1);
+ assertEquals(WifiManager.HOTSPOT_FAILED, message.what);
+ assertEquals(WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC, message.arg1);
+ }
+
+ /**
+ * Verify that sendHotspotStartedMessage does send a Message properly
+ */
+ @Test
+ public void verifySendStartedMessage() throws Exception {
+ mLOHSRequestInfo = new LocalOnlyHotspotRequestInfo(mAppBinder, mMessenger, mCallback);
+ WifiConfiguration config = mock(WifiConfiguration.class);
+ mLOHSRequestInfo.sendHotspotStartedMessage(config);
+ Message message = mTestLooper.nextMessage();
+ assertEquals(WifiManager.HOTSPOT_STARTED, message.what);
+ assertEquals(config, (WifiConfiguration) message.obj);
+ }
+
+ /**
+ * Verify that sendHotspotStoppedMessage does send a Message properly
+ */
+ @Test
+ public void verifySendStoppedMessage() throws Exception {
+ mLOHSRequestInfo = new LocalOnlyHotspotRequestInfo(mAppBinder, mMessenger, mCallback);
+ mLOHSRequestInfo.sendHotspotStoppedMessage();
+ Message message = mTestLooper.nextMessage();
+ assertEquals(WifiManager.HOTSPOT_STOPPED, message.what);
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/TestUtil.java b/tests/wifitests/src/com/android/server/wifi/TestUtil.java
index 3b43ad8c5..90df07a61 100644
--- a/tests/wifitests/src/com/android/server/wifi/TestUtil.java
+++ b/tests/wifitests/src/com/android/server/wifi/TestUtil.java
@@ -71,6 +71,21 @@ public class TestUtil {
}
/**
+ * Send {@link WifiManager#WIFI_AP_STATE_CHANGED} broadcast.
+ */
+ public static void sendWifiApStateChanged(BroadcastReceiver broadcastReceiver,
+ Context context, int apState, int previousState, int error) {
+ Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, apState);
+ intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousState);
+ if (apState == WifiManager.WIFI_AP_STATE_FAILED) {
+ //only set reason number when softAP start failed
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, error);
+ }
+ broadcastReceiver.onReceive(context, intent);
+ }
+
+ /**
* Send {@link ConnectivityManager#ACTION_TETHER_STATE_CHANGED} broadcast.
*/
public static void sendTetherStateChanged(BroadcastReceiver broadcastReceiver,
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index bef3fc104..f1c19e6b3 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -16,12 +16,21 @@
package com.android.server.wifi;
+import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
+import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
+import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL;
+import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL;
+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_FAILED;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
import static android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
import static android.provider.Settings.Secure.LOCATION_MODE_OFF;
+import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR;
import static com.android.server.wifi.WifiController.CMD_SET_AP;
import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
@@ -35,8 +44,10 @@ import static org.mockito.Mockito.*;
import android.app.ActivityManager;
import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.IpConfiguration;
import android.net.wifi.ScanSettings;
@@ -64,6 +75,8 @@ import com.android.server.wifi.util.WifiPermissionsUtil;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
@@ -89,14 +102,21 @@ public class WifiServiceImplTest {
private static final String TEST_PACKAGE_NAME = "TestPackage";
private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
private static final String SYSUI_PACKAGE_NAME = "com.android.systemui";
- private static final int TEST_UID = 6789;
+ private static final int TEST_PID = 6789;
+ private static final int TEST_PID2 = 9876;
private WifiServiceImpl mWifiServiceImpl;
private TestLooper mLooper;
private PowerManager mPowerManager;
private Handler mHandler;
private Messenger mAppMessenger;
- private int mUid;
+ private int mPid;
+
+ final ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ final ArgumentCaptor<IntentFilter> mIntentFilterCaptor =
+ ArgumentCaptor.forClass(IntentFilter.class);
+
@Mock Context mContext;
@Mock WifiInjector mWifiInjector;
@@ -182,10 +202,10 @@ public class WifiServiceImplTest {
@Before public void setUp() {
MockitoAnnotations.initMocks(this);
mLooper = new TestLooper();
- mHandler = new Handler(mLooper.getLooper());
+ mHandler = spy(new Handler(mLooper.getLooper()));
mAppMessenger = new Messenger(mHandler);
- when(mRequestInfo.getUid()).thenReturn(mUid);
+ when(mRequestInfo.getPid()).thenReturn(mPid);
when(mWifiInjector.getUserManager()).thenReturn(mUserManager);
when(mWifiInjector.getWifiController()).thenReturn(mWifiController);
when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics);
@@ -824,6 +844,219 @@ public class WifiServiceImplTest {
verify(mWifiController, never()).sendMessage(eq(CMD_SET_AP), eq(0), eq(0));
}
+ private class IntentFilterMatcher implements ArgumentMatcher<IntentFilter> {
+ @Override
+ public boolean matches(IntentFilter filter) {
+ return filter.hasAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+ }
+ }
+
+ /**
+ * Verify that onFailed is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE
+ * broadcast is received.
+ */
+ @Test
+ public void testRegisteredCallbacksTriggeredOnSoftApFailureGeneric() throws Exception {
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo);
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_GENERAL);
+
+ verify(mRequestInfo).sendHotspotFailedMessage(ERROR_GENERIC);
+ }
+
+ /**
+ * Verify that onFailed is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE
+ * broadcast is received with the SAP_START_FAILURE_NO_CHANNEL error.
+ */
+ @Test
+ public void testRegisteredCallbacksTriggeredOnSoftApFailureNoChannel() throws Exception {
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo);
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_NO_CHANNEL);
+
+ verify(mRequestInfo).sendHotspotFailedMessage(ERROR_NO_CHANNEL);
+ }
+
+ /**
+ * Verify that onStopped is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE
+ * broadcast is received with WIFI_AP_STATE_DISABLING.
+ */
+ @Test
+ public void testRegisteredCallbacksTriggeredOnSoftApDisabling() throws Exception {
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo);
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR);
+
+ verify(mRequestInfo).sendHotspotStoppedMessage();
+ }
+
+
+ /**
+ * Verify that onStopped is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE
+ * broadcast is received with WIFI_AP_STATE_DISABLED.
+ */
+ @Test
+ public void testRegisteredCallbacksTriggeredOnSoftApDisabled() throws Exception {
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo);
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR);
+
+ verify(mRequestInfo).sendHotspotStoppedMessage();
+ }
+
+ /**
+ * Verify that no callbacks are called for registered LOHS callers when a WIFI_AP_STATE_CHANGE
+ * broadcast is received and the softap started.
+ */
+ @Test
+ public void testRegisteredCallbacksNotTriggeredOnSoftApStart() throws Exception {
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo);
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR);
+ verifyNoMoreInteractions(mRequestInfo);
+ }
+
+ /**
+ * Verify that onStopped is called only once for registered LOHS callers when
+ * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_DISABLING and
+ * WIFI_AP_STATE_DISABLED.
+ */
+ @Test
+ public void testRegisteredCallbacksTriggeredOnlyOnceWhenSoftApDisabling() throws Exception {
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo);
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR);
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR);
+
+ verify(mRequestInfo).sendHotspotStoppedMessage();
+ }
+
+ /**
+ * Verify that onFailed is called only once for registered LOHS callers when
+ * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_FAILED twice.
+ */
+ @Test
+ public void testRegisteredCallbacksTriggeredOnlyOnceWhenSoftApFailsTwice() throws Exception {
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo);
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC);
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC);
+
+ verify(mRequestInfo).sendHotspotFailedMessage(ERROR_GENERIC);
+ }
+
+ /**
+ * Verify that onFailed is called for all registered LOHS callers when
+ * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_FAILED.
+ */
+ @Test
+ public void testAllRegisteredCallbacksTriggeredWhenSoftApFails() throws Exception {
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ // make an additional request for this test
+ LocalOnlyHotspotRequestInfo request2 = mock(LocalOnlyHotspotRequestInfo.class);
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo);
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID2, request2);
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC);
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC);
+
+ verify(mRequestInfo).sendHotspotFailedMessage(ERROR_GENERIC);
+ verify(request2).sendHotspotFailedMessage(ERROR_GENERIC);
+ }
+
+ /**
+ * Verify that onFailed is called for all registered LOHS callers when
+ * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_DISABLED.
+ */
+ @Test
+ public void testAllRegisteredCallbacksTriggeredWhenSoftApStops() throws Exception {
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ // make an additional request for this test
+ LocalOnlyHotspotRequestInfo request2 = mock(LocalOnlyHotspotRequestInfo.class);
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo);
+ mWifiServiceImpl.registerLOHSForTest(TEST_PID2, request2);
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR);
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR);
+
+ verify(mRequestInfo).sendHotspotStoppedMessage();
+ verify(request2).sendHotspotStoppedMessage();
+ }
+
/**
* Verify that a call to startWatchLocalOnlyHotspot is only allowed from callers with the
* signature only NETWORK_SETTINGS permission.