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
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index f3e5493..8fbf472 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1970,7 +1970,18 @@
*/
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 @@
* @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 75cd095..3c0fc6e 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 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 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 @@
}
/**
- * 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 @@
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();
+ }
+
}