Merge "Implemented network score cache filtering."

This commit is contained in:
TreeHugger Robot
2017-01-25 03:01:34 +00:00
committed by Android (Google) Code Review
4 changed files with 549 additions and 21 deletions

View File

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

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

View File

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

View File

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