diff options
| -rw-r--r-- | packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java | 142 | ||||
| -rw-r--r-- | packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java | 147 |
2 files changed, 242 insertions, 47 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index b8c5aca4b946..0de3e52f34ed 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -124,8 +124,14 @@ public class AccessPoint implements Comparable<AccessPoint> { private final ConcurrentHashMap<String, ScanResult> mScanResultCache = new ConcurrentHashMap<String, ScanResult>(32); - /** Map of BSSIDs to speed values for individual ScanResults. */ - private final Map<String, Integer> mScanResultScores = new HashMap<>(); + /** + * Map of BSSIDs to scored networks for individual bssids. + * + * <p>This cache should not be evicted with scan results, as the values here are used to + * generate a fallback in the absence of scores for the visible APs. + */ + // TODO(b/63073866): change this to have score eviction logic + private final Map<String, ScoredNetwork> mScoredNetworkCache = new HashMap<>(); /** Maximum age of scan results to hold onto while actively scanning. **/ private static final long MAX_SCAN_RESULT_AGE_MS = 15000; @@ -138,6 +144,7 @@ public class AccessPoint implements Comparable<AccessPoint> { static final String KEY_SPEED = "key_speed"; static final String KEY_PSKTYPE = "key_psktype"; static final String KEY_SCANRESULTCACHE = "key_scanresultcache"; + static final String KEY_SCOREDNETWORKCACHE = "key_scorednetworkcache"; static final String KEY_CONFIG = "key_config"; static final String KEY_FQDN = "key_fqdn"; static final String KEY_PROVIDER_FRIENDLY_NAME = "key_provider_friendly_name"; @@ -188,7 +195,7 @@ public class AccessPoint implements Comparable<AccessPoint> { private Object mTag; - private int mSpeed = Speed.NONE; + @Speed private int mSpeed = Speed.NONE; private boolean mIsScoredNetworkMetered = false; // used to co-relate internal vs returned accesspoint. @@ -238,6 +245,13 @@ public class AccessPoint implements Comparable<AccessPoint> { mScanResultCache.put(result.BSSID, result); } } + if (savedState.containsKey(KEY_SCOREDNETWORKCACHE)) { + ArrayList<ScoredNetwork> scoredNetworkArrayList = + savedState.getParcelableArrayList(KEY_SCOREDNETWORKCACHE); + for (ScoredNetwork score : scoredNetworkArrayList) { + mScoredNetworkCache.put(score.networkKey.wifiKey.bssid, score); + } + } if (savedState.containsKey(KEY_FQDN)) { mFqdn = savedState.getString(KEY_FQDN); } @@ -308,8 +322,8 @@ public class AccessPoint implements Comparable<AccessPoint> { this.mNetworkInfo = that.mNetworkInfo; this.mScanResultCache.clear(); this.mScanResultCache.putAll(that.mScanResultCache); - this.mScanResultScores.clear(); - this.mScanResultScores.putAll(that.mScanResultScores); + this.mScoredNetworkCache.clear(); + this.mScoredNetworkCache.putAll(that.mScoredNetworkCache); this.mId = that.mId; this.mSpeed = that.mSpeed; this.mIsScoredNetworkMetered = that.mIsScoredNetworkMetered; @@ -347,7 +361,7 @@ public class AccessPoint implements Comparable<AccessPoint> { if (isSaved() && !other.isSaved()) return -1; if (!isSaved() && other.isSaved()) return 1; - // Faster speeds go before slower speeds + // Faster speeds go before slower speeds - but only if visible change in speed label if (getSpeed() != other.getSpeed()) { return other.getSpeed() - getSpeed(); } @@ -425,7 +439,6 @@ public class AccessPoint implements Comparable<AccessPoint> { */ boolean update(WifiNetworkScoreCache scoreCache, boolean scoringUiEnabled) { boolean scoreChanged = false; - mScanResultScores.clear(); if (scoringUiEnabled) { scoreChanged = updateScores(scoreCache); } @@ -435,38 +448,79 @@ public class AccessPoint implements Comparable<AccessPoint> { /** * Updates the AccessPoint rankingScore and speed, returning true if the data has changed. * + * <p>Precondition: {@link #mRssi} is up to date before invoking this method. + * * @param scoreCache The score cache to use to retrieve scores. + * @return true if the set speed has changed */ private boolean updateScores(WifiNetworkScoreCache scoreCache) { - int oldSpeed = mSpeed; - mSpeed = Speed.NONE; - for (ScanResult result : mScanResultCache.values()) { ScoredNetwork score = scoreCache.getScoredNetwork(result); if (score == null) { continue; } - - int speed = score.calculateBadge(result.level); - mScanResultScores.put(result.BSSID, speed); - mSpeed = Math.max(mSpeed, speed); + mScoredNetworkCache.put(result.BSSID, score); } - // set mSpeed to the connected ScanResult if the AccessPoint is the active network + return updateSpeed(); + } + + /** + * Updates the internal speed, returning true if the update resulted in a speed label change. + */ + private boolean updateSpeed() { + int oldSpeed = mSpeed; + mSpeed = generateAverageSpeedForSsid(); + + // set speed to the connected ScanResult if the AccessPoint is the active network if (isActive() && mInfo != null) { - NetworkKey key = new NetworkKey(new WifiKey( - AccessPoint.convertToQuotedString(ssid), mInfo.getBSSID())); - ScoredNetwork score = scoreCache.getScoredNetwork(key); + ScoredNetwork score = mScoredNetworkCache.get(mInfo.getBSSID()); if (score != null) { - mSpeed = score.calculateBadge(mInfo.getRssi()); + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Set score using specific access point curve for connected AP: " + + getSsidStr()); + } + // TODO(b/63073866): Map using getLevel rather than specific rssi value so score + // doesn't change without a visible wifi bar change. + int speed = score.calculateBadge(mInfo.getRssi()); + if (speed != Speed.NONE) { + mSpeed = speed; + } } } - if(WifiTracker.sVerboseLogging) { + boolean changed = oldSpeed != mSpeed; + if(WifiTracker.sVerboseLogging && changed) { Log.i(TAG, String.format("%s: Set speed to %d", ssid, mSpeed)); } + return changed; + } + + /** Creates a speed value for the current {@link #mRssi} by averaging all non zero badges. */ + @Speed private int generateAverageSpeedForSsid() { + if (mScoredNetworkCache.isEmpty()) { + return Speed.NONE; + } + + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, String.format("Generating fallbackspeed for %s using cache: %s", + getSsidStr(), mScoredNetworkCache)); + } - return oldSpeed != mSpeed; + int count = 0; + int totalSpeed = 0; + for (ScoredNetwork score : mScoredNetworkCache.values()) { + int speed = score.calculateBadge(mRssi); + if (speed != Speed.NONE) { + count++; + totalSpeed += speed; + } + } + int speed = count == 0 ? Speed.NONE : totalSpeed / count; + if (WifiTracker.sVerboseLogging) { + Log.i(TAG, String.format("%s generated fallback speed is: %d", getSsidStr(), speed)); + } + return roundToClosestSpeedEnum(speed); } /** @@ -582,8 +636,6 @@ public class AccessPoint implements Comparable<AccessPoint> { /** Updates {@link #mSeen} based on the scan result cache. */ private void updateSeen() { - // TODO(sghuman): Set to now if connected - long seen = 0; for (ScanResult result : mScanResultCache.values()) { if (result.timestamp > seen) { @@ -942,17 +994,23 @@ public class AccessPoint implements Comparable<AccessPoint> { } stringBuilder.append("=").append(result.frequency); stringBuilder.append(",").append(result.level); - if (hasSpeed(result)) { + int speed = getSpecificApSpeed(result); + if (speed != Speed.NONE) { stringBuilder.append(",") - .append(getSpeedLabel(mScanResultScores.get(result.BSSID))); + .append(getSpeedLabel(speed)); } stringBuilder.append("}"); return stringBuilder.toString(); } - private boolean hasSpeed(ScanResult result) { - return mScanResultScores.containsKey(result.BSSID) - && mScanResultScores.get(result.BSSID) != Speed.NONE; + @Speed private int getSpecificApSpeed(ScanResult result) { + ScoredNetwork score = mScoredNetworkCache.get(result.BSSID); + if (score == null) { + return Speed.NONE; + } + // For debugging purposes we may want to use mRssi rather than result.level as the average + // speed wil be determined by mRssi + return score.calculateBadge(result.level); } /** @@ -1067,6 +1125,8 @@ public class AccessPoint implements Comparable<AccessPoint> { evictOldScanResults(); savedState.putParcelableArrayList(KEY_SCANRESULTCACHE, new ArrayList<ScanResult>(mScanResultCache.values())); + savedState.putParcelableArrayList(KEY_SCOREDNETWORKCACHE, + new ArrayList<>(mScoredNetworkCache.values())); if (mNetworkInfo != null) { savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo); } @@ -1105,8 +1165,12 @@ public class AccessPoint implements Comparable<AccessPoint> { updateRssi(); int newLevel = getLevel(); - if (newLevel > 0 && newLevel != oldLevel && mAccessPointListener != null) { - mAccessPointListener.onLevelChanged(this); + if (newLevel > 0 && newLevel != oldLevel) { + // Only update labels on visible rssi changes + updateSpeed(); + if (mAccessPointListener != null) { + mAccessPointListener.onLevelChanged(this); + } } // This flag only comes from scans, is not easily saved in config if (security == SECURITY_PSK) { @@ -1191,7 +1255,23 @@ public class AccessPoint implements Comparable<AccessPoint> { } @Nullable - private String getSpeedLabel(int speed) { + @Speed + private int roundToClosestSpeedEnum(int speed) { + if (speed < Speed.SLOW) { + return Speed.NONE; + } else if (speed < (Speed.SLOW + Speed.MODERATE) / 2) { + return Speed.SLOW; + } else if (speed < (Speed.MODERATE + Speed.FAST) / 2) { + return Speed.MODERATE; + } else if (speed < (Speed.FAST + Speed.VERY_FAST) / 2) { + return Speed.FAST; + } else { + return Speed.VERY_FAST; + } + } + + @Nullable + private String getSpeedLabel(@Speed int speed) { switch (speed) { case Speed.VERY_FAST: return mContext.getString(R.string.speed_label_very_fast); diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index ae59d3781430..083d0c51c696 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -66,10 +66,24 @@ import java.util.Collections; public class AccessPointTest { private static final String TEST_SSID = "test_ssid"; + private static final int NUM_SCAN_RESULTS = 5; + + private static final ArrayList<ScanResult> SCAN_RESULTS = buildScanResultCache(); + private Context mContext; @Mock private RssiCurve mockBadgeCurve; @Mock private WifiNetworkScoreCache mockWifiNetworkScoreCache; + private static ScanResult createScanResult(String ssid, String bssid, int rssi) { + ScanResult scanResult = new ScanResult(); + scanResult.SSID = ssid; + scanResult.level = rssi; + scanResult.BSSID = bssid; + scanResult.timestamp = SystemClock.elapsedRealtime() * 1000; + scanResult.capabilities = ""; + return scanResult; + } + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -400,7 +414,7 @@ public class AccessPointTest { } @Test - public void testSpeedLabel_isDerivedFromConnectedBssid() { + public void testSpeedLabel_isDerivedFromConnectedBssidWhenScoreAvailable() { int rssi = -55; String bssid = "00:00:00:00:00:00"; int networkId = 123; @@ -411,24 +425,42 @@ public class AccessPointTest { info.setBSSID(bssid); info.setNetworkId(networkId); + ArrayList<ScanResult> scanResults = new ArrayList<>(); + ScanResult scanResultUnconnected = createScanResult(TEST_SSID, "11:11:11:11:11:11", rssi); + scanResults.add(scanResultUnconnected); + + ScanResult scanResultConnected = createScanResult(TEST_SSID, bssid, rssi); + scanResults.add(scanResultConnected); + AccessPoint ap = new TestAccessPointBuilder(mContext) .setActive(true) .setNetworkId(networkId) .setSsid(TEST_SSID) - .setScanResultCache(buildScanResultCache()) + .setScanResultCache(scanResults) .setWifiInfo(info) .build(); - NetworkKey key = new NetworkKey(new WifiKey('"' + TEST_SSID + '"', bssid)); - when(mockWifiNetworkScoreCache.getScoredNetwork(key)) + when(mockWifiNetworkScoreCache.getScoredNetwork(scanResultUnconnected)) .thenReturn(buildScoredNetworkWithMockBadgeCurve()); - when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.FAST); + when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) Speed.SLOW); + + int connectedSpeed = Speed.VERY_FAST; + RssiCurve connectedBadgeCurve = mock(RssiCurve.class); + Bundle attr1 = new Bundle(); + attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, connectedBadgeCurve); + ScoredNetwork connectedScore = new ScoredNetwork( + NetworkKey.createFromScanResult(scanResultConnected), + connectedBadgeCurve, + false /* meteredHint */, + attr1); + when(mockWifiNetworkScoreCache.getScoredNetwork(scanResultConnected)) + .thenReturn(connectedScore); + when(connectedBadgeCurve.lookupScore(anyInt())).thenReturn((byte) connectedSpeed); ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); - verify(mockWifiNetworkScoreCache, times(2)).getScoredNetwork(key); - assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.FAST); + assertThat(ap.getSpeed()).isEqualTo(connectedSpeed); } @Test @@ -562,8 +594,13 @@ public class AccessPointTest { } private ScoredNetwork buildScoredNetworkWithMockBadgeCurve() { + return buildScoredNetworkWithGivenBadgeCurve(mockBadgeCurve); + + } + + private ScoredNetwork buildScoredNetworkWithGivenBadgeCurve(RssiCurve badgeCurve) { Bundle attr1 = new Bundle(); - attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve); + attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, badgeCurve); return new ScoredNetwork( new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00")), mockBadgeCurve, @@ -574,19 +611,14 @@ public class AccessPointTest { private AccessPoint createAccessPointWithScanResultCache() { Bundle bundle = new Bundle(); - ArrayList<ScanResult> scanResults = buildScanResultCache(); - bundle.putParcelableArrayList(AccessPoint.KEY_SCANRESULTCACHE, scanResults); + bundle.putParcelableArrayList(AccessPoint.KEY_SCANRESULTCACHE, SCAN_RESULTS); return new AccessPoint(mContext, bundle); } - private ArrayList<ScanResult> buildScanResultCache() { + private static ArrayList<ScanResult> buildScanResultCache() { ArrayList<ScanResult> scanResults = new ArrayList<>(); for (int i = 0; i < 5; i++) { - ScanResult scanResult = new ScanResult(); - scanResult.level = i; - scanResult.BSSID = "bssid-" + i; - scanResult.timestamp = SystemClock.elapsedRealtime() * 1000; - scanResult.capabilities = ""; + ScanResult scanResult = createScanResult(TEST_SSID, "bssid-" + i, i); scanResults.add(scanResult); } return scanResults; @@ -849,4 +881,87 @@ public class AccessPointTest { ap.update(null, wifiInfo, networkInfo); } + + @Test + public void testSpeedLabelAveragesAllBssidScores() { + AccessPoint ap = createAccessPointWithScanResultCache(); + + int speed1 = Speed.MODERATE; + RssiCurve badgeCurve1 = mock(RssiCurve.class); + when(badgeCurve1.lookupScore(anyInt())).thenReturn((byte) speed1); + when(mockWifiNetworkScoreCache.getScoredNetwork(SCAN_RESULTS.get(0))) + .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve1)); + int speed2 = Speed.VERY_FAST; + RssiCurve badgeCurve2 = mock(RssiCurve.class); + when(badgeCurve2.lookupScore(anyInt())).thenReturn((byte) speed2); + when(mockWifiNetworkScoreCache.getScoredNetwork(SCAN_RESULTS.get(1))) + .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve2)); + + int expectedSpeed = (speed1 + speed2) / 2; + + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + + assertThat(ap.getSpeed()).isEqualTo(expectedSpeed); + } + + @Test + public void testSpeedLabelAverageIgnoresNoSpeedScores() { + AccessPoint ap = createAccessPointWithScanResultCache(); + + int speed1 = Speed.VERY_FAST; + RssiCurve badgeCurve1 = mock(RssiCurve.class); + when(badgeCurve1.lookupScore(anyInt())).thenReturn((byte) speed1); + when(mockWifiNetworkScoreCache.getScoredNetwork(SCAN_RESULTS.get(0))) + .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve1)); + int speed2 = Speed.NONE; + RssiCurve badgeCurve2 = mock(RssiCurve.class); + when(badgeCurve2.lookupScore(anyInt())).thenReturn((byte) speed2); + when(mockWifiNetworkScoreCache.getScoredNetwork(SCAN_RESULTS.get(1))) + .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve2)); + + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + + assertThat(ap.getSpeed()).isEqualTo(speed1); + } + + @Test + public void testSpeedLabelUsesFallbackScoreWhenConnectedAccessPointScoreUnavailable() { + int rssi = -55; + String bssid = "00:00:00:00:00:00"; + int networkId = 123; + + WifiInfo info = new WifiInfo(); + info.setRssi(rssi); + info.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID)); + info.setBSSID(bssid); + info.setNetworkId(networkId); + + ArrayList<ScanResult> scanResults = new ArrayList<>(); + ScanResult scanResultUnconnected = createScanResult(TEST_SSID, "11:11:11:11:11:11", rssi); + scanResults.add(scanResultUnconnected); + + ScanResult scanResultConnected = createScanResult(TEST_SSID, bssid, rssi); + scanResults.add(scanResultConnected); + + AccessPoint ap = + new TestAccessPointBuilder(mContext) + .setActive(true) + .setNetworkId(networkId) + .setSsid(TEST_SSID) + .setScanResultCache(scanResults) + .setWifiInfo(info) + .build(); + + int fallbackSpeed = Speed.SLOW; + when(mockWifiNetworkScoreCache.getScoredNetwork(scanResultUnconnected)) + .thenReturn(buildScoredNetworkWithMockBadgeCurve()); + when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) fallbackSpeed); + + when(mockWifiNetworkScoreCache.getScoredNetwork(scanResultConnected)) + .thenReturn(null); + + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + + assertThat(ap.getSpeed()).isEqualTo(fallbackSpeed); + } } |