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 bceee2e29c80f..5e13f5959e30a 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);