summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nate(Qiang) Jiang <qiangjiang@google.com> 2019-10-09 16:47:39 -0700
committer Nate(Qiang) Jiang <qiangjiang@google.com> 2019-10-17 15:48:06 -0700
commitee434e819482cc48baec1b3fa3bcd11f26434e10 (patch)
tree197fa18ce5078d60259cda52182bbcfcf9beb717
parent1e3af3199097532d1f7178b948fb208db057e59c (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.txt6
-rw-r--r--wifi/java/android/net/wifi/IScanResultsListener.aidl27
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl5
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java86
-rw-r--r--wifi/java/com/android/server/wifi/BaseWifiService.java12
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java68
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);
+ }
}