From d57f3247766d7e5f2a5c2cbe7be6d241526a9eba Mon Sep 17 00:00:00 2001 From: Sundeep Ghuman Date: Fri, 13 Jan 2017 15:31:48 -0800 Subject: [PATCH] Update Status Bar with Badged Wifi Icons. This change inserts badged wifi icons into the status bar to indicate historical network strength. The existing callback handler was modified to explicitly pass the drawable as currently the icon is a rendered from two separate resources, composited together in a LayeredDrawable. Badging is controlled by Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED and can be enabled from the Wifi Settings page. Bug: 34056846 Test: runtest --path frameworks/base/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java Change-Id: I33b736d4543e380887513cbb5937f49945794c09 --- .../src/com/android/settingslib/Utils.java | 13 +- .../settingslib/wifi/WifiStatusTracker.java | 36 ++++-- .../systemui/statusbar/SignalClusterView.java | 50 ++++++- .../statusbar/policy/NetworkController.java | 18 ++- .../policy/NetworkControllerImpl.java | 18 ++- .../policy/WifiSignalController.java | 114 +++++++++++++++- .../statusbar/policy/CallbackHandlerTest.java | 1 - .../policy/NetworkControllerBaseTest.java | 11 +- .../policy/NetworkControllerDataTest.java | 3 +- .../policy/NetworkControllerSignalTest.java | 6 +- .../policy/NetworkControllerWifiTest.java | 122 +++++++++++++++++- 11 files changed, 357 insertions(+), 35 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index fbc6aa3828768..ae6ada2a258e3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -21,6 +21,8 @@ import android.net.ScoredNetwork; import android.os.BatteryManager; import android.os.UserManager; import android.print.PrintManager; +import android.view.View; + import com.android.internal.util.UserIcons; import com.android.settingslib.drawable.UserIconDrawable; @@ -32,7 +34,7 @@ public class Utils { private static String sServicesSystemSharedLibPackageName; private static String sSharedSystemSharedLibPackageName; - static final int[] WIFI_PIE_FOR_BADGING = { + public static final int[] WIFI_PIE_FOR_BADGING = { com.android.internal.R.drawable.ic_signal_wifi_badged_0_bars, com.android.internal.R.drawable.ic_signal_wifi_badged_1_bar, com.android.internal.R.drawable.ic_signal_wifi_badged_2_bars, @@ -288,8 +290,15 @@ public class Utils { }); } - private static int getWifiBadgeResource(int badge) { + /** + * Returns the resource id for the given badge or {@link View.NO_ID} if no badge is to be shown. + * + * @throws IllegalArgumentException if the given badge value is not supported. + */ + public static int getWifiBadgeResource(int badge) { switch (badge) { + case ScoredNetwork.BADGING_NONE: + return View.NO_ID; case ScoredNetwork.BADGING_SD: return com.android.internal.R.drawable.ic_signal_wifi_badged_sd; case ScoredNetwork.BADGING_HD: diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index fabae573e4b00..6f52dcace323c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -12,13 +12,17 @@ package com.android.settingslib.wifi; import android.content.Intent; import android.net.NetworkInfo; +import android.net.NetworkKey; +import android.net.WifiKey; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import android.util.Log; import java.util.List; public class WifiStatusTracker { + private static final String TAG = "WifiStatusTracker"; private final WifiManager mWifiManager; public boolean enabled; @@ -26,6 +30,7 @@ public class WifiStatusTracker { public String ssid; public int rssi; public int level; + public NetworkKey networkKey; public WifiStatusTracker(WifiManager wifiManager) { mWifiManager = wifiManager; @@ -40,19 +45,32 @@ public class WifiStatusTracker { final NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); connected = networkInfo != null && networkInfo.isConnected(); + WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null + ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) + : mWifiManager.getConnectionInfo(); + // If Connected grab the signal strength and ssid. - if (connected) { - // try getting it out of the intent first - WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null - ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) - : mWifiManager.getConnectionInfo(); - if (info != null) { - ssid = getSsid(info); + if (connected && info != null) { + ssid = getSsid(info); + String bssid = info.getBSSID(); + if ((ssid != null) && (bssid != null)) { + // Reuse existing network key object if possible. + if ((networkKey == null) + || !networkKey.wifiKey.ssid.equals(ssid) + || !networkKey.wifiKey.bssid.equals(bssid)) { + try { + networkKey = new NetworkKey( + new WifiKey(ssid, bssid)); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Cannot create NetworkKey", e); + } + } } else { - ssid = null; + networkKey = null; } - } else if (!connected) { + } else { ssid = null; + networkKey = null; } } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { // Default to -200 as its below WifiManager.MIN_RSSI. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index 1128101f142b9..c8e8973b2113b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -16,15 +16,18 @@ package com.android.systemui.statusbar; +import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Animatable; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.telephony.SubscriptionInfo; import android.util.ArraySet; import android.util.AttributeSet; @@ -74,8 +77,10 @@ public class SignalClusterView private boolean mEthernetVisible = false; private int mEthernetIconId = 0; private int mLastEthernetIconId = -1; + private int mWifiBadgeId = -1; private boolean mWifiVisible = false; private int mWifiStrengthId = 0; + private int mLastWifiBadgeId = -1; private int mLastWifiStrengthId = -1; private boolean mIsAirplaneMode = false; private int mAirplaneIconId = 0; @@ -259,6 +264,7 @@ public class SignalClusterView boolean activityIn, boolean activityOut, String description) { mWifiVisible = statusIcon.visible && !mBlockWifi; mWifiStrengthId = statusIcon.icon; + mWifiBadgeId = statusIcon.iconOverlay; mWifiDescription = statusIcon.contentDescription; apply(); @@ -399,6 +405,7 @@ public class SignalClusterView mWifi.setImageDrawable(null); mWifiDark.setImageDrawable(null); mLastWifiStrengthId = -1; + mLastWifiBadgeId = -1; } for (PhoneState state : mPhoneStates) { @@ -464,10 +471,16 @@ public class SignalClusterView (mEthernetVisible ? "VISIBLE" : "GONE"))); if (mWifiVisible) { - if (mWifiStrengthId != mLastWifiStrengthId) { - setIconForView(mWifi, mWifiStrengthId); - setIconForView(mWifiDark, mWifiStrengthId); + if (mWifiStrengthId != mLastWifiStrengthId || mWifiBadgeId != mLastWifiBadgeId) { + if (mWifiBadgeId == -1) { + setIconForView(mWifi, mWifiStrengthId); + setIconForView(mWifiDark, mWifiStrengthId); + } else { + setBadgedWifiIconForView(mWifi, mWifiStrengthId, mWifiBadgeId); + setBadgedWifiIconForView(mWifiDark, mWifiStrengthId, mWifiBadgeId); + } mLastWifiStrengthId = mWifiStrengthId; + mLastWifiBadgeId = mWifiBadgeId; } mWifiGroup.setContentDescription(mWifiDescription); mWifiGroup.setVisibility(View.VISIBLE); @@ -529,6 +542,10 @@ public class SignalClusterView // Using the imageView's context to retrieve the Drawable so that theme is preserved. Drawable icon = imageView.getContext().getDrawable(iconId); + setScaledIcon(imageView, icon); + } + + private void setScaledIcon(ImageView imageView, Drawable icon) { if (mIconScaleFactor == 1.f) { imageView.setImageDrawable(icon); } else { @@ -536,6 +553,33 @@ public class SignalClusterView } } + /** + * Creates and sets a LayerDrawable from the given ids on the given view. + * + *

This method will also scale the icon by {@link #mIconScaleFactor} if appropriate. + */ + private void setBadgedWifiIconForView(ImageView imageView, @DrawableRes int wifiPieId, + @DrawableRes int badgeId) { + // Using the imageView's context to retrieve the Drawable so that theme is preserved.; + LayerDrawable icon = new LayerDrawable(new Drawable[] { + imageView.getContext().getDrawable(wifiPieId), + imageView.getContext().getDrawable(badgeId)}); + + // The LayerDrawable shares an underlying state so we must mutate the object to change the + // color between the light and dark themes. + icon.mutate().setTint(getColorAttr(imageView.getContext(), R.attr.singleToneColor)); + + setScaledIcon(imageView, icon); + } + + /** Returns the given color attribute value, or white if not defined. */ + @ColorInt private static int getColorAttr(Context context, int attr) { + TypedArray ta = context.obtainStyledAttributes(new int[] {attr}); + @ColorInt int colorAccent = ta.getColor(0, Color.WHITE); + ta.recycle(); + return colorAccent; + } + public void setIconTint(int tint, float darkIntensity, Rect tintArea) { boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity || !mTintArea.equals(tintArea); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index a22fc6b8b72d7..a3a9d71877b4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.policy; import android.content.Context; import android.content.Intent; import android.telephony.SubscriptionInfo; +import android.view.View; + import com.android.settingslib.net.DataUsageController; import com.android.settingslib.wifi.AccessPoint; import com.android.systemui.DemoMode; @@ -68,15 +70,29 @@ public interface NetworkController extends CallbackController, D public static class IconState { public final boolean visible; + public final int icon; + + /** + * Optional iconOverlay resource id. + * + *

Set to -1 if not present. + */ + public final int iconOverlay; + public final String contentDescription; - public IconState(boolean visible, int icon, String contentDescription) { + public IconState(boolean visible, int icon, int iconOverlay, String contentDescription) { this.visible = visible; this.icon = icon; + this.iconOverlay = iconOverlay; this.contentDescription = contentDescription; } + public IconState(boolean visible, int icon, String contentDescription) { + this(visible, icon, -1 /* iconOverlay */, contentDescription); + } + public IconState(boolean visible, int icon, int contentDescription, Context context) { this(visible, icon, context.getString(contentDescription)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index edf2c8a93650e..b57c3636c6f8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -24,6 +24,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; +import android.net.NetworkScoreManager; import android.net.wifi.WifiManager; import android.os.AsyncTask; import android.os.Bundle; @@ -88,6 +89,7 @@ public class NetworkControllerImpl extends BroadcastReceiver private final DataSaverController mDataSaverController; private final CurrentUserTracker mUserTracker; private Config mConfig; + private final NetworkScoreManager mNetworkScoreManager; // Subcontrollers. @VisibleForTesting @@ -145,9 +147,12 @@ public class NetworkControllerImpl extends BroadcastReceiver public NetworkControllerImpl(Context context, Looper bgLooper, DeviceProvisionedController deviceProvisionedController) { this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE), + context.getSystemService(NetworkScoreManager.class), (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE), (WifiManager) context.getSystemService(Context.WIFI_SERVICE), - SubscriptionManager.from(context), Config.readConfig(context), bgLooper, + SubscriptionManager.from(context), + Config.readConfig(context), + bgLooper, new CallbackHandler(), new AccessPointControllerImpl(context, bgLooper), new DataUsageController(context), @@ -158,8 +163,12 @@ public class NetworkControllerImpl extends BroadcastReceiver @VisibleForTesting NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, - TelephonyManager telephonyManager, WifiManager wifiManager, - SubscriptionManager subManager, Config config, Looper bgLooper, + NetworkScoreManager networkScoreManager, + TelephonyManager telephonyManager, + WifiManager wifiManager, + SubscriptionManager subManager, + Config config, + Looper bgLooper, CallbackHandler callbackHandler, AccessPointControllerImpl accessPointController, DataUsageController dataUsageController, @@ -182,6 +191,7 @@ public class NetworkControllerImpl extends BroadcastReceiver // wifi mWifiManager = wifiManager; + mNetworkScoreManager = networkScoreManager; mLocale = mContext.getResources().getConfiguration().locale; mAccessPoints = accessPointController; @@ -195,7 +205,7 @@ public class NetworkControllerImpl extends BroadcastReceiver } }); mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature, - mCallbackHandler, this); + mCallbackHandler, this, mNetworkScoreManager); mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index b1bc2f07a414c..42c20ff6e2efd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -15,18 +15,27 @@ */ package com.android.systemui.statusbar.policy; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.database.ContentObserver; import android.net.NetworkCapabilities; +import android.net.NetworkKey; +import android.net.NetworkScoreManager; +import android.net.ScoredNetwork; import android.net.wifi.WifiManager; +import android.net.wifi.WifiNetworkScoreCache; +import android.net.wifi.WifiNetworkScoreCache.CacheListener; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Messenger; +import android.provider.Settings; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.AsyncChannel; +import com.android.settingslib.Utils; import com.android.settingslib.wifi.WifiStatusTracker; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; @@ -34,17 +43,24 @@ import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.R; import java.util.Objects; +import java.util.List; public class WifiSignalController extends SignalController { + private final WifiManager mWifiManager; private final AsyncChannel mWifiChannel; private final boolean mHasMobileData; + private final NetworkScoreManager mNetworkScoreManager; + private final WifiNetworkScoreCache mScoreCache; private final WifiStatusTracker mWifiTracker; + private boolean mScoringEnabled = false; + public WifiSignalController(Context context, boolean hasMobileData, - CallbackHandler callbackHandler, NetworkControllerImpl networkController) { + CallbackHandler callbackHandler, NetworkControllerImpl networkController, + NetworkScoreManager networkScoreManager) { super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI, callbackHandler, networkController); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); @@ -68,6 +84,44 @@ public class WifiSignalController extends WifiIcons.QS_WIFI_NO_NETWORK, AccessibilityContentDescriptions.WIFI_NO_CONNECTION ); + + mScoreCache = new WifiNetworkScoreCache(context, new CacheListener(handler) { + @Override + public void networkCacheUpdated(List networks) { + mCurrentState.badgeEnum = getWifiBadgeEnum(); + notifyListenersIfNecessary(); + } + }); + + // Setup scoring + mNetworkScoreManager = networkScoreManager; + ContentObserver observer = new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + mScoringEnabled = + Settings.Global.getInt( + mContext.getContentResolver(), + Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) == 1; + if (!mScoringEnabled) { + mScoreCache.clearScores(); + } + } + }; + ContentResolver cr = mContext.getContentResolver(); + cr.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED), + false /* notifyForDescendants */, + observer); + observer.onChange(false /* selfChange */); + registerScoreCache(); + } + + private void registerScoreCache() { + Log.d(mTag, "Registered score cache"); + mNetworkScoreManager.registerNetworkScoreCache( + NetworkKey.TYPE_WIFI, + mScoreCache, + NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK); } @Override @@ -88,27 +142,74 @@ public class WifiSignalController extends ("," + mContext.getString(R.string.accessibility_quick_settings_no_internet)); } - IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription); - IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(), - contentDescription); + IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), + Utils.getWifiBadgeResource(mCurrentState.badgeEnum), contentDescription); + IconState qsIcon = new IconState( + mCurrentState.connected, getQsCurrentIconId(), + Utils.getWifiBadgeResource(mCurrentState.badgeEnum), contentDescription); callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon, ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut, wifiDesc); } + @Override + public int getCurrentIconId() { + if (mCurrentState.badgeEnum != ScoredNetwork.BADGING_NONE) { + return Utils.WIFI_PIE_FOR_BADGING[mCurrentState.level]; + } + return super.getCurrentIconId(); + } + /** * Extract wifi state directly from broadcasts about changes in wifi state. */ public void handleBroadcast(Intent intent) { + // Update the WifiStatusTracker with the new information and update the score cache. + NetworkKey previousNetworkKey = mWifiTracker.networkKey; mWifiTracker.handleBroadcast(intent); + updateScoreCacheIfNecessary(previousNetworkKey); + mCurrentState.enabled = mWifiTracker.enabled; mCurrentState.connected = mWifiTracker.connected; mCurrentState.ssid = mWifiTracker.ssid; mCurrentState.rssi = mWifiTracker.rssi; mCurrentState.level = mWifiTracker.level; + mCurrentState.badgeEnum = getWifiBadgeEnum(); notifyListenersIfNecessary(); } + /** + * Clears old scores out of the cache and requests new scores if the network key has changed. + * + *

New scores are requested asynchronously. + */ + private void updateScoreCacheIfNecessary(NetworkKey previousNetworkKey) { + if (mWifiTracker.networkKey == null) { + return; + } + if ((previousNetworkKey == null) || !mWifiTracker.networkKey.equals(previousNetworkKey)) { + mScoreCache.clearScores(); + mNetworkScoreManager.requestScores(new NetworkKey[]{mWifiTracker.networkKey}); + } + } + + /** + * Returns the wifi badge enum for the current {@link #mWifiTracker} state. + * + *

{@link #updateScoreCacheIfNecessary} should be called prior to this method. + */ + private int getWifiBadgeEnum() { + if (!mScoringEnabled || mWifiTracker.networkKey == null) { + return ScoredNetwork.BADGING_NONE; + } + ScoredNetwork score = mScoreCache.getScoredNetwork(mWifiTracker.networkKey); + + if (score != null) { + return score.calculateBadge(mWifiTracker.rssi); + } + return ScoredNetwork.BADGING_NONE; + } + @VisibleForTesting void setActivity(int wifiActivity) { mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT @@ -149,12 +250,14 @@ public class WifiSignalController extends static class WifiState extends SignalController.State { String ssid; + int badgeEnum; @Override public void copyFrom(State s) { super.copyFrom(s); WifiState state = (WifiState) s; ssid = state.ssid; + badgeEnum = state.badgeEnum; } @Override @@ -166,7 +269,8 @@ public class WifiSignalController extends @Override public boolean equals(Object o) { return super.equals(o) - && Objects.equals(((WifiState) o).ssid, ssid); + && Objects.equals(((WifiState) o).ssid, ssid) + && (((WifiState) o).badgeEnum == badgeEnum); } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java index 7b56ea39137d9..c969cc2d2779f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.policy; import android.os.HandlerThread; import android.support.test.runner.AndroidJUnit4; import android.telephony.SubscriptionInfo; -import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import com.android.systemui.R; import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 23c635c3e93f1..6aa021e75239b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.policy; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; +import android.net.NetworkScoreManager; import android.net.wifi.WifiManager; import android.os.Looper; import android.telephony.PhoneStateListener; @@ -79,6 +80,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected Config mConfig; protected CallbackHandler mCallbackHandler; protected SubscriptionDefaults mMockSubDefaults; + protected NetworkScoreManager mMockNetworkScoreManager; protected int mSubId; @@ -105,6 +107,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mMockCm = mock(ConnectivityManager.class); mMockSubDefaults = mock(SubscriptionDefaults.class); mNetCapabilities = new NetworkCapabilities(); + mMockNetworkScoreManager = mock(NetworkScoreManager.class); + when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true); when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn( new NetworkCapabilities[] { mNetCapabilities }); @@ -115,7 +119,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mConfig = new Config(); mConfig.hspaDataDistinguishable = true; mCallbackHandler = mock(CallbackHandler.class); - mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, + mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, + mMockTm, mMockWm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, mock(DeviceProvisionedController.class)); @@ -157,8 +162,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected NetworkControllerImpl setUpNoMobileData() { when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); NetworkControllerImpl networkControllerNoMobile - = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, - mConfig, mContext.getMainLooper(), mCallbackHandler, + = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, mMockTm, + mMockWm, mMockSm, mConfig, mContext.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, mock(DeviceProvisionedController.class)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index 1f7ec1aecd168..1ec041872d19f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -100,7 +100,8 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { public void test4gDataIcon() { // Switch to showing 4g icon and re-initialize the NetworkController. mConfig.show4gForLte = true; - mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, + mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, + mMockTm, mMockWm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 1a61d80e24f19..00e5926415a43 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -53,7 +53,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Turn off mobile network support. Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); // Create a new NetworkController as this is currently handled in constructor. - mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, + mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, + mMockTm, mMockWm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, mock(DeviceProvisionedController.class)); @@ -107,7 +108,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Turn off mobile network support. Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); // Create a new NetworkController as this is currently handled in constructor. - mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm, + mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockNetworkScoreManager, + mMockTm, mMockWm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, mock(DeviceProvisionedController.class)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index ed32f65179c6d..06a512297282e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -1,24 +1,50 @@ package com.android.systemui.statusbar.policy; import android.content.Intent; +import android.graphics.drawable.Drawable; import android.net.NetworkCapabilities; import android.net.NetworkInfo; +import android.net.NetworkKey; +import android.net.RssiCurve; +import android.net.ScoredNetwork; +import android.net.WifiKey; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import android.net.wifi.WifiNetworkScoreCache; +import android.os.Bundle; +import android.provider.Settings; +import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; +import com.android.settingslib.Utils; import com.android.systemui.statusbar.policy.NetworkController.IconState; +import com.android.systemui.utils.FakeSettingsProvider.SettingOverrider; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Matchers; import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; @SmallTest @RunWith(AndroidJUnit4.class) @@ -27,6 +53,15 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { private static final int MIN_RSSI = -100; private static final int MAX_RSSI = -55; + private static final int LATCH_TIMEOUT = 2000; + private static final String TEST_SSID = "\"Test SSID\""; + private static final String TEST_BSSID = "00:00:00:00:00:00"; + + private final List mRequestedKeys = new ArrayList<>(); + private CountDownLatch mRequestScoresLatch; + + private SettingOverrider mSettingsOverrider; + @Test public void testWifiIcon() { String testSsid = "Test SSID"; @@ -46,6 +81,77 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { } } + @Test + public void testBadgedWifiIcon() throws Exception { + int testLevel = 1; + RssiCurve mockBadgeCurve = mock(RssiCurve.class); + Bundle attr = new Bundle(); + attr.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve); + ScoredNetwork score = + new ScoredNetwork( + new NetworkKey(new WifiKey(TEST_SSID, TEST_BSSID)), + null, + false /* meteredHint */, + attr); + + // Enable scoring + mSettingsOverrider = mContext.getSettingsProvider().acquireOverridesBuilder(this) + .addSetting("global", Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, "1") + .build(); + + setupNetworkScoreManager(); + mRequestScoresLatch = new CountDownLatch(1); + setWifiEnabled(true); + setWifiState(true, TEST_SSID, TEST_BSSID); + mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS); + + when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) ScoredNetwork.BADGING_SD); + + ArgumentCaptor scoreCacheCaptor = + ArgumentCaptor.forClass(WifiNetworkScoreCache.class); + verify(mMockNetworkScoreManager).registerNetworkScoreCache( + anyInt(), + scoreCacheCaptor.capture(), + Matchers.anyInt()); + scoreCacheCaptor.getValue().updateScores(Arrays.asList(score)); + + setWifiLevel(testLevel); + NetworkController.SignalCallback mockCallback = + mock(NetworkController.SignalCallback.class); + mNetworkController.addCallback(mockCallback); + + ArgumentCaptor iconState = ArgumentCaptor.forClass(IconState.class); + Mockito.verify(mockCallback).setWifiIndicators( + anyBoolean(), iconState.capture(), any(), anyBoolean(), anyBoolean(), any()); + + assertEquals("Badged Wifi Resource is set", + Utils.WIFI_PIE_FOR_BADGING[testLevel], + iconState.getValue().icon); + assertEquals("SD Badge is set", + Utils.getWifiBadgeResource(ScoredNetwork.BADGING_SD), + iconState.getValue().iconOverlay); + + mSettingsOverrider.release(); + } + + private void setupNetworkScoreManager() { + // Capture requested keys and count down latch if present + doAnswer( + new Answer() { + @Override + public Boolean answer(InvocationOnMock input) { + if (mRequestScoresLatch != null) { + mRequestScoresLatch.countDown(); + } + NetworkKey[] keys = (NetworkKey[]) input.getArguments()[0]; + for (NetworkKey key : keys) { + mRequestedKeys.add(key); + } + return true; + } + }).when(mMockNetworkScoreManager).requestScores(Matchers.any()); + } + @Test public void testQsWifiIcon() { String testSsid = "Test SSID"; @@ -97,7 +203,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { @Test public void testRoamingIconDuringWifi() { // Setup normal connection - String testSsid = "Test SSID"; + String testSsid = "\"Test SSID\""; int testLevel = 2; setWifiEnabled(true); setWifiState(true, testSsid); @@ -137,12 +243,19 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { } protected void setWifiState(boolean connected, String ssid) { + setWifiState(connected, ssid, null); + } + + protected void setWifiState(boolean connected, String ssid, String bssid) { Intent i = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); NetworkInfo networkInfo = Mockito.mock(NetworkInfo.class); Mockito.when(networkInfo.isConnected()).thenReturn(connected); WifiInfo wifiInfo = Mockito.mock(WifiInfo.class); Mockito.when(wifiInfo.getSSID()).thenReturn(ssid); + if (bssid != null) { + Mockito.when(wifiInfo.getBSSID()).thenReturn(bssid); + } i.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo); i.putExtra(WifiManager.EXTRA_WIFI_INFO, wifiInfo); @@ -166,8 +279,8 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { ArgumentCaptor descArg = ArgumentCaptor.forClass(String.class); Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators( - enabledArg.capture(), any(), iconArg.capture(), anyBoolean(), anyBoolean(), - descArg.capture()); + enabledArg.capture(), any(), iconArg.capture(), anyBoolean(), + anyBoolean(), descArg.capture()); IconState iconState = iconArg.getValue(); assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue()); assertEquals("WiFi connected, in quick settings", connected, iconState.visible); @@ -179,7 +292,8 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { ArgumentCaptor iconArg = ArgumentCaptor.forClass(IconState.class); Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators( - anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(), any()); + anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(), + any()); IconState iconState = iconArg.getValue(); assertEquals("WiFi visible, in status bar", visible, iconState.visible); assertEquals("WiFi signal, in status bar", icon, iconState.icon);