From b1c4cb795c3fa62cac7fbee66d0dda5cee19b49d Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Wed, 26 Apr 2017 21:50:04 -0700 Subject: [PATCH 1/5] WifiManager: add LocalOnlyHotspotCallbackProxy Add the proxy for LOHS callbacks to make sure we give updates to calling apps on the correct thread. This will be used in a follow-on CL. Bug: 36704763 Test: mmma -j64 frameworks/base/ Change-Id: Ib32dfd232ff8aaeb5f7b228cf0cfc3fd23fd7ee4 --- wifi/java/android/net/wifi/WifiManager.java | 93 +++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 7bf1d60d578bd..f806f1c748506 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -47,6 +47,7 @@ import com.android.server.net.NetworkPinner; import dalvik.system.CloseGuard; +import java.lang.ref.WeakReference; import java.net.InetAddress; import java.util.Collections; import java.util.List; @@ -851,6 +852,16 @@ public class WifiManager { private CountDownLatch mConnected; private Looper mLooper; + /* LocalOnlyHotspot callback message types */ + /** @hide */ + public static final int HOTSPOT_STARTED = 0; + /** @hide */ + public static final int HOTSPOT_STOPPED = 1; + /** @hide */ + public static final int HOTSPOT_FAILED = 2; + /** @hide */ + public static final int HOTSPOT_OBSERVER_REGISTERED = 3; + /** * Create a new WifiManager instance. * Applications will almost always want to use @@ -2282,6 +2293,88 @@ public class WifiManager { public void onFailed(int reason) { }; } + /** + * Callback proxy for LocalOnlyHotspotCallback objects. + */ + private static class LocalOnlyHotspotCallbackProxy { + private final Handler mHandler; + private final WeakReference mWifiManager; + private final Looper mLooper; + private final Messenger mMessenger; + + /** + * Constructs a {@link LocalOnlyHotspotCallback} using the specified looper. All callbacks + * will be delivered on the thread of the specified looper. + * + * @param manager WifiManager + * @param looper Looper for delivering callbacks + * @param callback LocalOnlyHotspotCallback to notify the calling application. + */ + LocalOnlyHotspotCallbackProxy(WifiManager manager, Looper looper, + final LocalOnlyHotspotCallback callback) { + mWifiManager = new WeakReference<>(manager); + mLooper = looper; + + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + Log.d(TAG, "LocalOnlyHotspotCallbackProxy: handle message what: " + + msg.what + " msg: " + msg); + + WifiManager manager = mWifiManager.get(); + if (manager == null) { + Log.w(TAG, "LocalOnlyHotspotCallbackProxy: handle message post GC"); + return; + } + + switch (msg.what) { + case HOTSPOT_STARTED: + WifiConfiguration config = (WifiConfiguration) msg.obj; + if (config == null) { + Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null."); + callback.onFailed(LocalOnlyHotspotCallback.ERROR_GENERIC); + return; + } + callback.onStarted(manager.new LocalOnlyHotspotReservation(config)); + break; + case HOTSPOT_STOPPED: + Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped"); + callback.onStopped(); + break; + case HOTSPOT_FAILED: + int reasonCode = msg.arg1; + Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start. reason: " + + reasonCode); + callback.onFailed(reasonCode); + Log.w(TAG, "done with the callback..."); + break; + default: + Log.e(TAG, "LocalOnlyHotspotCallbackProxy unhandled message. type: " + + msg.what); + } + } + }; + mMessenger = new Messenger(mHandler); + } + + public Messenger getMessenger() { + return mMessenger; + } + + /** + * Helper method allowing the the incoming application call to move the onFailed callback + * over to the desired callback thread. + * + * @param reason int representing the error type + */ + public void notifyFailed(int reason) throws RemoteException { + Message msg = Message.obtain(); + msg.what = HOTSPOT_FAILED; + msg.arg1 = reason; + mMessenger.send(msg); + } + } + /** * LocalOnlyHotspotSubscription that is an AutoCloseable object for tracking applications * watching for LocalOnlyHotspot changes. From 54a540c04ace6b3f9c02adb3517f44970538eb15 Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Wed, 26 Apr 2017 22:02:30 -0700 Subject: [PATCH 2/5] WifiManager: add LocalOnlyHotspotObserverProxy Add the proxy for LOHS observer callbacks to make sure we give updates to calling apps on the correct thread. This will be used in a follow-on CL. Bug: 36704763 Test: mmma -j64 frameworks/base/ Change-Id: I20faa73325116426f45d9d8fabc45b279bd5a286 --- wifi/java/android/net/wifi/WifiManager.java | 69 +++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index f806f1c748506..6f1324e953058 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2436,6 +2436,75 @@ public class WifiManager { public void onStopped() {}; } + /** + * Callback proxy for LocalOnlyHotspotObserver objects. + */ + private static class LocalOnlyHotspotObserverProxy { + private final Handler mHandler; + private final WeakReference mWifiManager; + private final Looper mLooper; + private final Messenger mMessenger; + + /** + * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper. + * All callbacks will be delivered on the thread of the specified looper. + * + * @param manager WifiManager + * @param looper Looper for delivering callbacks + * @param observer LocalOnlyHotspotObserver to notify the calling application. + */ + LocalOnlyHotspotObserverProxy(WifiManager manager, Looper looper, + final LocalOnlyHotspotObserver observer) { + mWifiManager = new WeakReference<>(manager); + mLooper = looper; + + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + Log.d(TAG, "LocalOnlyHotspotObserverProxy: handle message what: " + + msg.what + " msg: " + msg); + + WifiManager manager = mWifiManager.get(); + if (manager == null) { + Log.w(TAG, "LocalOnlyHotspotObserverProxy: handle message post GC"); + return; + } + + switch (msg.what) { + case HOTSPOT_OBSERVER_REGISTERED: + observer.onRegistered(manager.new LocalOnlyHotspotSubscription()); + break; + case HOTSPOT_STARTED: + WifiConfiguration config = (WifiConfiguration) msg.obj; + if (config == null) { + Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null."); + return; + } + observer.onStarted(config); + break; + case HOTSPOT_STOPPED: + observer.onStopped(); + break; + default: + Log.e(TAG, "LocalOnlyHotspotObserverProxy unhandled message. type: " + + msg.what); + } + } + }; + mMessenger = new Messenger(mHandler); + } + + public Messenger getMessenger() { + return mMessenger; + } + + public void registered() throws RemoteException { + Message msg = Message.obtain(); + msg.what = HOTSPOT_OBSERVER_REGISTERED; + mMessenger.send(msg); + } + } + // Ensure that multiple ServiceHandler threads do not interleave message dispatch. private static final Object sServiceHandlerDispatchLock = new Object(); From ce74fc29b0247443199671d89d6bda58bb399a13 Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Sat, 25 Mar 2017 12:40:29 -0700 Subject: [PATCH 3/5] WifiManager: implement start/stopLocalOnlyHotspot Implement new calls to startLocalOnlyHotspot and cancelLocalOnlyHotspotRequest along with the classes LocalOnlyHotspotCallback and LocalOnlyHotspotReservation. Added tests for starting LOHS and cancelling a LOHS request. 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: If54a89cb8dfd235bc18ef3e6c89f9d30882136a3 --- wifi/java/android/net/wifi/WifiManager.java | 43 +- .../src/android/net/wifi/WifiManagerTest.java | 582 ++++++++++++++++++ 2 files changed, 622 insertions(+), 3 deletions(-) create mode 100644 wifi/tests/src/android/net/wifi/WifiManagerTest.java diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 6f1324e953058..f3e549364776d 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 0000000000000..75cd09530b5d3 --- /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 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(); + } +} From 4871da6b0715bf09b14fb593cfe112733d0c53ef Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Thu, 27 Apr 2017 13:57:19 -0700 Subject: [PATCH 4/5] 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 f3e549364776d..8fbf4721a20e0 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 75cd09530b5d3..3c0fc6ef0aa8b 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(); } } @@ -324,15 +329,6 @@ public class WifiManagerTest { 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. */ @@ -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(); + } + } From ec18f81e5b8bc4e4486b00f37e68cff4ff9131eb Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Fri, 28 Apr 2017 13:28:12 -0700 Subject: [PATCH 5/5] WifiManager: expose Local Only Hotspot APIs Expose the APIs to start and stop LocalOnlyHotspot. Bug: 31466854 Bug: 37073685 Test: make update-api Test: make Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh Test: frameworks/base/wifi/tests/runtests.sh Change-Id: I8d149ab04d24bf0eb54dd8d8a62e285f9c5b483e --- api/current.txt | 16 ++++++++++++++++ api/system-current.txt | 16 ++++++++++++++++ api/test-current.txt | 16 ++++++++++++++++ wifi/java/android/net/wifi/WifiManager.java | 7 ------- 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/api/current.txt b/api/current.txt index c8bfa47335c6b..3695a4295cfc9 100644 --- a/api/current.txt +++ b/api/current.txt @@ -26552,6 +26552,7 @@ package android.net.wifi { method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); method public boolean setWifiEnabled(boolean); + method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler); method public boolean startScan(); method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback); method public int updateNetwork(android.net.wifi.WifiConfiguration); @@ -26602,6 +26603,21 @@ package android.net.wifi { field public static final int WPS_WEP_PROHIBITED = 4; // 0x4 } + public static class WifiManager.LocalOnlyHotspotCallback { + ctor public WifiManager.LocalOnlyHotspotCallback(); + method public void onFailed(int); + method public void onStarted(android.net.wifi.WifiManager.LocalOnlyHotspotReservation); + method public void onStopped(); + field public static final int ERROR_GENERIC = 2; // 0x2 + field public static final int ERROR_INCOMPATIBLE_MODE = 3; // 0x3 + field public static final int ERROR_NO_CHANNEL = 1; // 0x1 + } + + public class WifiManager.LocalOnlyHotspotReservation implements java.lang.AutoCloseable { + method public void close(); + method public android.net.wifi.WifiConfiguration getConfig(); + } + public class WifiManager.MulticastLock { method public void acquire(); method public boolean isHeld(); diff --git a/api/system-current.txt b/api/system-current.txt index 1696bfa308d34..5dec7df1d7d5e 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -29132,6 +29132,7 @@ package android.net.wifi { method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration); method public boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean); method public boolean setWifiEnabled(boolean); + method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler); method public deprecated boolean startLocationRestrictedScan(android.os.WorkSource); method public boolean startScan(); method public boolean startScan(android.os.WorkSource); @@ -29209,6 +29210,21 @@ package android.net.wifi { method public abstract void onSuccess(); } + public static class WifiManager.LocalOnlyHotspotCallback { + ctor public WifiManager.LocalOnlyHotspotCallback(); + method public void onFailed(int); + method public void onStarted(android.net.wifi.WifiManager.LocalOnlyHotspotReservation); + method public void onStopped(); + field public static final int ERROR_GENERIC = 2; // 0x2 + field public static final int ERROR_INCOMPATIBLE_MODE = 3; // 0x3 + field public static final int ERROR_NO_CHANNEL = 1; // 0x1 + } + + public class WifiManager.LocalOnlyHotspotReservation implements java.lang.AutoCloseable { + method public void close(); + method public android.net.wifi.WifiConfiguration getConfig(); + } + public class WifiManager.MulticastLock { method public void acquire(); method public boolean isHeld(); diff --git a/api/test-current.txt b/api/test-current.txt index a97f165929349..8018f7c9a6328 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -26660,6 +26660,7 @@ package android.net.wifi { method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); method public boolean setWifiEnabled(boolean); + method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler); method public boolean startScan(); method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback); method public int updateNetwork(android.net.wifi.WifiConfiguration); @@ -26710,6 +26711,21 @@ package android.net.wifi { field public static final int WPS_WEP_PROHIBITED = 4; // 0x4 } + public static class WifiManager.LocalOnlyHotspotCallback { + ctor public WifiManager.LocalOnlyHotspotCallback(); + method public void onFailed(int); + method public void onStarted(android.net.wifi.WifiManager.LocalOnlyHotspotReservation); + method public void onStopped(); + field public static final int ERROR_GENERIC = 2; // 0x2 + field public static final int ERROR_INCOMPATIBLE_MODE = 3; // 0x3 + field public static final int ERROR_NO_CHANNEL = 1; // 0x1 + } + + public class WifiManager.LocalOnlyHotspotReservation implements java.lang.AutoCloseable { + method public void close(); + method public android.net.wifi.WifiConfiguration getConfig(); + } + public class WifiManager.MulticastLock { method public void acquire(); method public boolean isHeld(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 8fbf4721a20e0..0e1eb15ca9e5d 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1882,8 +1882,6 @@ public class WifiManager { * operating status. * @param handler Handler to be used for callbacks. If the caller passes a null Handler, the * main thread will be used. - * - * @hide */ public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback, @Nullable Handler handler) { @@ -2274,8 +2272,6 @@ public class WifiManager { * any further callbacks. If the LocalOnlyHotspot is stopped due to a * user triggered mode change, applications will be notified via the {@link * LocalOnlyHotspotCallback#onStopped()} callback. - * - * @hide */ public class LocalOnlyHotspotReservation implements AutoCloseable { @@ -2318,8 +2314,6 @@ public class WifiManager { /** * Callback class for applications to receive updates about the LocalOnlyHotspot status. - * - * @hide */ public static class LocalOnlyHotspotCallback { public static final int ERROR_NO_CHANNEL = 1; @@ -2442,7 +2436,6 @@ public class WifiManager { public class LocalOnlyHotspotSubscription implements AutoCloseable { private final CloseGuard mCloseGuard = CloseGuard.get(); - /** @hide */ @VisibleForTesting public LocalOnlyHotspotSubscription() { mCloseGuard.open("close");