Merge "Expose additional WifiScanner @SystemApis"
This commit is contained in:
commit
2a095b1fdc
@ -5580,6 +5580,7 @@ package android.net.wifi {
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<java.lang.Integer> getAvailableChannels(int);
|
||||
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults();
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.net.wifi.ScanResult> getSingleScanResults();
|
||||
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void registerScanListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiScanner.ScanListener);
|
||||
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setScanningEnabled(boolean);
|
||||
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
|
||||
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
|
||||
@ -5591,6 +5592,7 @@ package android.net.wifi {
|
||||
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopScan(android.net.wifi.WifiScanner.ScanListener);
|
||||
method @Deprecated public void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
|
||||
method @Deprecated public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
|
||||
method public void unregisterScanListener(@NonNull android.net.wifi.WifiScanner.ScanListener);
|
||||
field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
|
||||
field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
|
||||
field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
|
||||
@ -5603,6 +5605,9 @@ package android.net.wifi {
|
||||
field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
|
||||
field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
|
||||
field public static final int REPORT_EVENT_NO_BATCH = 4; // 0x4
|
||||
field public static final int SCAN_TYPE_HIGH_ACCURACY = 2; // 0x2
|
||||
field public static final int SCAN_TYPE_LOW_LATENCY = 0; // 0x0
|
||||
field public static final int SCAN_TYPE_LOW_POWER = 1; // 0x1
|
||||
field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
|
||||
field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
|
||||
field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
|
||||
@ -5671,6 +5676,7 @@ package android.net.wifi {
|
||||
ctor public WifiScanner.ScanSettings();
|
||||
field public int band;
|
||||
field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
|
||||
field @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public final java.util.List<android.net.wifi.WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks;
|
||||
field public boolean hideFromAppOps;
|
||||
field public boolean ignoreLocationSettings;
|
||||
field public int maxPeriodInMs;
|
||||
@ -5679,6 +5685,12 @@ package android.net.wifi {
|
||||
field public int periodInMs;
|
||||
field public int reportEvents;
|
||||
field public int stepCount;
|
||||
field @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public int type;
|
||||
}
|
||||
|
||||
public static class WifiScanner.ScanSettings.HiddenNetwork {
|
||||
ctor public WifiScanner.ScanSettings.HiddenNetwork(@NonNull String);
|
||||
field @NonNull public final String ssid;
|
||||
}
|
||||
|
||||
@Deprecated public static interface WifiScanner.WifiChangeListener extends android.net.wifi.WifiScanner.ActionListener {
|
||||
|
@ -65,7 +65,7 @@ MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent
|
||||
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #1:
|
||||
|
||||
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #2:
|
||||
|
||||
|
||||
MissingNullability: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
|
||||
|
||||
MissingNullability: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context) parameter #0:
|
||||
@ -181,6 +181,8 @@ MutableBareField: android.net.wifi.WifiConfiguration#saePasswordId:
|
||||
Bare field saePasswordId must be marked final, or moved behind accessors if mutable
|
||||
MutableBareField: android.net.wifi.WifiConfiguration#shared:
|
||||
Bare field shared must be marked final, or moved behind accessors if mutable
|
||||
MutableBareField: android.net.wifi.WifiScanner.ScanSettings#type:
|
||||
Bare field type must be marked final, or moved behind accessors if mutable
|
||||
|
||||
|
||||
NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
|
||||
|
29
wifi/java/android/net/wifi/SynchronousExecutor.java
Normal file
29
wifi/java/android/net/wifi/SynchronousExecutor.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* An executor implementation that runs synchronously on the current thread.
|
||||
* @hide
|
||||
*/
|
||||
public class SynchronousExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(Runnable r) {
|
||||
r.run();
|
||||
}
|
||||
}
|
@ -17,13 +17,16 @@
|
||||
package android.net.wifi;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@ -45,6 +48,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* This class provides a way to scan the Wifi universe around the device
|
||||
@ -196,24 +200,29 @@ public class WifiScanner {
|
||||
*/
|
||||
public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = {"SCAN_TYPE_"}, value = {
|
||||
SCAN_TYPE_LOW_LATENCY,
|
||||
SCAN_TYPE_LOW_POWER,
|
||||
SCAN_TYPE_HIGH_ACCURACY})
|
||||
public @interface ScanType {}
|
||||
|
||||
/**
|
||||
* This is used to indicate the purpose of the scan to the wifi chip in
|
||||
* {@link ScanSettings#type}.
|
||||
* On devices with multiple hardware radio chains (and hence different modes of scan),
|
||||
* this type serves as an indication to the hardware on what mode of scan to perform.
|
||||
* Only apps holding android.Manifest.permission.NETWORK_STACK permission can set this value.
|
||||
*
|
||||
* Note: This serves as an intent and not as a stipulation, the wifi chip
|
||||
* might honor or ignore the indication based on the current radio conditions. Always
|
||||
* use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration used
|
||||
* to receive the corresponding scan result.
|
||||
* Optimize the scan for lower latency.
|
||||
* @see ScanSettings#type
|
||||
*/
|
||||
/** {@hide} */
|
||||
public static final int TYPE_LOW_LATENCY = 0;
|
||||
/** {@hide} */
|
||||
public static final int TYPE_LOW_POWER = 1;
|
||||
/** {@hide} */
|
||||
public static final int TYPE_HIGH_ACCURACY = 2;
|
||||
public static final int SCAN_TYPE_LOW_LATENCY = 0;
|
||||
/**
|
||||
* Optimize the scan for lower power usage.
|
||||
* @see ScanSettings#type
|
||||
*/
|
||||
public static final int SCAN_TYPE_LOW_POWER = 1;
|
||||
/**
|
||||
* Optimize the scan for higher accuracy.
|
||||
* @see ScanSettings#type
|
||||
*/
|
||||
public static final int SCAN_TYPE_HIGH_ACCURACY = 2;
|
||||
|
||||
/** {@hide} */
|
||||
public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
|
||||
@ -228,18 +237,14 @@ public class WifiScanner {
|
||||
* scan configuration parameters to be sent to {@link #startBackgroundScan}
|
||||
*/
|
||||
public static class ScanSettings implements Parcelable {
|
||||
/**
|
||||
* Hidden network to be scanned for.
|
||||
* {@hide}
|
||||
*/
|
||||
/** Hidden network to be scanned for. */
|
||||
public static class HiddenNetwork {
|
||||
/** SSID of the network */
|
||||
public String ssid;
|
||||
@NonNull
|
||||
public final String ssid;
|
||||
|
||||
/**
|
||||
* Default constructor for HiddenNetwork.
|
||||
*/
|
||||
public HiddenNetwork(String ssid) {
|
||||
/** Default constructor for HiddenNetwork. */
|
||||
public HiddenNetwork(@NonNull String ssid) {
|
||||
this.ssid = ssid;
|
||||
}
|
||||
}
|
||||
@ -249,12 +254,12 @@ public class WifiScanner {
|
||||
/** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
|
||||
public ChannelSpec[] channels;
|
||||
/**
|
||||
* list of hidden networks to scan for. Explicit probe requests are sent out for such
|
||||
* List of hidden networks to scan for. Explicit probe requests are sent out for such
|
||||
* networks during scan. Only valid for single scan requests.
|
||||
* {@hide}
|
||||
*/
|
||||
@NonNull
|
||||
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
|
||||
public HiddenNetwork[] hiddenNetworks;
|
||||
public final List<HiddenNetwork> hiddenNetworks = new ArrayList<>();
|
||||
/** period of background scan; in millisecond, 0 => single shot scan */
|
||||
public int periodInMs;
|
||||
/** must have a valid REPORT_EVENT value */
|
||||
@ -285,11 +290,24 @@ public class WifiScanner {
|
||||
public boolean isPnoScan;
|
||||
/**
|
||||
* Indicate the type of scan to be performed by the wifi chip.
|
||||
* Default value: {@link #TYPE_LOW_LATENCY}.
|
||||
* {@hide}
|
||||
*
|
||||
* On devices with multiple hardware radio chains (and hence different modes of scan),
|
||||
* this type serves as an indication to the hardware on what mode of scan to perform.
|
||||
* Only apps holding {@link android.Manifest.permission.NETWORK_STACK} permission can set
|
||||
* this value.
|
||||
*
|
||||
* Note: This serves as an intent and not as a stipulation, the wifi chip
|
||||
* might honor or ignore the indication based on the current radio conditions. Always
|
||||
* use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration
|
||||
* used to receive the corresponding scan result.
|
||||
*
|
||||
* One of {@link #SCAN_TYPE_LOW_LATENCY}, {@link #SCAN_TYPE_LOW_POWER},
|
||||
* {@link #SCAN_TYPE_HIGH_ACCURACY}.
|
||||
* Default value: {@link #SCAN_TYPE_LOW_LATENCY}.
|
||||
*/
|
||||
@ScanType
|
||||
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
|
||||
public int type = TYPE_LOW_LATENCY;
|
||||
public int type = SCAN_TYPE_LOW_LATENCY;
|
||||
/**
|
||||
* This scan request may ignore location settings while receiving scans. This should only
|
||||
* be used in emergency situations.
|
||||
@ -336,13 +354,9 @@ public class WifiScanner {
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
if (hiddenNetworks != null) {
|
||||
dest.writeInt(hiddenNetworks.length);
|
||||
for (int i = 0; i < hiddenNetworks.length; i++) {
|
||||
dest.writeString(hiddenNetworks[i].ssid);
|
||||
}
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
dest.writeInt(hiddenNetworks.size());
|
||||
for (HiddenNetwork hiddenNetwork : hiddenNetworks) {
|
||||
dest.writeString(hiddenNetwork.ssid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -372,10 +386,10 @@ public class WifiScanner {
|
||||
settings.channels[i] = spec;
|
||||
}
|
||||
int numNetworks = in.readInt();
|
||||
settings.hiddenNetworks = new HiddenNetwork[numNetworks];
|
||||
settings.hiddenNetworks.clear();
|
||||
for (int i = 0; i < numNetworks; i++) {
|
||||
String ssid = in.readString();
|
||||
settings.hiddenNetworks[i] = new HiddenNetwork(ssid);;
|
||||
settings.hiddenNetworks.add(new HiddenNetwork(ssid));
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
@ -801,33 +815,44 @@ public class WifiScanner {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a listener that will receive results from all single scans
|
||||
* Either the onSuccess/onFailure will be called once when the listener is registered. After
|
||||
* (assuming onSuccess was called) all subsequent single scan results will be delivered to the
|
||||
* listener. It is possible that onFullResult will not be called for all results of the first
|
||||
* scan if the listener was registered during the scan.
|
||||
* Register a listener that will receive results from all single scans.
|
||||
* Either the {@link ScanListener#onSuccess()} or {@link ScanListener#onFailure(int, String)}
|
||||
* method will be called once when the listener is registered.
|
||||
* Afterwards (assuming onSuccess was called), all subsequent single scan results will be
|
||||
* delivered to the listener. It is possible that onFullResult will not be called for all
|
||||
* results of the first scan if the listener was registered during the scan.
|
||||
*
|
||||
* @param listener specifies the object to report events to. This object is also treated as a
|
||||
* key for this request, and must also be specified to cancel the request.
|
||||
* Multiple requests should also not share this object.
|
||||
* {@hide}
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.NETWORK_STACK)
|
||||
public void registerScanListener(ScanListener listener) {
|
||||
public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull ScanListener listener) {
|
||||
Preconditions.checkNotNull(executor, "executor cannot be null");
|
||||
Preconditions.checkNotNull(listener, "listener cannot be null");
|
||||
int key = addListener(listener);
|
||||
int key = addListener(listener, executor);
|
||||
if (key == INVALID_KEY) return;
|
||||
validateChannel();
|
||||
mAsyncChannel.sendMessage(CMD_REGISTER_SCAN_LISTENER, 0, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload of {@link #registerScanListener(Executor, ScanListener)} that executes the callback
|
||||
* synchronously.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.NETWORK_STACK)
|
||||
public void registerScanListener(@NonNull ScanListener listener) {
|
||||
registerScanListener(new SynchronousExecutor(), listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregister a listener for ongoing single scans
|
||||
* @param listener specifies which scan to cancel; must be same object as passed in {@link
|
||||
* #registerScanListener}
|
||||
* {@hide}
|
||||
*/
|
||||
public void deregisterScanListener(ScanListener listener) {
|
||||
public void unregisterScanListener(@NonNull ScanListener listener) {
|
||||
Preconditions.checkNotNull(listener, "listener cannot be null");
|
||||
int key = removeListener(listener);
|
||||
if (key == INVALID_KEY) return;
|
||||
@ -1280,6 +1305,7 @@ public class WifiScanner {
|
||||
private int mListenerKey = 1;
|
||||
|
||||
private final SparseArray mListenerMap = new SparseArray();
|
||||
private final SparseArray<Executor> mExecutorMap = new SparseArray<>();
|
||||
private final Object mListenerMapLock = new Object();
|
||||
|
||||
private AsyncChannel mAsyncChannel;
|
||||
@ -1327,10 +1353,14 @@ public class WifiScanner {
|
||||
"No permission to access and change wifi or a bad initialization");
|
||||
}
|
||||
|
||||
private int addListener(ActionListener listener) {
|
||||
return addListener(listener, null);
|
||||
}
|
||||
|
||||
// Add a listener into listener map. If the listener already exists, return INVALID_KEY and
|
||||
// send an error message to internal handler; Otherwise add the listener to the listener map and
|
||||
// return the key of the listener.
|
||||
private int addListener(ActionListener listener) {
|
||||
private int addListener(ActionListener listener, Executor executor) {
|
||||
synchronized (mListenerMapLock) {
|
||||
boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
|
||||
// Note we need to put the listener into listener map even if it's a duplicate as the
|
||||
@ -1346,6 +1376,7 @@ public class WifiScanner {
|
||||
message.sendToTarget();
|
||||
return INVALID_KEY;
|
||||
} else {
|
||||
mExecutorMap.put(key, executor);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@ -1363,11 +1394,22 @@ public class WifiScanner {
|
||||
return key;
|
||||
}
|
||||
|
||||
private Object getListener(int key) {
|
||||
if (key == INVALID_KEY) return null;
|
||||
private static class ListenerWithExecutor {
|
||||
@Nullable final Object mListener;
|
||||
@Nullable final Executor mExecutor;
|
||||
|
||||
ListenerWithExecutor(@Nullable Object listener, @Nullable Executor executor) {
|
||||
mListener = listener;
|
||||
mExecutor = executor;
|
||||
}
|
||||
}
|
||||
|
||||
private ListenerWithExecutor getListenerWithExecutor(int key) {
|
||||
if (key == INVALID_KEY) return new ListenerWithExecutor(null, null);
|
||||
synchronized (mListenerMapLock) {
|
||||
Object listener = mListenerMap.get(key);
|
||||
return listener;
|
||||
Executor executor = mExecutorMap.get(key);
|
||||
return new ListenerWithExecutor(listener, executor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1388,6 +1430,7 @@ public class WifiScanner {
|
||||
synchronized (mListenerMapLock) {
|
||||
Object listener = mListenerMap.get(key);
|
||||
mListenerMap.remove(key);
|
||||
mExecutorMap.remove(key);
|
||||
return listener;
|
||||
}
|
||||
}
|
||||
@ -1400,6 +1443,7 @@ public class WifiScanner {
|
||||
}
|
||||
synchronized (mListenerMapLock) {
|
||||
mListenerMap.remove(key);
|
||||
mExecutorMap.remove(key);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@ -1458,7 +1502,8 @@ public class WifiScanner {
|
||||
return;
|
||||
}
|
||||
|
||||
Object listener = getListener(msg.arg2);
|
||||
ListenerWithExecutor listenerWithExecutor = getListenerWithExecutor(msg.arg2);
|
||||
Object listener = listenerWithExecutor.mListener;
|
||||
|
||||
if (listener == null) {
|
||||
if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
|
||||
@ -1467,36 +1512,52 @@ public class WifiScanner {
|
||||
if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
|
||||
}
|
||||
|
||||
Executor executor = listenerWithExecutor.mExecutor;
|
||||
if (executor == null) {
|
||||
executor = new SynchronousExecutor();
|
||||
}
|
||||
|
||||
switch (msg.what) {
|
||||
/* ActionListeners grouped together */
|
||||
case CMD_OP_SUCCEEDED :
|
||||
((ActionListener) listener).onSuccess();
|
||||
break;
|
||||
case CMD_OP_FAILED : {
|
||||
OperationResult result = (OperationResult)msg.obj;
|
||||
((ActionListener) listener).onFailure(result.reason, result.description);
|
||||
removeListener(msg.arg2);
|
||||
}
|
||||
break;
|
||||
case CMD_SCAN_RESULT :
|
||||
((ScanListener) listener).onResults(
|
||||
((ParcelableScanData) msg.obj).getResults());
|
||||
return;
|
||||
case CMD_FULL_SCAN_RESULT :
|
||||
/* ActionListeners grouped together */
|
||||
case CMD_OP_SUCCEEDED: {
|
||||
ActionListener actionListener = (ActionListener) listener;
|
||||
Binder.clearCallingIdentity();
|
||||
executor.execute(actionListener::onSuccess);
|
||||
} break;
|
||||
case CMD_OP_FAILED: {
|
||||
OperationResult result = (OperationResult) msg.obj;
|
||||
ActionListener actionListener = (ActionListener) listener;
|
||||
removeListener(msg.arg2);
|
||||
Binder.clearCallingIdentity();
|
||||
executor.execute(() ->
|
||||
actionListener.onFailure(result.reason, result.description));
|
||||
} break;
|
||||
case CMD_SCAN_RESULT: {
|
||||
ScanListener scanListener = (ScanListener) listener;
|
||||
ParcelableScanData parcelableScanData = (ParcelableScanData) msg.obj;
|
||||
Binder.clearCallingIdentity();
|
||||
executor.execute(() -> scanListener.onResults(parcelableScanData.getResults()));
|
||||
} break;
|
||||
case CMD_FULL_SCAN_RESULT: {
|
||||
ScanResult result = (ScanResult) msg.obj;
|
||||
((ScanListener) listener).onFullResult(result);
|
||||
return;
|
||||
case CMD_SINGLE_SCAN_COMPLETED:
|
||||
ScanListener scanListener = ((ScanListener) listener);
|
||||
Binder.clearCallingIdentity();
|
||||
executor.execute(() -> scanListener.onFullResult(result));
|
||||
} break;
|
||||
case CMD_SINGLE_SCAN_COMPLETED: {
|
||||
if (DBG) Log.d(TAG, "removing listener for single scan");
|
||||
removeListener(msg.arg2);
|
||||
break;
|
||||
case CMD_PNO_NETWORK_FOUND:
|
||||
((PnoScanListener) listener).onPnoNetworkFound(
|
||||
((ParcelableScanResults) msg.obj).getResults());
|
||||
return;
|
||||
default:
|
||||
} break;
|
||||
case CMD_PNO_NETWORK_FOUND: {
|
||||
PnoScanListener pnoScanListener = (PnoScanListener) listener;
|
||||
ParcelableScanResults parcelableScanResults = (ParcelableScanResults) msg.obj;
|
||||
Binder.clearCallingIdentity();
|
||||
executor.execute(() ->
|
||||
pnoScanListener.onPnoNetworkFound(parcelableScanResults.getResults()));
|
||||
} break;
|
||||
default: {
|
||||
if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
|
||||
return;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1436,15 +1436,6 @@ public class WifiManagerTest {
|
||||
eq((int) listenerIdentifier.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined for testing purpose.
|
||||
*/
|
||||
class SynchronousExecutor implements Executor {
|
||||
public void execute(Runnable r) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test behavior of isEnhancedOpenSupported
|
||||
*/
|
||||
|
@ -22,7 +22,9 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.validateMockitoUsage;
|
||||
@ -33,6 +35,7 @@ import android.content.Context;
|
||||
import android.net.wifi.WifiScanner.PnoSettings;
|
||||
import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork;
|
||||
import android.net.wifi.WifiScanner.ScanData;
|
||||
import android.net.wifi.WifiScanner.ScanListener;
|
||||
import android.net.wifi.WifiScanner.ScanSettings;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@ -51,8 +54,10 @@ import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link android.net.wifi.WifiScanner}.
|
||||
@ -63,6 +68,13 @@ public class WifiScannerTest {
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private IWifiScanner mService;
|
||||
@Spy
|
||||
private Executor mExecutor = new SynchronousExecutor();
|
||||
@Mock
|
||||
private ScanListener mScanListener;
|
||||
@Mock
|
||||
private WifiScanner.ParcelableScanData mParcelableScanData;
|
||||
private ScanData[] mScanData = {};
|
||||
|
||||
private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false;
|
||||
private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60;
|
||||
@ -76,6 +88,7 @@ public class WifiScannerTest {
|
||||
private static final String TEST_SSID_2 = "TEST2";
|
||||
private static final int[] TEST_FREQUENCIES_1 = {};
|
||||
private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
|
||||
private static final String DESCRIPTION_NOT_AUTHORIZED = "Not authorized";
|
||||
|
||||
private WifiScanner mWifiScanner;
|
||||
private TestLooper mLooper;
|
||||
@ -95,6 +108,7 @@ public class WifiScannerTest {
|
||||
when(mService.getMessenger()).thenReturn(mBidirectionalAsyncChannelServer.getMessenger());
|
||||
mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
|
||||
mLooper.dispatchAll();
|
||||
when(mParcelableScanData.getResults()).thenReturn(mScanData);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,7 +125,7 @@ public class WifiScannerTest {
|
||||
@Test
|
||||
public void verifyScanSettingsParcelWithBand() throws Exception {
|
||||
ScanSettings writeSettings = new ScanSettings();
|
||||
writeSettings.type = WifiScanner.TYPE_LOW_POWER;
|
||||
writeSettings.type = WifiScanner.SCAN_TYPE_LOW_POWER;
|
||||
writeSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
|
||||
|
||||
ScanSettings readSettings = parcelWriteRead(writeSettings);
|
||||
@ -126,7 +140,7 @@ public class WifiScannerTest {
|
||||
@Test
|
||||
public void verifyScanSettingsParcelWithChannels() throws Exception {
|
||||
ScanSettings writeSettings = new ScanSettings();
|
||||
writeSettings.type = WifiScanner.TYPE_HIGH_ACCURACY;
|
||||
writeSettings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY;
|
||||
writeSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
|
||||
writeSettings.channels = new WifiScanner.ChannelSpec[] {
|
||||
new WifiScanner.ChannelSpec(5),
|
||||
@ -243,13 +257,13 @@ public class WifiScannerTest {
|
||||
|
||||
|
||||
/**
|
||||
* Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
|
||||
* Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testStartScan() throws Exception {
|
||||
ScanSettings scanSettings = new ScanSettings();
|
||||
WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
|
||||
ScanListener scanListener = mock(ScanListener.class);
|
||||
|
||||
mWifiScanner.startScan(scanSettings, scanListener);
|
||||
mLooper.dispatchAll();
|
||||
@ -273,13 +287,13 @@ public class WifiScannerTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test behavior of {@link WifiScanner#stopScan(WifiScanner.ScanListener)}
|
||||
* Test behavior of {@link WifiScanner#stopScan(ScanListener)}
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testStopScan() throws Exception {
|
||||
ScanSettings scanSettings = new ScanSettings();
|
||||
WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
|
||||
ScanListener scanListener = mock(ScanListener.class);
|
||||
|
||||
mWifiScanner.startScan(scanSettings, scanListener);
|
||||
mLooper.dispatchAll();
|
||||
@ -302,13 +316,13 @@ public class WifiScannerTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
|
||||
* Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testStartScanListenerOnSuccess() throws Exception {
|
||||
ScanSettings scanSettings = new ScanSettings();
|
||||
WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
|
||||
ScanListener scanListener = mock(ScanListener.class);
|
||||
|
||||
mWifiScanner.startScan(scanSettings, scanListener);
|
||||
mLooper.dispatchAll();
|
||||
@ -332,13 +346,13 @@ public class WifiScannerTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
|
||||
* Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testStartScanListenerOnResults() throws Exception {
|
||||
ScanSettings scanSettings = new ScanSettings();
|
||||
WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
|
||||
ScanListener scanListener = mock(ScanListener.class);
|
||||
|
||||
mWifiScanner.startScan(scanSettings, scanListener);
|
||||
mLooper.dispatchAll();
|
||||
@ -425,7 +439,7 @@ public class WifiScannerTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test behavior of {@link WifiScanner#stopPnoScan(WifiScanner.ScanListener)}
|
||||
* Test behavior of {@link WifiScanner#stopPnoScan(ScanListener)}
|
||||
* WifiScanner.PnoScanListener)}
|
||||
* @throws Exception
|
||||
*/
|
||||
@ -480,4 +494,134 @@ public class WifiScannerTest {
|
||||
assertEquals(scanData.getResults().length, readScanData.getResults().length);
|
||||
assertEquals(scanData.getResults()[0].SSID, readScanData.getResults()[0].SSID);
|
||||
}
|
||||
|
||||
/** Tests that upon registration success, {@link ScanListener#onSuccess()} is called. */
|
||||
@Test
|
||||
public void testRegisterScanListenerSuccess() throws Exception {
|
||||
mWifiScanner.registerScanListener(mExecutor, mScanListener);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(mHandler).handleMessage(messageArgumentCaptor.capture());
|
||||
Message sentMessage = messageArgumentCaptor.getValue();
|
||||
assertNotNull(sentMessage);
|
||||
|
||||
assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
|
||||
Messenger scannerMessenger =
|
||||
mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
|
||||
|
||||
Message responseMessage = Message.obtain();
|
||||
responseMessage.what = WifiScanner.CMD_OP_SUCCEEDED;
|
||||
responseMessage.arg2 = sentMessage.arg2;
|
||||
scannerMessenger.send(responseMessage);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mExecutor).execute(any());
|
||||
verify(mScanListener).onSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that upon registration failed, {@link ScanListener#onFailure(int, String)} is called.
|
||||
*/
|
||||
@Test
|
||||
public void testRegisterScanListenerFailed() throws Exception {
|
||||
mWifiScanner.registerScanListener(mExecutor, mScanListener);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(mHandler).handleMessage(messageArgumentCaptor.capture());
|
||||
Message sentMessage = messageArgumentCaptor.getValue();
|
||||
assertNotNull(sentMessage);
|
||||
|
||||
assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
|
||||
Messenger scannerMessenger =
|
||||
mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
|
||||
|
||||
{
|
||||
Message responseMessage = Message.obtain();
|
||||
responseMessage.what = WifiScanner.CMD_OP_FAILED;
|
||||
responseMessage.arg2 = sentMessage.arg2;
|
||||
responseMessage.obj = new WifiScanner.OperationResult(
|
||||
WifiScanner.REASON_NOT_AUTHORIZED, DESCRIPTION_NOT_AUTHORIZED);
|
||||
scannerMessenger.send(responseMessage);
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
|
||||
verify(mExecutor).execute(any());
|
||||
verify(mScanListener).onFailure(
|
||||
WifiScanner.REASON_NOT_AUTHORIZED, DESCRIPTION_NOT_AUTHORIZED);
|
||||
|
||||
// CMD_OP_FAILED should have caused the removal of the listener, verify this
|
||||
{
|
||||
Message responseMessage = Message.obtain();
|
||||
responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
|
||||
responseMessage.arg2 = sentMessage.arg2;
|
||||
responseMessage.obj = mParcelableScanData;
|
||||
scannerMessenger.send(responseMessage);
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
// execute() called once before, not called again
|
||||
verify(mExecutor, times(1)).execute(any());
|
||||
// onResults() never triggered
|
||||
verify(mScanListener, never()).onResults(any());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when the ScanListener is triggered, {@link ScanListener#onResults(ScanData[])}
|
||||
* is called.
|
||||
*/
|
||||
@Test
|
||||
public void testRegisterScanListenerReceiveScanResults() throws Exception {
|
||||
mWifiScanner.registerScanListener(mExecutor, mScanListener);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(mHandler).handleMessage(messageArgumentCaptor.capture());
|
||||
Message sentMessage = messageArgumentCaptor.getValue();
|
||||
assertNotNull(sentMessage);
|
||||
|
||||
assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
|
||||
Messenger scannerMessenger =
|
||||
mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
|
||||
|
||||
Message responseMessage = Message.obtain();
|
||||
responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
|
||||
responseMessage.arg2 = sentMessage.arg2;
|
||||
responseMessage.obj = mParcelableScanData;
|
||||
scannerMessenger.send(responseMessage);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mExecutor).execute(any());
|
||||
verify(mScanListener).onResults(mScanData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that after unregistering a scan listener, {@link ScanListener#onResults(ScanData[])}
|
||||
* is not called.
|
||||
*/
|
||||
@Test
|
||||
public void testUnregisterScanListener() throws Exception {
|
||||
mWifiScanner.registerScanListener(mExecutor, mScanListener);
|
||||
mWifiScanner.unregisterScanListener(mScanListener);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
|
||||
Messenger scannerMessenger =
|
||||
mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
|
||||
|
||||
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(mHandler, times(2)).handleMessage(messageArgumentCaptor.capture());
|
||||
Message sentMessage = messageArgumentCaptor.getValue();
|
||||
assertNotNull(sentMessage);
|
||||
|
||||
Message responseMessage = Message.obtain();
|
||||
responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
|
||||
responseMessage.obj = mParcelableScanData;
|
||||
responseMessage.arg2 = sentMessage.arg2;
|
||||
scannerMessenger.send(responseMessage);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mExecutor, never()).execute(any());
|
||||
verify(mScanListener, never()).onResults(mScanData);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user