Merge "Expose additional WifiScanner @SystemApis"

This commit is contained in:
David Su 2019-11-29 03:27:22 +00:00 committed by Android (Google) Code Review
commit 2a095b1fdc
6 changed files with 340 additions and 101 deletions

View File

@ -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 {

View File

@ -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:

View 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();
}
}

View File

@ -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;
}
}
}

View File

@ -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
*/

View File

@ -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);
}
}