Merge "Implemented network score cache filtering."
This commit is contained in:
committed by
Android (Google) Code Review
commit
482ebe9bad
@@ -16,10 +16,14 @@
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.net.wifi.ScanResult;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiSsid;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -64,6 +68,27 @@ public class NetworkKey implements Parcelable {
|
||||
'"' + result.wifiSsid.toString() + '"', result.BSSID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new NetworkKey for the given {@link WifiInfo}.
|
||||
*
|
||||
* @param wifiInfo the {@link WifiInfo} to create a {@link NetworkKey} for.
|
||||
* @return A new {@link NetworkKey} instance or <code>null</code> if the given {@link WifiInfo}
|
||||
* instance doesn't represent a connected WiFi network.
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public static NetworkKey createFromWifiInfo(@Nullable WifiInfo wifiInfo) {
|
||||
if (wifiInfo != null) {
|
||||
final String ssid = wifiInfo.getSSID();
|
||||
final String bssid = wifiInfo.getBSSID();
|
||||
if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
|
||||
&& !TextUtils.isEmpty(bssid)) {
|
||||
return new NetworkKey(new WifiKey(ssid, bssid));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@link NetworkKey} for a Wi-Fi network.
|
||||
* @param wifiKey the {@link WifiKey} identifying this Wi-Fi network.
|
||||
|
||||
75
core/tests/coretests/src/android/net/NetworkKeyTest.java
Normal file
75
core/tests/coretests/src/android/net/NetworkKeyTest.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package android.net;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiSsid;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NetworkKeyTest {
|
||||
private static final String VALID_SSID = "\"ssid1\"";
|
||||
private static final String VALID_BSSID = "00:00:00:00:00:00";
|
||||
@Mock private WifiInfo mWifiInfo;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromWifi_nullInput() throws Exception {
|
||||
assertNull(NetworkKey.createFromWifiInfo(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromWifi_nullSsid() throws Exception {
|
||||
when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
|
||||
assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromWifi_emptySsid() throws Exception {
|
||||
when(mWifiInfo.getSSID()).thenReturn("");
|
||||
when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
|
||||
assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromWifi_noneSsid() throws Exception {
|
||||
when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE);
|
||||
when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
|
||||
assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromWifi_nullBssid() throws Exception {
|
||||
when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
|
||||
assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromWifi_emptyBssid() throws Exception {
|
||||
when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
|
||||
when(mWifiInfo.getBSSID()).thenReturn("");
|
||||
assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromWifi_validWifiInfo() throws Exception {
|
||||
when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
|
||||
when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
|
||||
|
||||
NetworkKey expected = new NetworkKey(new WifiKey(VALID_SSID, VALID_BSSID));
|
||||
final NetworkKey actual = NetworkKey.createFromWifiInfo(mWifiInfo);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,10 @@ import android.net.RecommendationRequest;
|
||||
import android.net.RecommendationResult;
|
||||
import android.net.ScoredNetwork;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.ScanResult;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.WifiScanner;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -76,7 +80,9 @@ import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Backing service for {@link android.net.NetworkScoreManager}.
|
||||
@@ -391,6 +397,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
isEmpty = callbackList == null
|
||||
|| callbackList.getRegisteredCallbackCount() == 0;
|
||||
}
|
||||
|
||||
if (isEmpty) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "No scorer registered for type " + entry.getKey()
|
||||
@@ -399,18 +406,10 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
continue;
|
||||
}
|
||||
|
||||
sendCallback(new Consumer<INetworkScoreCache>() {
|
||||
@Override
|
||||
public void accept(INetworkScoreCache networkScoreCache) {
|
||||
try {
|
||||
networkScoreCache.updateScores(entry.getValue());
|
||||
} catch (RemoteException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, Collections.singleton(callbackList));
|
||||
final BiConsumer<INetworkScoreCache, Object> consumer =
|
||||
new FilteringCacheUpdatingConsumer(mContext, entry.getValue(),
|
||||
entry.getKey());
|
||||
sendCacheUpdateCallback(consumer, Collections.singleton(callbackList));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -419,6 +418,229 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BiConsumer} implementation that filters the given {@link ScoredNetwork}
|
||||
* list (if needed) before invoking {@link INetworkScoreCache#updateScores(List)} on the
|
||||
* accepted {@link INetworkScoreCache} implementation.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static class FilteringCacheUpdatingConsumer
|
||||
implements BiConsumer<INetworkScoreCache, Object> {
|
||||
private final Context mContext;
|
||||
private final List<ScoredNetwork> mScoredNetworkList;
|
||||
private final int mNetworkType;
|
||||
// TODO(jjoslin): 1/23/17 - Consider a Map if we implement more filters.
|
||||
private Function<List<ScoredNetwork>, List<ScoredNetwork>> mCurrentNetworkFilter;
|
||||
private Function<List<ScoredNetwork>, List<ScoredNetwork>> mScanResultsFilter;
|
||||
|
||||
public FilteringCacheUpdatingConsumer(Context context,
|
||||
List<ScoredNetwork> scoredNetworkList, int networkType) {
|
||||
this(context, scoredNetworkList, networkType, null, null);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public FilteringCacheUpdatingConsumer(Context context,
|
||||
List<ScoredNetwork> scoredNetworkList, int networkType,
|
||||
Function<List<ScoredNetwork>, List<ScoredNetwork>> currentNetworkFilter,
|
||||
Function<List<ScoredNetwork>, List<ScoredNetwork>> scanResultsFilter) {
|
||||
mContext = context;
|
||||
mScoredNetworkList = scoredNetworkList;
|
||||
mNetworkType = networkType;
|
||||
mCurrentNetworkFilter = currentNetworkFilter;
|
||||
mScanResultsFilter = scanResultsFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
|
||||
int filterType = NetworkScoreManager.CACHE_FILTER_NONE;
|
||||
if (cookie instanceof Integer) {
|
||||
filterType = (Integer) cookie;
|
||||
}
|
||||
|
||||
try {
|
||||
final List<ScoredNetwork> filteredNetworkList =
|
||||
filterScores(mScoredNetworkList, filterType);
|
||||
if (!filteredNetworkList.isEmpty()) {
|
||||
networkScoreCache.updateScores(
|
||||
Collections.unmodifiableList(filteredNetworkList));
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "Unable to update scores of type " + mNetworkType, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the appropriate filter and returns the filtered results.
|
||||
*/
|
||||
private List<ScoredNetwork> filterScores(List<ScoredNetwork> scoredNetworkList,
|
||||
int filterType) {
|
||||
switch (filterType) {
|
||||
case NetworkScoreManager.CACHE_FILTER_NONE:
|
||||
return scoredNetworkList;
|
||||
|
||||
case NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK:
|
||||
if (mCurrentNetworkFilter == null) {
|
||||
mCurrentNetworkFilter =
|
||||
new CurrentNetworkScoreCacheFilter(new WifiInfoSupplier(mContext));
|
||||
}
|
||||
return mCurrentNetworkFilter.apply(scoredNetworkList);
|
||||
|
||||
case NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS:
|
||||
if (mScanResultsFilter == null) {
|
||||
mScanResultsFilter = new ScanResultsScoreCacheFilter(
|
||||
new ScanResultsSupplier(mContext));
|
||||
}
|
||||
return mScanResultsFilter.apply(scoredNetworkList);
|
||||
|
||||
default:
|
||||
Log.w(TAG, "Unknown filter type: " + filterType);
|
||||
return scoredNetworkList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class that improves the testability of the cache filter Functions.
|
||||
*/
|
||||
private static class WifiInfoSupplier implements Supplier<WifiInfo> {
|
||||
private final Context mContext;
|
||||
|
||||
WifiInfoSupplier(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WifiInfo get() {
|
||||
WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
|
||||
if (wifiManager != null) {
|
||||
return wifiManager.getConnectionInfo();
|
||||
}
|
||||
Log.w(TAG, "WifiManager is null, failed to return the WifiInfo.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class that improves the testability of the cache filter Functions.
|
||||
*/
|
||||
private static class ScanResultsSupplier implements Supplier<List<ScanResult>> {
|
||||
private final Context mContext;
|
||||
|
||||
ScanResultsSupplier(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ScanResult> get() {
|
||||
WifiScanner wifiScanner = mContext.getSystemService(WifiScanner.class);
|
||||
if (wifiScanner != null) {
|
||||
return wifiScanner.getSingleScanResults();
|
||||
}
|
||||
Log.w(TAG, "WifiScanner is null, failed to return scan results.");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the given set of {@link ScoredNetwork}s and returns a new List containing only the
|
||||
* {@link ScoredNetwork} associated with the current network. If no network is connected the
|
||||
* returned list will be empty.
|
||||
* <p>
|
||||
* Note: this filter performs some internal caching for consistency and performance. The
|
||||
* current network is determined at construction time and never changed. Also, the
|
||||
* last filtered list is saved so if the same input is provided multiple times in a row
|
||||
* the computation is only done once.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static class CurrentNetworkScoreCacheFilter
|
||||
implements Function<List<ScoredNetwork>, List<ScoredNetwork>> {
|
||||
private final NetworkKey mCurrentNetwork;
|
||||
private Pair<List<ScoredNetwork>, Integer> mCache;
|
||||
|
||||
CurrentNetworkScoreCacheFilter(Supplier<WifiInfo> wifiInfoSupplier) {
|
||||
mCurrentNetwork = NetworkKey.createFromWifiInfo(wifiInfoSupplier.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ScoredNetwork> apply(List<ScoredNetwork> scoredNetworks) {
|
||||
if (mCurrentNetwork == null || scoredNetworks.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final int inputListHash = scoredNetworks.hashCode();
|
||||
if (mCache == null || mCache.second != inputListHash) {
|
||||
ScoredNetwork currentScore = null;
|
||||
for (int i = 0; i < scoredNetworks.size(); i++) {
|
||||
final ScoredNetwork scoredNetwork = scoredNetworks.get(i);
|
||||
if (scoredNetwork.networkKey.equals(mCurrentNetwork)) {
|
||||
currentScore = scoredNetwork;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentScore == null) {
|
||||
mCache = Pair.create(Collections.emptyList(), inputListHash);
|
||||
} else {
|
||||
mCache = Pair.create(Collections.singletonList(currentScore), inputListHash);
|
||||
}
|
||||
}
|
||||
|
||||
return mCache.first;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the given set of {@link ScoredNetwork}s and returns a new List containing only the
|
||||
* {@link ScoredNetwork} associated with the current set of {@link ScanResult}s.
|
||||
* If there are no {@link ScanResult}s the returned list will be empty.
|
||||
* <p>
|
||||
* Note: this filter performs some internal caching for consistency and performance. The
|
||||
* current set of ScanResults is determined at construction time and never changed.
|
||||
* Also, the last filtered list is saved so if the same input is provided multiple
|
||||
* times in a row the computation is only done once.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static class ScanResultsScoreCacheFilter
|
||||
implements Function<List<ScoredNetwork>, List<ScoredNetwork>> {
|
||||
private final List<NetworkKey> mScanResultKeys;
|
||||
private Pair<List<ScoredNetwork>, Integer> mCache;
|
||||
|
||||
ScanResultsScoreCacheFilter(Supplier<List<ScanResult>> resultsSupplier) {
|
||||
mScanResultKeys = new ArrayList<>();
|
||||
List<ScanResult> scanResults = resultsSupplier.get();
|
||||
for (int i = 0; i < scanResults.size(); i++) {
|
||||
ScanResult scanResult = scanResults.get(i);
|
||||
mScanResultKeys.add(NetworkKey.createFromScanResult(scanResult));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ScoredNetwork> apply(List<ScoredNetwork> scoredNetworks) {
|
||||
if (mScanResultKeys.isEmpty() || scoredNetworks.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final int inputListHash = scoredNetworks.hashCode();
|
||||
if (mCache == null || mCache.second != inputListHash) {
|
||||
List<ScoredNetwork> filteredScores = new ArrayList<>();
|
||||
for (int i = 0; i < scoredNetworks.size(); i++) {
|
||||
final ScoredNetwork scoredNetwork = scoredNetworks.get(i);
|
||||
for (int j = 0; j < mScanResultKeys.size(); j++) {
|
||||
final NetworkKey scanResultKey = mScanResultKeys.get(j);
|
||||
if (scanResultKey.equals(scoredNetwork.networkKey)) {
|
||||
filteredScores.add(scoredNetwork);
|
||||
}
|
||||
}
|
||||
}
|
||||
mCache = Pair.create(filteredScores, inputListHash);
|
||||
}
|
||||
|
||||
return mCache.first;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCallerSystemUid() {
|
||||
// REQUEST_NETWORK_SCORES is a signature only permission.
|
||||
return mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES) ==
|
||||
@@ -499,9 +721,9 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
|
||||
/** Clear scores. Callers are responsible for checking permissions as appropriate. */
|
||||
private void clearInternal() {
|
||||
sendCallback(new Consumer<INetworkScoreCache>() {
|
||||
sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
|
||||
@Override
|
||||
public void accept(INetworkScoreCache networkScoreCache) {
|
||||
public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
|
||||
try {
|
||||
networkScoreCache.clearScores();
|
||||
} catch (RemoteException e) {
|
||||
@@ -675,9 +897,9 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
}
|
||||
writer.println("Current scorer: " + currentScorer.packageName);
|
||||
|
||||
sendCallback(new Consumer<INetworkScoreCache>() {
|
||||
sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
|
||||
@Override
|
||||
public void accept(INetworkScoreCache networkScoreCache) {
|
||||
public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
|
||||
try {
|
||||
TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
|
||||
} catch (IOException | RemoteException e) {
|
||||
@@ -708,14 +930,15 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void sendCallback(Consumer<INetworkScoreCache> consumer,
|
||||
private void sendCacheUpdateCallback(BiConsumer<INetworkScoreCache, Object> consumer,
|
||||
Collection<RemoteCallbackList<INetworkScoreCache>> remoteCallbackLists) {
|
||||
for (RemoteCallbackList<INetworkScoreCache> callbackList : remoteCallbackLists) {
|
||||
synchronized (callbackList) { // Ensure only one active broadcast per RemoteCallbackList
|
||||
final int count = callbackList.beginBroadcast();
|
||||
try {
|
||||
for (int i = 0; i < count; i++) {
|
||||
consumer.accept(callbackList.getBroadcastItem(i));
|
||||
consumer.accept(callbackList.getBroadcastItem(i),
|
||||
callbackList.getRegisteredCallbackCookie(i));
|
||||
}
|
||||
} finally {
|
||||
callbackList.finishBroadcast();
|
||||
|
||||
@@ -63,7 +63,10 @@ import android.net.RecommendationResult;
|
||||
import android.net.ScoredNetwork;
|
||||
import android.net.Uri;
|
||||
import android.net.WifiKey;
|
||||
import android.net.wifi.ScanResult;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiSsid;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -82,6 +85,8 @@ import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.devicepolicy.MockUtils;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -96,9 +101,12 @@ import org.mockito.stubbing.Answer;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Tests for {@link NetworkScoreService}.
|
||||
@@ -106,19 +114,27 @@ import java.util.concurrent.TimeUnit;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class NetworkScoreServiceTest {
|
||||
private static final String SSID = "ssid";
|
||||
private static final String SSID_2 = "ssid_2";
|
||||
private static final String SSID_3 = "ssid_3";
|
||||
private static final ScoredNetwork SCORED_NETWORK =
|
||||
new ScoredNetwork(new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00")),
|
||||
new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID), "00:00:00:00:00:00")),
|
||||
null /* rssiCurve*/);
|
||||
private static final ScoredNetwork SCORED_NETWORK_2 =
|
||||
new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID_2), "00:00:00:00:00:00")),
|
||||
null /* rssiCurve*/);
|
||||
private static final NetworkScorerAppData NEW_SCORER =
|
||||
new NetworkScorerAppData("newPackageName", 1, "newScoringServiceClass");
|
||||
|
||||
@Mock private PackageManager mPackageManager;
|
||||
@Mock private NetworkScorerAppManager mNetworkScorerAppManager;
|
||||
@Mock private Context mContext;
|
||||
@Mock private Resources mResources;
|
||||
@Mock private INetworkScoreCache.Stub mNetworkScoreCache, mNetworkScoreCache2;
|
||||
@Mock private IBinder mIBinder, mIBinder2;
|
||||
@Mock private INetworkRecommendationProvider mRecommendationProvider;
|
||||
@Mock private Function<List<ScoredNetwork>, List<ScoredNetwork>> mCurrentNetworkFilter;
|
||||
@Mock private Function<List<ScoredNetwork>, List<ScoredNetwork>> mScanResultsFilter;
|
||||
@Mock private WifiInfo mWifiInfo;
|
||||
@Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
|
||||
|
||||
private ContentResolver mContentResolver;
|
||||
@@ -127,6 +143,11 @@ public class NetworkScoreServiceTest {
|
||||
private RemoteCallback mRemoteCallback;
|
||||
private OnResultListener mOnResultListener;
|
||||
private HandlerThread mHandlerThread;
|
||||
private List<ScanResult> mScanResults;
|
||||
|
||||
private static String quote(String str) {
|
||||
return String.format("\"%s\"", str);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -136,6 +157,8 @@ public class NetworkScoreServiceTest {
|
||||
mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
|
||||
when(mContext.getContentResolver()).thenReturn(mContentResolver);
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mWifiInfo.getSSID()).thenReturn(SCORED_NETWORK.networkKey.wifiKey.ssid);
|
||||
when(mWifiInfo.getBSSID()).thenReturn(SCORED_NETWORK.networkKey.wifiKey.bssid);
|
||||
mHandlerThread = new HandlerThread("NetworkScoreServiceTest");
|
||||
mHandlerThread.start();
|
||||
mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager,
|
||||
@@ -150,6 +173,21 @@ public class NetworkScoreServiceTest {
|
||||
Settings.Global.putLong(mContentResolver,
|
||||
Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, -1L);
|
||||
mNetworkScoreService.refreshRecommendationRequestTimeoutMs();
|
||||
populateScanResults();
|
||||
}
|
||||
|
||||
private void populateScanResults() {
|
||||
mScanResults = new ArrayList<>();
|
||||
mScanResults.add(createScanResult(SSID, SCORED_NETWORK.networkKey.wifiKey.bssid));
|
||||
mScanResults.add(createScanResult(SSID_2, SCORED_NETWORK_2.networkKey.wifiKey.bssid));
|
||||
mScanResults.add(createScanResult(SSID_3, "10:10:00:00:10:10"));
|
||||
}
|
||||
|
||||
private ScanResult createScanResult(String ssid, String bssid) {
|
||||
ScanResult result = new ScanResult();
|
||||
result.wifiSsid = WifiSsid.createFromAsciiEncoded(ssid);
|
||||
result.BSSID = bssid;
|
||||
return result;
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -622,6 +660,173 @@ public class NetworkScoreServiceTest {
|
||||
assertEquals(NEW_SCORER.packageName, mNetworkScoreService.getActiveScorerPackage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheUpdatingConsumer_nullFilter() throws Exception {
|
||||
List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
|
||||
NetworkScoreService.FilteringCacheUpdatingConsumer consumer =
|
||||
new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
|
||||
new ArrayList<>(scoredNetworkList), NetworkKey.TYPE_WIFI,
|
||||
mCurrentNetworkFilter, mScanResultsFilter);
|
||||
|
||||
consumer.accept(mNetworkScoreCache, null /*cookie*/);
|
||||
|
||||
verify(mNetworkScoreCache).updateScores(scoredNetworkList);
|
||||
verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheUpdatingConsumer_noneFilter() throws Exception {
|
||||
List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
|
||||
NetworkScoreService.FilteringCacheUpdatingConsumer
|
||||
consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
|
||||
new ArrayList<>(scoredNetworkList),
|
||||
NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
|
||||
|
||||
consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
|
||||
|
||||
verify(mNetworkScoreCache).updateScores(scoredNetworkList);
|
||||
verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheUpdatingConsumer_unknownFilter() throws Exception {
|
||||
List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
|
||||
NetworkScoreService.FilteringCacheUpdatingConsumer
|
||||
consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
|
||||
new ArrayList<>(scoredNetworkList),
|
||||
NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
|
||||
|
||||
consumer.accept(mNetworkScoreCache, -1 /*cookie*/);
|
||||
|
||||
verify(mNetworkScoreCache).updateScores(scoredNetworkList);
|
||||
verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheUpdatingConsumer_nonIntFilter() throws Exception {
|
||||
List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
|
||||
NetworkScoreService.FilteringCacheUpdatingConsumer
|
||||
consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
|
||||
new ArrayList<>(scoredNetworkList),
|
||||
NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
|
||||
|
||||
consumer.accept(mNetworkScoreCache, "not an int" /*cookie*/);
|
||||
|
||||
verify(mNetworkScoreCache).updateScores(scoredNetworkList);
|
||||
verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheUpdatingConsumer_emptyScoreList() throws Exception {
|
||||
NetworkScoreService.FilteringCacheUpdatingConsumer
|
||||
consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
|
||||
Collections.emptyList(),
|
||||
NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
|
||||
|
||||
consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
|
||||
|
||||
verifyZeroInteractions(mNetworkScoreCache, mCurrentNetworkFilter, mScanResultsFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheUpdatingConsumer_currentNetworkFilter() throws Exception {
|
||||
List<ScoredNetwork> scoredNetworkList =
|
||||
Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
|
||||
NetworkScoreService.FilteringCacheUpdatingConsumer
|
||||
consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
|
||||
new ArrayList<>(scoredNetworkList),
|
||||
NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
|
||||
|
||||
List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
|
||||
filteredList.remove(SCORED_NETWORK);
|
||||
when(mCurrentNetworkFilter.apply(scoredNetworkList)).thenReturn(filteredList);
|
||||
consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
|
||||
|
||||
verify(mNetworkScoreCache).updateScores(filteredList);
|
||||
verifyZeroInteractions(mScanResultsFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheUpdatingConsumer_scanResultsFilter() throws Exception {
|
||||
List<ScoredNetwork> scoredNetworkList =
|
||||
Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
|
||||
NetworkScoreService.FilteringCacheUpdatingConsumer
|
||||
consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
|
||||
new ArrayList<>(scoredNetworkList),
|
||||
NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
|
||||
|
||||
List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
|
||||
filteredList.remove(SCORED_NETWORK);
|
||||
when(mScanResultsFilter.apply(scoredNetworkList)).thenReturn(filteredList);
|
||||
consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
|
||||
|
||||
verify(mNetworkScoreCache).updateScores(filteredList);
|
||||
verifyZeroInteractions(mCurrentNetworkFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrentNetworkScoreCacheFilter_nullWifiInfo() throws Exception {
|
||||
NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
|
||||
new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> null /*WifiInfo*/);
|
||||
|
||||
List<ScoredNetwork> actualList =
|
||||
cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
|
||||
|
||||
assertTrue(actualList.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrentNetworkScoreCacheFilter_scoreFiltered() throws Exception {
|
||||
NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
|
||||
new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
|
||||
|
||||
List<ScoredNetwork> actualList =
|
||||
cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
|
||||
|
||||
List<ScoredNetwork> expectedList = Collections.singletonList(SCORED_NETWORK);
|
||||
assertEquals(expectedList, actualList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurrentNetworkScoreCacheFilter_currentNetworkNotInList() throws Exception {
|
||||
when(mWifiInfo.getSSID()).thenReturn("\"notInList\"");
|
||||
NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
|
||||
new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
|
||||
|
||||
List<ScoredNetwork> actualList =
|
||||
cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
|
||||
|
||||
assertTrue(actualList.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScanResultsScoreCacheFilter_emptyScanResults() throws Exception {
|
||||
NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
|
||||
new NetworkScoreService.ScanResultsScoreCacheFilter(Collections::emptyList);
|
||||
|
||||
List<ScoredNetwork> actualList =
|
||||
cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
|
||||
|
||||
assertTrue(actualList.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScanResultsScoreCacheFilter_scoresFiltered() throws Exception {
|
||||
NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
|
||||
new NetworkScoreService.ScanResultsScoreCacheFilter(() -> mScanResults);
|
||||
|
||||
ScoredNetwork unmatchedScore =
|
||||
new ScoredNetwork(new NetworkKey(new WifiKey(quote("newSsid"),
|
||||
"00:00:00:00:00:00")), null /* rssiCurve*/);
|
||||
|
||||
List<ScoredNetwork> actualList =
|
||||
cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2,
|
||||
unmatchedScore));
|
||||
|
||||
List<ScoredNetwork> expectedList = Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
|
||||
assertEquals(expectedList, actualList);
|
||||
}
|
||||
|
||||
// "injects" the mock INetworkRecommendationProvider into the NetworkScoreService.
|
||||
private void injectProvider() {
|
||||
final ComponentName componentName = new ComponentName(NEW_SCORER.packageName,
|
||||
|
||||
Reference in New Issue
Block a user