From 4871da6b0715bf09b14fb593cfe112733d0c53ef Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Thu, 27 Apr 2017 13:57:19 -0700 Subject: [PATCH] WifiManager: implement watch LocalOnlyHotspot Implement new calls to watchLocalOnlyHotspot and unregisterLocalOnlyHotspotObserver along with the classes LocalOnlyHotspotObserver and LocalOnlyHotspotSubscription. Added tests for watching LOHS and cancelling a LOHS subscription. The calls will be exposed in a later CL. Bug: 36704763 Test: compiles Test: frameworks/base/wifi/tests/runtests.sh Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: Ia0a528191ae0897742304d8b61e9779ad721a450 --- wifi/java/android/net/wifi/WifiManager.java | 27 ++- .../src/android/net/wifi/WifiManagerTest.java | 197 ++++++++++++++++++++- 2 files changed, 212 insertions(+), 12 deletions(-) diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index f3e549364776..8fbf4721a20e 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1970,7 +1970,18 @@ public class WifiManager { */ public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer, @Nullable Handler handler) { - throw new UnsupportedOperationException("LocalOnlyHotspot is still in development"); + synchronized (mLock) { + Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); + mLOHSObserverProxy = new LocalOnlyHotspotObserverProxy(this, looper, observer); + try { + mService.startWatchLocalOnlyHotspot( + mLOHSObserverProxy.getMessenger(), new Binder()); + mLOHSObserverProxy.registered(); + } catch (RemoteException e) { + mLOHSObserverProxy = null; + throw e.rethrowFromSystemServer(); + } + } } /** @@ -1980,10 +1991,20 @@ public class WifiManager { * @hide */ public void unregisterLocalOnlyHotspotObserver() { - throw new UnsupportedOperationException("LocalOnlyHotspot is still in development"); + synchronized (mLock) { + if (mLOHSObserverProxy == null) { + // nothing to do, the callback was already cleaned up + return; + } + mLOHSObserverProxy = null; + try { + mService.stopWatchLocalOnlyHotspot(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } - /** * Gets the Wi-Fi enabled state. * @return One of {@link #WIFI_AP_STATE_DISABLED}, diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 75cd09530b5d..3c0fc6ef0aa8 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -25,6 +25,7 @@ import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHA import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; @@ -234,22 +235,26 @@ public class WifiManagerTest { public boolean mOnStoppedCalled = false; public WifiConfiguration mConfig = null; public LocalOnlyHotspotSubscription mSub = null; + public long mCallingThreadId = -1; @Override public void onRegistered(LocalOnlyHotspotSubscription sub) { mOnRegistered = true; mSub = sub; + mCallingThreadId = Thread.currentThread().getId(); } @Override public void onStarted(WifiConfiguration config) { mOnStartedCalled = true; mConfig = config; + mCallingThreadId = Thread.currentThread().getId(); } @Override public void onStopped() { mOnStoppedCalled = true; + mCallingThreadId = Thread.currentThread().getId(); } } @@ -325,15 +330,6 @@ public class WifiManagerTest { } /** - * 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 @@ -579,4 +575,187 @@ public class WifiManagerTest { mWifiManager.cancelLocalOnlyHotspotRequest(); verify(mWifiService, never()).stopLocalOnlyHotspot(); } + + /** + * Verify the watchLocalOnlyHotspot call goes to WifiServiceImpl. + */ + public void testWatchLocalOnlyHotspot() throws Exception { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + + mWifiManager.watchLocalOnlyHotspot(observer, mHandler); + verify(mWifiService).startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + } + + /** + * Verify a SecurityException is thrown for callers without proper permissions for + * startWatchLocalOnlyHotspot. + */ + @Test(expected = SecurityException.class) + public void testStartWatchLocalOnlyHotspotThrowsSecurityException() throws Exception { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + doThrow(new SecurityException()).when(mWifiService) + .startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + mWifiManager.watchLocalOnlyHotspot(observer, mHandler); + } + + /** + * Verify an IllegalStateException is thrown for callers that already have a pending request for + * watchLocalOnlyHotspot. + */ + @Test(expected = IllegalStateException.class) + public void testStartWatchLocalOnlyHotspotThrowsIllegalStateException() throws Exception { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + doThrow(new IllegalStateException()).when(mWifiService) + .startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + mWifiManager.watchLocalOnlyHotspot(observer, mHandler); + } + + /** + * Verify that the handler provided by the caller is used for the observer. + */ + @Test + public void testCorrectLooperIsUsedForObserverHandler() throws Exception { + // record thread from looper.getThread and check ids. + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + mWifiManager.watchLocalOnlyHotspot(observer, mHandler); + mLooper.dispatchAll(); + assertTrue(observer.mOnRegistered); + assertEquals(mLooper.getLooper().getThread().getId(), observer.mCallingThreadId); + } + + /** + * Verify that the main looper's thread is used if a handler is not provided by the requesting + * application. + */ + @Test + public void testMainLooperIsUsedWhenHandlerNotProvidedForObserver() throws Exception { + // record thread from looper.getThread and check ids. + TestLooper altLooper = new TestLooper(); + when(mContext.getMainLooper()).thenReturn(altLooper.getLooper()); + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + mWifiManager.watchLocalOnlyHotspot(observer, null); + altLooper.dispatchAll(); + assertTrue(observer.mOnRegistered); + assertEquals(altLooper.getLooper().getThread().getId(), observer.mCallingThreadId); + } + + /** + * Verify the LOHS onRegistered observer callback is triggered when WifiManager receives a + * HOTSPOT_OBSERVER_REGISTERED message from WifiServiceImpl. + */ + @Test + public void testOnRegisteredIsCalledWithSubscription() throws Exception { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + TestLooper observerLooper = new TestLooper(); + Handler observerHandler = new Handler(observerLooper.getLooper()); + assertFalse(observer.mOnRegistered); + assertEquals(null, observer.mSub); + mWifiManager.watchLocalOnlyHotspot(observer, observerHandler); + verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(), + any(IBinder.class)); + // now trigger the callback + observerLooper.dispatchAll(); + mLooper.dispatchAll(); + assertTrue(observer.mOnRegistered); + assertNotNull(observer.mSub); + } + + /** + * Verify the LOHS onStarted observer callback is triggered when WifiManager receives a + * HOTSPOT_STARTED message from WifiServiceImpl. + */ + @Test + public void testObserverOnStartedIsCalledWithWifiConfig() throws Exception { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + TestLooper observerLooper = new TestLooper(); + Handler observerHandler = new Handler(observerLooper.getLooper()); + mWifiManager.watchLocalOnlyHotspot(observer, observerHandler); + verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(), + any(IBinder.class)); + observerLooper.dispatchAll(); + mLooper.dispatchAll(); + assertFalse(observer.mOnStartedCalled); + // now trigger the callback + Message msg = new Message(); + msg.what = HOTSPOT_STARTED; + msg.obj = mApConfig; + mMessengerCaptor.getValue().send(msg); + mLooper.dispatchAll(); + observerLooper.dispatchAll(); + assertTrue(observer.mOnStartedCalled); + assertEquals(mApConfig, observer.mConfig); + } + + /** + * Verify the LOHS onStarted observer callback is triggered not when WifiManager receives a + * HOTSPOT_STARTED message from WifiServiceImpl with a null config. + */ + @Test + public void testObserverOnStartedNotCalledWithNullConfig() throws Exception { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + TestLooper observerLooper = new TestLooper(); + Handler observerHandler = new Handler(observerLooper.getLooper()); + mWifiManager.watchLocalOnlyHotspot(observer, observerHandler); + verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(), + any(IBinder.class)); + observerLooper.dispatchAll(); + mLooper.dispatchAll(); + assertFalse(observer.mOnStartedCalled); + // now trigger the callback + Message msg = new Message(); + msg.what = HOTSPOT_STARTED; + mMessengerCaptor.getValue().send(msg); + mLooper.dispatchAll(); + observerLooper.dispatchAll(); + assertFalse(observer.mOnStartedCalled); + assertEquals(null, observer.mConfig); + } + + + /** + * Verify the LOHS onStopped observer callback is triggered when WifiManager receives a + * HOTSPOT_STOPPED message from WifiServiceImpl. + */ + @Test + public void testObserverOnStoppedIsCalled() throws Exception { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + TestLooper observerLooper = new TestLooper(); + Handler observerHandler = new Handler(observerLooper.getLooper()); + mWifiManager.watchLocalOnlyHotspot(observer, observerHandler); + verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(), + any(IBinder.class)); + observerLooper.dispatchAll(); + mLooper.dispatchAll(); + assertFalse(observer.mOnStoppedCalled); + // now trigger the callback + Message msg = new Message(); + msg.what = HOTSPOT_STOPPED; + mMessengerCaptor.getValue().send(msg); + mLooper.dispatchAll(); + observerLooper.dispatchAll(); + assertTrue(observer.mOnStoppedCalled); + } + + /** + * Verify WifiServiceImpl is not called if there is not a registered LOHS observer callback. + */ + @Test + public void testUnregisterWifiServiceImplNotCalledWithoutRegisteredObserver() throws Exception { + mWifiManager.unregisterLocalOnlyHotspotObserver(); + verifyZeroInteractions(mWifiService); + } + + /** + * Verify WifiServiceImpl is called when there is a registered LOHS observer callback. + */ + @Test + public void testUnregisterWifiServiceImplCalledWithRegisteredObserver() throws Exception { + TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); + TestLooper observerLooper = new TestLooper(); + Handler observerHandler = new Handler(observerLooper.getLooper()); + mWifiManager.watchLocalOnlyHotspot(observer, observerHandler); + mWifiManager.unregisterLocalOnlyHotspotObserver(); + verify(mWifiService).stopWatchLocalOnlyHotspot(); + } + } -- 2.11.0