Loading wifi/java/android/net/wifi/WifiNetworkScoreCache.java +91 −11 Original line number Diff line number Diff line Loading @@ -17,13 +17,19 @@ package android.net.wifi; import android.Manifest.permission; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Context; import android.os.Handler; import android.net.INetworkScoreCache; import android.net.NetworkKey; import android.net.ScoredNetwork; import android.util.Log; import com.android.internal.util.Preconditions; import com.android.internal.annotations.GuardedBy; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; Loading @@ -43,22 +49,41 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { // We treat the lowest possible score as though there were no score, effectively allowing the // scorer to provide an RSSI threshold below which a network should not be used. public static final int INVALID_NETWORK_SCORE = Byte.MIN_VALUE; // See {@link #CacheListener}. @Nullable @GuardedBy("mCacheLock") private CacheListener mListener; private final Context mContext; private final Object mCacheLock = new Object(); // The key is of the form "<ssid>"<bssid> // TODO: What about SSIDs that can't be encoded as UTF-8? private final Map<String, ScoredNetwork> mNetworkCache; public WifiNetworkScoreCache(Context context) { mContext = context; this(context, null /* listener */); } /** * Instantiates a WifiNetworkScoreCache. * * @param context Application context * @param listener CacheListener for cache updates */ public WifiNetworkScoreCache(Context context, @Nullable CacheListener listener) { mContext = context.getApplicationContext(); mListener = listener; mNetworkCache = new HashMap<String, ScoredNetwork>(); } @Override public final void updateScores(List<ScoredNetwork> networks) { if (networks == null) { if (networks == null || networks.isEmpty()) { return; } Log.e(TAG, "updateScores list size=" + networks.size()); Log.d(TAG, "updateScores list size=" + networks.size()); synchronized(mNetworkCache) { for (ScoredNetwork network : networks) { Loading @@ -67,6 +92,12 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { mNetworkCache.put(networkKey, network); } } synchronized (mCacheLock) { if (mListener != null) { mListener.post(networks); } } } @Override public final void clearScores() { Loading Loading @@ -193,4 +224,53 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { } } /** Registers a CacheListener instance, replacing the previous listener if it existed. */ public void registerListener(CacheListener listener) { synchronized (mCacheLock) { mListener = listener; } } /** Removes the registered CacheListener. */ public void unregisterListener() { synchronized (mCacheLock) { mListener = null; } } /** Listener for updates to the cache inside WifiNetworkScoreCache. */ public abstract static class CacheListener { private Handler mHandler; /** * Constructor for CacheListener. * * @param handler the Handler on which to invoke the {@link #networkCacheUpdated} method. * This cannot be null. */ public CacheListener(@NonNull Handler handler) { Preconditions.checkNotNull(handler); mHandler = handler; } /** Invokes the {@link #networkCacheUpdated(List<ScoredNetwork>)} method on the handler. */ void post(List<ScoredNetwork> updatedNetworks) { mHandler.post(new Runnable() { @Override public void run() { networkCacheUpdated(updatedNetworks); } }); } /** * Invoked whenever the cache is updated. * * <p>Clearing the cache does not invoke this method. * * @param updatedNetworks the networks that were updated */ public abstract void networkCacheUpdated(List<ScoredNetwork> updatedNetworks); } } wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java +160 −112 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package android.net.wifi; import static org.junit.Assert.*; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; Loading @@ -24,6 +26,9 @@ import android.net.NetworkKey; import android.net.RssiCurve; import android.net.ScoredNetwork; import android.net.WifiKey; import android.net.wifi.WifiNetworkScoreCache.CacheListener; import android.os.Handler; import android.os.HandlerThread; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; Loading @@ -33,17 +38,21 @@ import org.junit.Rule; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** Unit tests for {@link WifiNetworkScoreCache}. */ @RunWith(AndroidJUnit4.class) @SmallTest public class WifiNetworkScoreCacheTest { @Mock public Context mockContext; // isn't used, can be null @Mock private RssiCurve mockRssiCurve; public static final String SSID = "ssid"; public static final String FORMATTED_SSID = "\"" + SSID + "\""; public static final String BSSID = "AA:AA:AA:AA:AA:AA"; Loading @@ -52,6 +61,15 @@ public class WifiNetworkScoreCacheTest { public static final ScanResult VALID_SCAN_RESULT = buildScanResult(SSID, BSSID); @Mock private Context mockApplicationContext; @Mock private Context mockContext; // isn't used, can be null @Mock private RssiCurve mockRssiCurve; private CacheListener mCacheListener; private CountDownLatch mLatch; private Handler mHandler; private List<ScoredNetwork> mUpdatedNetworksCaptor; private ScoredNetwork mValidScoredNetwork; private WifiNetworkScoreCache mScoreCache = new WifiNetworkScoreCache(mockContext); Loading Loading @@ -80,9 +98,24 @@ public class WifiNetworkScoreCacheTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mockContext.getApplicationContext()).thenReturn(mockApplicationContext); mValidScoredNetwork = buildScoredNetwork(VALID_KEY, mockRssiCurve); mScoreCache = new WifiNetworkScoreCache(mockContext); initializeCacheWithValidScoredNetwork(); HandlerThread thread = new HandlerThread("WifiNetworkScoreCacheTest Handler Thread"); thread.start(); mHandler = new Handler(thread.getLooper()); mLatch = new CountDownLatch(1); mCacheListener = new CacheListener(mHandler) { @Override public void networkCacheUpdated(List<ScoredNetwork> updatedNetworks) { mUpdatedNetworksCaptor = updatedNetworks; mLatch.countDown(); } }; } Loading Loading @@ -148,9 +181,24 @@ public class WifiNetworkScoreCacheTest { @Test public void getMeteredHintShouldReturnTrue() { ScoredNetwork network = new ScoredNetwork(new NetworkKey(VALID_KEY), mockRssiCurve, true /* metered Hint */); new ScoredNetwork( new NetworkKey(VALID_KEY), mockRssiCurve, true /* metered Hint */); mScoreCache.updateScores(ImmutableList.of(network)); assertTrue(mScoreCache.getMeteredHint(VALID_SCAN_RESULT)); } @Test public void updateScoresShouldInvokeCacheListener_networkCacheUpdated() { mScoreCache = new WifiNetworkScoreCache(mockContext, mCacheListener); initializeCacheWithValidScoredNetwork(); try { mLatch.await(1, TimeUnit.SECONDS); // wait for listener to be executed } catch (InterruptedException e) { fail("Interrupted Exception while waiting for listener to be invoked."); } assertEquals("One network should be updated", 1, mUpdatedNetworksCaptor.size()); assertEquals(mValidScoredNetwork, mUpdatedNetworksCaptor.get(0)); } } Loading
wifi/java/android/net/wifi/WifiNetworkScoreCache.java +91 −11 Original line number Diff line number Diff line Loading @@ -17,13 +17,19 @@ package android.net.wifi; import android.Manifest.permission; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Context; import android.os.Handler; import android.net.INetworkScoreCache; import android.net.NetworkKey; import android.net.ScoredNetwork; import android.util.Log; import com.android.internal.util.Preconditions; import com.android.internal.annotations.GuardedBy; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; Loading @@ -43,22 +49,41 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { // We treat the lowest possible score as though there were no score, effectively allowing the // scorer to provide an RSSI threshold below which a network should not be used. public static final int INVALID_NETWORK_SCORE = Byte.MIN_VALUE; // See {@link #CacheListener}. @Nullable @GuardedBy("mCacheLock") private CacheListener mListener; private final Context mContext; private final Object mCacheLock = new Object(); // The key is of the form "<ssid>"<bssid> // TODO: What about SSIDs that can't be encoded as UTF-8? private final Map<String, ScoredNetwork> mNetworkCache; public WifiNetworkScoreCache(Context context) { mContext = context; this(context, null /* listener */); } /** * Instantiates a WifiNetworkScoreCache. * * @param context Application context * @param listener CacheListener for cache updates */ public WifiNetworkScoreCache(Context context, @Nullable CacheListener listener) { mContext = context.getApplicationContext(); mListener = listener; mNetworkCache = new HashMap<String, ScoredNetwork>(); } @Override public final void updateScores(List<ScoredNetwork> networks) { if (networks == null) { if (networks == null || networks.isEmpty()) { return; } Log.e(TAG, "updateScores list size=" + networks.size()); Log.d(TAG, "updateScores list size=" + networks.size()); synchronized(mNetworkCache) { for (ScoredNetwork network : networks) { Loading @@ -67,6 +92,12 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { mNetworkCache.put(networkKey, network); } } synchronized (mCacheLock) { if (mListener != null) { mListener.post(networks); } } } @Override public final void clearScores() { Loading Loading @@ -193,4 +224,53 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { } } /** Registers a CacheListener instance, replacing the previous listener if it existed. */ public void registerListener(CacheListener listener) { synchronized (mCacheLock) { mListener = listener; } } /** Removes the registered CacheListener. */ public void unregisterListener() { synchronized (mCacheLock) { mListener = null; } } /** Listener for updates to the cache inside WifiNetworkScoreCache. */ public abstract static class CacheListener { private Handler mHandler; /** * Constructor for CacheListener. * * @param handler the Handler on which to invoke the {@link #networkCacheUpdated} method. * This cannot be null. */ public CacheListener(@NonNull Handler handler) { Preconditions.checkNotNull(handler); mHandler = handler; } /** Invokes the {@link #networkCacheUpdated(List<ScoredNetwork>)} method on the handler. */ void post(List<ScoredNetwork> updatedNetworks) { mHandler.post(new Runnable() { @Override public void run() { networkCacheUpdated(updatedNetworks); } }); } /** * Invoked whenever the cache is updated. * * <p>Clearing the cache does not invoke this method. * * @param updatedNetworks the networks that were updated */ public abstract void networkCacheUpdated(List<ScoredNetwork> updatedNetworks); } }
wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java +160 −112 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package android.net.wifi; import static org.junit.Assert.*; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; Loading @@ -24,6 +26,9 @@ import android.net.NetworkKey; import android.net.RssiCurve; import android.net.ScoredNetwork; import android.net.WifiKey; import android.net.wifi.WifiNetworkScoreCache.CacheListener; import android.os.Handler; import android.os.HandlerThread; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; Loading @@ -33,17 +38,21 @@ import org.junit.Rule; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** Unit tests for {@link WifiNetworkScoreCache}. */ @RunWith(AndroidJUnit4.class) @SmallTest public class WifiNetworkScoreCacheTest { @Mock public Context mockContext; // isn't used, can be null @Mock private RssiCurve mockRssiCurve; public static final String SSID = "ssid"; public static final String FORMATTED_SSID = "\"" + SSID + "\""; public static final String BSSID = "AA:AA:AA:AA:AA:AA"; Loading @@ -52,6 +61,15 @@ public class WifiNetworkScoreCacheTest { public static final ScanResult VALID_SCAN_RESULT = buildScanResult(SSID, BSSID); @Mock private Context mockApplicationContext; @Mock private Context mockContext; // isn't used, can be null @Mock private RssiCurve mockRssiCurve; private CacheListener mCacheListener; private CountDownLatch mLatch; private Handler mHandler; private List<ScoredNetwork> mUpdatedNetworksCaptor; private ScoredNetwork mValidScoredNetwork; private WifiNetworkScoreCache mScoreCache = new WifiNetworkScoreCache(mockContext); Loading Loading @@ -80,9 +98,24 @@ public class WifiNetworkScoreCacheTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mockContext.getApplicationContext()).thenReturn(mockApplicationContext); mValidScoredNetwork = buildScoredNetwork(VALID_KEY, mockRssiCurve); mScoreCache = new WifiNetworkScoreCache(mockContext); initializeCacheWithValidScoredNetwork(); HandlerThread thread = new HandlerThread("WifiNetworkScoreCacheTest Handler Thread"); thread.start(); mHandler = new Handler(thread.getLooper()); mLatch = new CountDownLatch(1); mCacheListener = new CacheListener(mHandler) { @Override public void networkCacheUpdated(List<ScoredNetwork> updatedNetworks) { mUpdatedNetworksCaptor = updatedNetworks; mLatch.countDown(); } }; } Loading Loading @@ -148,9 +181,24 @@ public class WifiNetworkScoreCacheTest { @Test public void getMeteredHintShouldReturnTrue() { ScoredNetwork network = new ScoredNetwork(new NetworkKey(VALID_KEY), mockRssiCurve, true /* metered Hint */); new ScoredNetwork( new NetworkKey(VALID_KEY), mockRssiCurve, true /* metered Hint */); mScoreCache.updateScores(ImmutableList.of(network)); assertTrue(mScoreCache.getMeteredHint(VALID_SCAN_RESULT)); } @Test public void updateScoresShouldInvokeCacheListener_networkCacheUpdated() { mScoreCache = new WifiNetworkScoreCache(mockContext, mCacheListener); initializeCacheWithValidScoredNetwork(); try { mLatch.await(1, TimeUnit.SECONDS); // wait for listener to be executed } catch (InterruptedException e) { fail("Interrupted Exception while waiting for listener to be invoked."); } assertEquals("One network should be updated", 1, mUpdatedNetworksCaptor.size()); assertEquals(mValidScoredNetwork, mUpdatedNetworksCaptor.get(0)); } }