diff options
| -rw-r--r-- | wifi/java/android/net/wifi/WifiManager.java | 43 | ||||
| -rw-r--r-- | wifi/tests/src/android/net/wifi/WifiManagerTest.java | 582 |
2 files changed, 622 insertions, 3 deletions
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 6f1324e95305..f3e549364776 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -40,6 +40,7 @@ import android.os.WorkSource; import android.util.Log; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; @@ -862,6 +863,12 @@ public class WifiManager { /** @hide */ public static final int HOTSPOT_OBSERVER_REGISTERED = 3; + private final Object mLock = new Object(); // lock guarding access to the following vars + @GuardedBy("mLock") + private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy; + @GuardedBy("mLock") + private LocalOnlyHotspotObserverProxy mLOHSObserverProxy; + /** * Create a new WifiManager instance. * Applications will almost always want to use @@ -1880,7 +1887,24 @@ public class WifiManager { */ public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback, @Nullable Handler handler) { - throw new UnsupportedOperationException("LocalOnlyHotspot is still in development"); + synchronized (mLock) { + Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); + LocalOnlyHotspotCallbackProxy proxy = + new LocalOnlyHotspotCallbackProxy(this, looper, callback); + try { + WifiConfiguration config = mService.startLocalOnlyHotspot( + proxy.getMessenger(), new Binder()); + if (config == null) { + // Send message to the proxy to make sure we call back on the correct thread + proxy.notifyFailed( + LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE); + return; + } + mLOHSCallbackProxy = proxy; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } /** @@ -1897,7 +1921,9 @@ public class WifiManager { * @hide */ public void cancelLocalOnlyHotspotRequest() { - throw new UnsupportedOperationException("LocalOnlyHotspot is still in development"); + synchronized (mLock) { + stopLocalOnlyHotspot(); + } } /** @@ -1911,7 +1937,18 @@ public class WifiManager { * method on their LocalOnlyHotspotReservation. */ private void stopLocalOnlyHotspot() { - throw new UnsupportedOperationException("LocalOnlyHotspot is still in development"); + synchronized (mLock) { + if (mLOHSCallbackProxy == null) { + // nothing to do, the callback was already cleaned up. + return; + } + mLOHSCallbackProxy = null; + try { + mService.stopLocalOnlyHotspot(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } /** diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java new file mode 100644 index 000000000000..75cd09530b5d --- /dev/null +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -0,0 +1,582 @@ +/* + * Copyright (C) 2017 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 android.net.wifi; + +import static android.net.wifi.WifiManager.HOTSPOT_FAILED; +import static android.net.wifi.WifiManager.HOTSPOT_STARTED; +import static android.net.wifi.WifiManager.HOTSPOT_STOPPED; +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 org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.*; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.net.wifi.WifiManager.LocalOnlyHotspotCallback; +import android.net.wifi.WifiManager.LocalOnlyHotspotObserver; +import android.net.wifi.WifiManager.LocalOnlyHotspotReservation; +import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.test.TestLooper; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Unit tests for {@link android.net.wifi.WifiManager}. + */ +@SmallTest +public class WifiManagerTest { + + private static final int ERROR_NOT_SET = -1; + private static final int ERROR_TEST_REASON = 5; + + @Mock Context mContext; + @Mock IWifiManager mWifiService; + @Mock ApplicationInfo mApplicationInfo; + @Mock WifiConfiguration mApConfig; + @Mock IBinder mAppBinder; + + private Handler mHandler; + private TestLooper mLooper; + private WifiManager mWifiManager; + private Messenger mWifiServiceMessenger; + final ArgumentCaptor<Messenger> mMessengerCaptor = ArgumentCaptor.forClass(Messenger.class); + + @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mLooper = new TestLooper(); + mHandler = spy(new Handler(mLooper.getLooper())); + when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); + + mWifiServiceMessenger = new Messenger(mHandler); + mWifiManager = new WifiManager(mContext, mWifiService, mLooper.getLooper()); + } + + /** + * Check the call to startSoftAp calls WifiService to startSoftAp with the provided + * WifiConfiguration. Verify that the return value is propagated to the caller. + */ + @Test + public void testStartSoftApCallsServiceWithWifiConfig() throws Exception { + when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(true); + assertTrue(mWifiManager.startSoftAp(mApConfig)); + + when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(false); + assertFalse(mWifiManager.startSoftAp(mApConfig)); + } + + /** + * Check the call to startSoftAp calls WifiService to startSoftAp with a null config. Verify + * that the return value is propagated to the caller. + */ + @Test + public void testStartSoftApCallsServiceWithNullConfig() throws Exception { + when(mWifiService.startSoftAp(eq(null))).thenReturn(true); + assertTrue(mWifiManager.startSoftAp(null)); + + when(mWifiService.startSoftAp(eq(null))).thenReturn(false); + assertFalse(mWifiManager.startSoftAp(null)); + } + + /** + * Check the call to stopSoftAp calls WifiService to stopSoftAp. + */ + @Test + public void testStopSoftApCallsService() throws Exception { + when(mWifiService.stopSoftAp()).thenReturn(true); + assertTrue(mWifiManager.stopSoftAp()); + + when(mWifiService.stopSoftAp()).thenReturn(false); + assertFalse(mWifiManager.stopSoftAp()); + } + + /** + * Test creation of a LocalOnlyHotspotReservation and verify that close properly calls + * WifiService.stopLocalOnlyHotspot. + */ + @Test + public void testCreationAndCloseOfLocalOnlyHotspotReservation() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class))) + .thenReturn(mApConfig); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + + callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(mApConfig)); + + assertEquals(mApConfig, callback.mRes.getConfig()); + callback.mRes.close(); + verify(mWifiService).stopLocalOnlyHotspot(); + } + + /** + * Verify stopLOHS is called when try-with-resources is used properly. + */ + @Test + public void testLocalOnlyHotspotReservationCallsStopProperlyInTryWithResources() + throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class))) + .thenReturn(mApConfig); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + + callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(mApConfig)); + + try (WifiManager.LocalOnlyHotspotReservation res = callback.mRes) { + assertEquals(mApConfig, res.getConfig()); + } + + verify(mWifiService).stopLocalOnlyHotspot(); + } + + /** + * Test creation of a LocalOnlyHotspotSubscription. + * TODO: when registrations are tracked, verify removal on close. + */ + @Test + public void testCreationOfLocalOnlyHotspotSubscription() throws Exception { + try (WifiManager.LocalOnlyHotspotSubscription sub = + mWifiManager.new LocalOnlyHotspotSubscription()) { + sub.close(); + } + } + + public class TestLocalOnlyHotspotCallback extends LocalOnlyHotspotCallback { + public boolean mOnStartedCalled = false; + public boolean mOnStoppedCalled = false; + public int mFailureReason = -1; + public LocalOnlyHotspotReservation mRes = null; + public long mCallingThreadId = -1; + + @Override + public void onStarted(LocalOnlyHotspotReservation r) { + mRes = r; + mOnStartedCalled = true; + mCallingThreadId = Thread.currentThread().getId(); + } + + @Override + public void onStopped() { + mOnStoppedCalled = true; + mCallingThreadId = Thread.currentThread().getId(); + } + + @Override + public void onFailed(int reason) { + mFailureReason = reason; + mCallingThreadId = Thread.currentThread().getId(); + } + } + + /** + * Verify callback is properly plumbed when called. + */ + @Test + public void testLocalOnlyHotspotCallback() { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + assertFalse(callback.mOnStartedCalled); + assertFalse(callback.mOnStoppedCalled); + assertEquals(ERROR_NOT_SET, callback.mFailureReason); + assertEquals(null, callback.mRes); + + // test onStarted + WifiManager.LocalOnlyHotspotReservation res = + mWifiManager.new LocalOnlyHotspotReservation(mApConfig); + callback.onStarted(res); + assertEquals(res, callback.mRes); + assertTrue(callback.mOnStartedCalled); + assertFalse(callback.mOnStoppedCalled); + assertEquals(ERROR_NOT_SET, callback.mFailureReason); + + // test onStopped + callback.onStopped(); + assertEquals(res, callback.mRes); + assertTrue(callback.mOnStartedCalled); + assertTrue(callback.mOnStoppedCalled); + assertEquals(ERROR_NOT_SET, callback.mFailureReason); + + // test onFailed + callback.onFailed(ERROR_TEST_REASON); + assertEquals(res, callback.mRes); + assertTrue(callback.mOnStartedCalled); + assertTrue(callback.mOnStoppedCalled); + assertEquals(ERROR_TEST_REASON, callback.mFailureReason); + } + + public class TestLocalOnlyHotspotObserver extends LocalOnlyHotspotObserver { + public boolean mOnRegistered = false; + public boolean mOnStartedCalled = false; + public boolean mOnStoppedCalled = false; + public WifiConfiguration mConfig = null; + public LocalOnlyHotspotSubscription mSub = null; + + @Override + public void onRegistered(LocalOnlyHotspotSubscription sub) { + mOnRegistered = true; + mSub = sub; + } + + @Override + public void onStarted(WifiConfiguration config) { + mOnStartedCalled = true; + mConfig = config; + } + + @Override + public void onStopped() { + mOnStoppedCalled = true; + } + } + + /** + * Verify observer is properly plumbed when called. + */ + @Test + public void testLocalOnlyHotspotObserver() { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + assertFalse(observer.mOnRegistered); + assertFalse(observer.mOnStartedCalled); + assertFalse(observer.mOnStoppedCalled); + assertEquals(null, observer.mConfig); + assertEquals(null, observer.mSub); + + WifiManager.LocalOnlyHotspotSubscription sub = + mWifiManager.new LocalOnlyHotspotSubscription(); + observer.onRegistered(sub); + assertTrue(observer.mOnRegistered); + assertFalse(observer.mOnStartedCalled); + assertFalse(observer.mOnStoppedCalled); + assertEquals(null, observer.mConfig); + assertEquals(sub, observer.mSub); + + observer.onStarted(mApConfig); + assertTrue(observer.mOnRegistered); + assertTrue(observer.mOnStartedCalled); + assertFalse(observer.mOnStoppedCalled); + assertEquals(mApConfig, observer.mConfig); + assertEquals(sub, observer.mSub); + + observer.onStopped(); + assertTrue(observer.mOnRegistered); + assertTrue(observer.mOnStartedCalled); + assertTrue(observer.mOnStoppedCalled); + assertEquals(mApConfig, observer.mConfig); + assertEquals(sub, observer.mSub); + } + + /** + * Verify call to startLocalOnlyHotspot goes to WifiServiceImpl. + */ + @Test + public void testStartLocalOnlyHotspot() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + + verify(mWifiService).startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + } + + /** + * Verify a SecurityException is thrown for callers without proper permissions for + * startLocalOnlyHotspot. + */ + @Test(expected = SecurityException.class) + public void testStartLocalOnlyHotspotThrowsSecurityException() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + doThrow(new SecurityException()).when(mWifiService) + .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + } + + /** + * Verify an IllegalStateException is thrown for callers that already have a pending request for + * startLocalOnlyHotspot. + */ + @Test(expected = IllegalStateException.class) + public void testStartLocalOnlyHotspotThrowsIllegalStateException() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + doThrow(new IllegalStateException()).when(mWifiService) + .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + } + + /** + * Verify the watchLocalOnlyHotspot call currently throws an UnsupportedOperationException. + */ + @Test(expected = UnsupportedOperationException.class) + public void testWatchLocalOnlyHotspot() throws Exception { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + mWifiManager.watchLocalOnlyHotspot(observer, mHandler); + } + + /** + * Verify that the handler provided by the caller is used for the callbacks. + */ + @Test + public void testCorrectLooperIsUsedForHandler() throws Exception { + // record thread from looper.getThread and check ids. + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class))) + .thenReturn(null); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + mLooper.dispatchAll(); + assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason); + assertEquals(mLooper.getLooper().getThread().getId(), callback.mCallingThreadId); + } + + /** + * Verify that the main looper's thread is used if a handler is not provided by the reqiestomg + * application. + */ + @Test + public void testMainLooperIsUsedWhenHandlerNotProvided() throws Exception { + // record thread from looper.getThread and check ids. + TestLooper altLooper = new TestLooper(); + when(mContext.getMainLooper()).thenReturn(altLooper.getLooper()); + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class))) + .thenReturn(null); + mWifiManager.startLocalOnlyHotspot(callback, null); + altLooper.dispatchAll(); + assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason); + assertEquals(altLooper.getLooper().getThread().getId(), callback.mCallingThreadId); + } + + /** + * Verify the LOHS onStarted callback is triggered when WifiManager receives a HOTSPOT_STARTED + * message from WifiServiceImpl. + */ + @Test + public void testOnStartedIsCalledWithReservation() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + TestLooper callbackLooper = new TestLooper(); + Handler callbackHandler = new Handler(callbackLooper.getLooper()); + when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(), + any(IBinder.class))).thenReturn(mApConfig); + mWifiManager.startLocalOnlyHotspot(callback, callbackHandler); + callbackLooper.dispatchAll(); + mLooper.dispatchAll(); + assertFalse(callback.mOnStartedCalled); + assertEquals(null, callback.mRes); + // now trigger the callback + Message msg = new Message(); + msg.what = HOTSPOT_STARTED; + msg.obj = mApConfig; + mMessengerCaptor.getValue().send(msg); + mLooper.dispatchAll(); + callbackLooper.dispatchAll(); + assertTrue(callback.mOnStartedCalled); + assertEquals(mApConfig, callback.mRes.getConfig()); + } + + /** + * Verify onFailed is called if WifiServiceImpl sends a HOTSPOT_STARTED message with a null + * config. + */ + @Test + public void testOnStartedIsCalledWithNullConfig() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + TestLooper callbackLooper = new TestLooper(); + Handler callbackHandler = new Handler(callbackLooper.getLooper()); + when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(), + any(IBinder.class))).thenReturn(mApConfig); + mWifiManager.startLocalOnlyHotspot(callback, callbackHandler); + callbackLooper.dispatchAll(); + mLooper.dispatchAll(); + assertFalse(callback.mOnStartedCalled); + assertEquals(null, callback.mRes); + // now trigger the callback + Message msg = new Message(); + msg.what = HOTSPOT_STARTED; + mMessengerCaptor.getValue().send(msg); + mLooper.dispatchAll(); + callbackLooper.dispatchAll(); + assertFalse(callback.mOnStartedCalled); + assertEquals(ERROR_GENERIC, callback.mFailureReason); + } + + /** + * Verify onStopped is called if WifiServiceImpl sends a HOTSPOT_STOPPED message. + */ + @Test + public void testOnStoppedIsCalled() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + TestLooper callbackLooper = new TestLooper(); + Handler callbackHandler = new Handler(callbackLooper.getLooper()); + when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(), + any(IBinder.class))).thenReturn(mApConfig); + mWifiManager.startLocalOnlyHotspot(callback, callbackHandler); + callbackLooper.dispatchAll(); + mLooper.dispatchAll(); + assertFalse(callback.mOnStoppedCalled); + // now trigger the callback + Message msg = new Message(); + msg.what = HOTSPOT_STOPPED; + mMessengerCaptor.getValue().send(msg); + mLooper.dispatchAll(); + callbackLooper.dispatchAll(); + assertTrue(callback.mOnStoppedCalled); + } + + /** + * Verify onFailed is called if WifiServiceImpl sends a HOTSPOT_FAILED message. + */ + @Test + public void testOnFailedIsCalled() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + TestLooper callbackLooper = new TestLooper(); + Handler callbackHandler = new Handler(callbackLooper.getLooper()); + when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(), + any(IBinder.class))).thenReturn(mApConfig); + mWifiManager.startLocalOnlyHotspot(callback, callbackHandler); + callbackLooper.dispatchAll(); + mLooper.dispatchAll(); + assertEquals(ERROR_NOT_SET, callback.mFailureReason); + // now trigger the callback + Message msg = new Message(); + msg.what = HOTSPOT_FAILED; + msg.arg1 = ERROR_NO_CHANNEL; + mMessengerCaptor.getValue().send(msg); + mLooper.dispatchAll(); + callbackLooper.dispatchAll(); + assertEquals(ERROR_NO_CHANNEL, callback.mFailureReason); + } + + /** + * Verify the handler passed in to startLocalOnlyHotspot is correctly used for callbacks when a + * null WifiConfig is returned. + */ + @Test + public void testLocalOnlyHotspotCallbackFullOnNullConfig() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class))) + .thenReturn(null); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + mLooper.dispatchAll(); + assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason); + assertFalse(callback.mOnStartedCalled); + assertFalse(callback.mOnStoppedCalled); + assertEquals(null, callback.mRes); + } + + /** + * Verify a SecurityException resulting from an application without necessary permissions will + * bubble up through the call to start LocalOnlyHotspot and will not trigger other callbacks. + */ + @Test(expected = SecurityException.class) + public void testLocalOnlyHotspotCallbackFullOnSecurityException() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + doThrow(new SecurityException()).when(mWifiService) + .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + try { + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + } catch (SecurityException e) { + assertEquals(ERROR_NOT_SET, callback.mFailureReason); + assertFalse(callback.mOnStartedCalled); + assertFalse(callback.mOnStoppedCalled); + assertEquals(null, callback.mRes); + throw e; + } + + } + + /** + * Verify the handler passed to startLocalOnlyHotspot is correctly used for callbacks when + * SoftApMode fails due to a underlying error. + */ + @Test + public void testLocalOnlyHotspotCallbackFullOnNoChannelError() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class))) + .thenReturn(mApConfig); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + mLooper.dispatchAll(); + //assertEquals(ERROR_NO_CHANNEL, callback.mFailureReason); + assertFalse(callback.mOnStartedCalled); + assertFalse(callback.mOnStoppedCalled); + assertEquals(null, callback.mRes); + } + + /** + * Verify that the call to cancel a LOHS request does call stopLOHS. + */ + @Test + public void testCancelLocalOnlyHotspotRequestCallsStopOnWifiService() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class))) + .thenReturn(mApConfig); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + mWifiManager.cancelLocalOnlyHotspotRequest(); + verify(mWifiService).stopLocalOnlyHotspot(); + } + + /** + * Verify that we do not crash if cancelLocalOnlyHotspotRequest is called without an existing + * callback stored. + */ + @Test + public void testCancelLocalOnlyHotspotReturnsWithoutExistingRequest() { + mWifiManager.cancelLocalOnlyHotspotRequest(); + } + + /** + * Verify that the callback is not triggered if the LOHS request was already cancelled. + */ + @Test + public void testCallbackAfterLocalOnlyHotspotWasCancelled() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class))) + .thenReturn(mApConfig); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + mWifiManager.cancelLocalOnlyHotspotRequest(); + verify(mWifiService).stopLocalOnlyHotspot(); + mLooper.dispatchAll(); + assertEquals(ERROR_NOT_SET, callback.mFailureReason); + assertFalse(callback.mOnStartedCalled); + assertFalse(callback.mOnStoppedCalled); + assertEquals(null, callback.mRes); + } + + /** + * Verify that calling cancel LOHS request does not crash if an error callback was already + * handled. + */ + @Test + public void testCancelAfterLocalOnlyHotspotCallbackTriggered() throws Exception { + TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); + when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class))) + .thenReturn(null); + mWifiManager.startLocalOnlyHotspot(callback, mHandler); + mLooper.dispatchAll(); + assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason); + assertFalse(callback.mOnStartedCalled); + assertFalse(callback.mOnStoppedCalled); + assertEquals(null, callback.mRes); + mWifiManager.cancelLocalOnlyHotspotRequest(); + verify(mWifiService, never()).stopLocalOnlyHotspot(); + } +} |