diff options
| author | 2019-10-09 16:47:39 -0700 | |
|---|---|---|
| committer | 2019-10-17 15:48:06 -0700 | |
| commit | ee434e819482cc48baec1b3fa3bcd11f26434e10 (patch) | |
| tree | 197fa18ce5078d60259cda52182bbcfcf9beb717 | |
| parent | 1e3af3199097532d1f7178b948fb208db057e59c (diff) | |
[WifiManager] add public API to register callback on scan result
Bug: 142680108
Test: atest android.net.wifi
Test: atest com.android.server.wifi
Change-Id: I370a972c166242d31d21672c9d8023258664968a
| -rw-r--r-- | api/current.txt | 6 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/IScanResultsListener.aidl | 27 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/IWifiManager.aidl | 5 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/WifiManager.java | 86 | ||||
| -rw-r--r-- | wifi/java/com/android/server/wifi/BaseWifiService.java | 12 | ||||
| -rw-r--r-- | wifi/tests/src/android/net/wifi/WifiManagerTest.java | 68 |
6 files changed, 202 insertions, 2 deletions
diff --git a/api/current.txt b/api/current.txt index 677e8c2209c2..04c5220d59d2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -29936,6 +29936,7 @@ package android.net.wifi { method @Deprecated public int addNetwork(android.net.wifi.WifiConfiguration); method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int addNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>); method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration); + method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void addScanResultsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.ScanResultsListener); method public static int calculateSignalLevel(int, int); method @Deprecated public void cancelWps(android.net.wifi.WifiManager.WpsCallback); method public static int compareSignalLevel(int, int); @@ -29971,6 +29972,7 @@ package android.net.wifi { method @Deprecated public boolean removeNetwork(int); method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int removeNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>); method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_CARRIER_PROVISIONING"}) public void removePasspointConfiguration(String); + method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void removeScanResultsListener(@NonNull android.net.wifi.WifiManager.ScanResultsListener); method @Deprecated public boolean saveConfiguration(); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(String, boolean); @@ -30046,6 +30048,10 @@ package android.net.wifi { method public void setReferenceCounted(boolean); } + public static interface WifiManager.ScanResultsListener { + method public void onScanResultsAvailable(); + } + public class WifiManager.WifiLock { method public void acquire(); method public boolean isHeld(); diff --git a/wifi/java/android/net/wifi/IScanResultsListener.aidl b/wifi/java/android/net/wifi/IScanResultsListener.aidl new file mode 100644 index 000000000000..bec74a620380 --- /dev/null +++ b/wifi/java/android/net/wifi/IScanResultsListener.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 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; + +/** + * Interface for Wi-Fi scan result available callback. + * + * @hide + */ +oneway interface IScanResultsListener +{ + void onScanResultsAvailable(); +} diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index b7e109463dab..13377390fc04 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -28,6 +28,7 @@ import android.net.wifi.IActionListener; import android.net.wifi.IDppCallback; import android.net.wifi.ILocalOnlyHotspotCallback; import android.net.wifi.INetworkRequestMatchCallback; +import android.net.wifi.IScanResultsListener; import android.net.wifi.ISoftApCallback; import android.net.wifi.ITrafficStateCallback; import android.net.wifi.ITxPacketCountListener; @@ -227,4 +228,8 @@ interface IWifiManager oneway void forget(int netId, in IBinder binder, in IActionListener listener, int callbackIdentifier); oneway void getTxPacketCount(String packageName, in IBinder binder, in ITxPacketCountListener listener, int callbackIdentifier); + + void registerScanResultsListener(in IBinder binder, in IScanResultsListener Listener, int listenerIdentifier); + + void unregisterScanResultsListener(int listenerIdentifier); } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 5496e83811f8..dd9ee3b4d793 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -5104,4 +5104,90 @@ public class WifiManager { throw e.rethrowFromSystemServer(); } } + + /** + * Base class for scan results listener. Should be implemented by applications and set when + * calling {@link WifiManager#addScanResultsListener(Executor, ScanResultsListener)}. + */ + public interface ScanResultsListener { + + /** + * Called when new scan results available. + * Caller should use {@link WifiManager#getScanResults()} to get the scan results. + */ + void onScanResultsAvailable(); + } + + private class ScanResultsListenerProxy extends IScanResultsListener.Stub { + private final Executor mExecutor; + private final ScanResultsListener mListener; + + ScanResultsListenerProxy(Executor executor, ScanResultsListener listener) { + mExecutor = executor; + mListener = listener; + } + + @Override + public void onScanResultsAvailable() { + mExecutor.execute(mListener::onScanResultsAvailable); + } + } + + /** + * Add a listener for Scan Results. See {@link ScanResultsListener}. + * Caller will receive the event when scan results are available. + * Caller should use {@link WifiManager#getScanResults()} to get the scan results. + * Caller can remove a previously registered listener using + * {@link WifiManager#removeScanResultsListener(ScanResultsListener)} + * <p> + * Applications should have the + * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission. Callers + * without the permission will trigger a {@link java.lang.SecurityException}. + * <p> + * + * @param executor The executor to execute the listener of the {@code listener} object. + * @param listener listener for Scan Results events + */ + + @RequiresPermission(ACCESS_WIFI_STATE) + public void addScanResultsListener(@NonNull @CallbackExecutor Executor executor, + @NonNull ScanResultsListener listener) { + if (listener == null) throw new IllegalArgumentException("listener cannot be null"); + if (executor == null) throw new IllegalArgumentException("executor cannot be null"); + Log.v(TAG, "addScanResultsListener: listener=" + listener + ", executor=" + executor); + try { + IWifiManager iWifiManager = getIWifiManager(); + if (iWifiManager == null) { + throw new RemoteException("Wifi service is not running"); + } + iWifiManager.registerScanResultsListener( + new Binder(), + new ScanResultsListenerProxy(executor, listener), + mContext.getOpPackageName().hashCode()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Allow callers to remove a previously added listener. After calling this method, + * applications will no longer receive Scan Results events. + * + * @param listener listener to remove for Scan Results events + */ + @RequiresPermission(ACCESS_WIFI_STATE) + public void removeScanResultsListener(@NonNull ScanResultsListener listener) { + if (listener == null) throw new IllegalArgumentException("listener cannot be null"); + Log.v(TAG, "removeScanResultsListener: listener=" + listener); + + try { + IWifiManager iWifiManager = getIWifiManager(); + if (iWifiManager == null) { + throw new RemoteException("Wifi service is not running"); + } + iWifiManager.unregisterScanResultsListener(mContext.getOpPackageName().hashCode()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index 4ca2a16252d6..94fb5ae4d61c 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -26,6 +26,7 @@ import android.net.wifi.IDppCallback; import android.net.wifi.ILocalOnlyHotspotCallback; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.IOnWifiUsabilityStatsListener; +import android.net.wifi.IScanResultsListener; import android.net.wifi.ISoftApCallback; import android.net.wifi.ITrafficStateCallback; import android.net.wifi.ITxPacketCountListener; @@ -515,4 +516,15 @@ public class BaseWifiService extends IWifiManager.Stub { ITxPacketCountListener callback, int callbackIdentifier) { throw new UnsupportedOperationException(); } + + @Override + public void registerScanResultsListener( + IBinder binder, IScanResultsListener listener, int listenerIdentifier) { + throw new UnsupportedOperationException(); + } + + @Override + public void unregisterScanResultsListener(int listenerIdentifier) { + throw new UnsupportedOperationException(); + } } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 885139b99b5f..f8a0c8f5fab8 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -59,6 +59,7 @@ import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription; import android.net.wifi.WifiManager.NetworkRequestMatchCallback; import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback; import android.net.wifi.WifiManager.OnWifiUsabilityStatsListener; +import android.net.wifi.WifiManager.ScanResultsListener; import android.net.wifi.WifiManager.SoftApCallback; import android.net.wifi.WifiManager.TrafficStateCallback; import android.os.Binder; @@ -102,13 +103,14 @@ public class WifiManagerTest { android.net.wifi.IWifiManager mWifiService; @Mock ApplicationInfo mApplicationInfo; @Mock WifiConfiguration mApConfig; - @Mock IBinder mAppBinder; @Mock SoftApCallback mSoftApCallback; @Mock TrafficStateCallback mTrafficStateCallback; @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback; @Mock OnWifiUsabilityStatsListener mOnWifiUsabilityStatsListener; + @Mock ScanResultsListener mScanResultListener; + @Mock Executor mCallbackExecutor; + @Mock Executor mExecutor; - private Executor mExecutor; private Handler mHandler; private TestLooper mLooper; private WifiManager mWifiManager; @@ -1711,4 +1713,66 @@ i * Verify that a call to cancel WPS immediately returns a failure. mLooper.dispatchAll(); verify(externalListener).onFailure(WifiManager.BUSY); } + + /** + * Verify an IllegalArgumentException is thrown if listener is not provided. + */ + @Test(expected = IllegalArgumentException.class) + public void testAddScanResultsListenerWithNullListener() throws Exception { + mWifiManager.addScanResultsListener(mCallbackExecutor, null); + } + + /** + * Verify an IllegalArgumentException is thrown if executor is not provided. + */ + @Test(expected = IllegalArgumentException.class) + public void testAddScanResultsListenerWithNullExecutor() throws Exception { + mWifiManager.addScanResultsListener(null, mScanResultListener); + } + + /** + * Verify client provided listener is being called to the right listener. + */ + @Test + public void testAddScanResultsListenerAndReceiveEvent() throws Exception { + ArgumentCaptor<IScanResultsListener.Stub> callbackCaptor = + ArgumentCaptor.forClass(IScanResultsListener.Stub.class); + Executor executor = new SynchronousExecutor(); + mWifiManager.addScanResultsListener(executor, mScanResultListener); + verify(mWifiService).registerScanResultsListener(any(IBinder.class), + callbackCaptor.capture(), anyInt()); + callbackCaptor.getValue().onScanResultsAvailable(); + verify(mScanResultListener).onScanResultsAvailable(); + } + + /** + * Verify client provided listener is being called on the right executor. + */ + @Test + public void testAddScanResultsListenerWithTheTargetExecutor() throws Exception { + ArgumentCaptor<IScanResultsListener.Stub> callbackCaptor = + ArgumentCaptor.forClass(IScanResultsListener.Stub.class); + mWifiManager.addScanResultsListener(mExecutor, mScanResultListener); + verify(mWifiService).registerScanResultsListener(any(IBinder.class), + callbackCaptor.capture(), anyInt()); + callbackCaptor.getValue().onScanResultsAvailable(); + verify(mExecutor).execute(any(Runnable.class)); + } + + /** + * Verify client removeScanResultsListener. + */ + @Test + public void testRemoveScanResultsListener() throws Exception { + mWifiManager.removeScanResultsListener(mScanResultListener); + verify(mWifiService).unregisterScanResultsListener(anyInt()); + } + + /** + * Verify client removeScanResultsListener with null listener will cause an exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testRemoveScanResultsListenerWithNullListener() throws Exception { + mWifiManager.removeScanResultsListener(null); + } } |