From acf1eebc403a38874e4f7c19ddb0af7056101218 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Wed, 31 Aug 2022 16:54:52 -0400 Subject: Create Configuration overrides for MCC/MNC values SystemUI currently only shows the RAT type indicator for the active network, which may change. At the same time, the Resources system does not track the active mobile network, which means that `context.getResources().getConfiguration()` may return a `Configuration` object with an incorrect MCC/MNC for the current active subscription. This CL creates a `MobileContextProvider` class, which will lazily generate `Context`s with a correctly overridden MCC/MNC, so that resource overlays properly load individual carrier iconography when the active data subscription changes. We also will load each individual mobile icon with the proper context, in case there is ever a need to show the RAT type indicator for multiple subscriptions at once. Lastly, this CL adds a new "mccmnc" arg string to demo mode so that we can easily validate RAT type indicator overlays. Test: atest MobileContextProviderTest Test: use the new `mccmnc` string in sysui demo mode to manually verify Fixes: 240555502 Change-Id: If1f7d31a46f19f335b9545ca33638786a423ba0d --- .../settingslib/mobile/MobileStatusTracker.java | 3 + .../systemui/statusbar/StatusBarMobileView.java | 10 ++ .../connectivity/ui/MobileContextProvider.kt | 137 +++++++++++++++++++++ .../systemui/statusbar/phone/DemoStatusIcons.java | 36 +++--- .../statusbar/phone/StatusBarIconController.java | 86 ++++++++----- .../connectivity/ui/MobileContextProviderTest.kt | 122 ++++++++++++++++++ .../phone/StatusBarIconControllerTest.java | 26 ++-- 7 files changed, 368 insertions(+), 52 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java index b416738ade4a..39b4b8e16708 100644 --- a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java @@ -78,6 +78,9 @@ public class MobileStatusTracker { * Config the MobileStatusTracker to start or stop monitoring platform signals. */ public void setListening(boolean listening) { + if (mListening == listening) { + return; + } mListening = listening; if (listening) { mPhone.registerTelephonyCallback(mReceiverHandler::post, mTelephonyCallback); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java index a57d849b24fa..25c6dce96b5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java @@ -38,6 +38,7 @@ import com.android.settingslib.graph.SignalDrawable; import com.android.systemui.DualToneHandler; import com.android.systemui.R; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; +import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; import java.util.ArrayList; @@ -64,6 +65,15 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver, /** * Designated constructor + * + * This view is special, in that it is the only view in SystemUI that allows for a configuration + * override on a MCC/MNC-basis. This means that for every mobile view inflated, we have to + * construct a context with that override, since the resource system doesn't have a way to + * handle this for us. + * + * @param context A context with resources configured by MCC/MNC + * @param slot The string key defining which slot this icon refers to. Always "mobile" for the + * mobile icon */ public static StatusBarMobileView fromContext( Context context, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt new file mode 100644 index 000000000000..a02dd3490341 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.connectivity.ui + +import android.content.Context +import android.content.res.Configuration +import android.os.Bundle +import android.telephony.SubscriptionInfo +import android.view.ContextThemeWrapper +import com.android.systemui.Dumpable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.demomode.DemoMode +import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK +import com.android.systemui.demomode.DemoModeController +import com.android.systemui.dump.DumpManager +import com.android.systemui.statusbar.connectivity.NetworkController +import com.android.systemui.statusbar.connectivity.SignalCallback +import java.io.PrintWriter +import javax.inject.Inject + +/** + * Every subscriptionId can have its own CarrierConfig associated with it, so we have to create our + * own [Configuration] and track resources based on the full set of available mcc-mnc combinations. + * + * (for future reference: b/240555502 is the initiating bug for this) + */ +@SysUISingleton +class MobileContextProvider +@Inject +constructor( + networkController: NetworkController, + dumpManager: DumpManager, + private val demoModeController: DemoModeController, +) : Dumpable, DemoMode { + private val subscriptions = mutableMapOf() + private val signalCallback = + object : SignalCallback { + override fun setSubs(subs: List) { + subscriptions.clear() + subs.forEach { info -> subscriptions[info.subscriptionId] = info } + } + } + + // These should always be null when not in demo mode + private var demoMcc: Int? = null + private var demoMnc: Int? = null + + init { + networkController.addCallback(signalCallback) + dumpManager.registerDumpable(this) + demoModeController.addCallback(this) + } + + /** + * @return a context with the MCC/MNC [Configuration] values corresponding to this + * subscriptionId + */ + fun getMobileContextForSub(subId: Int, context: Context): Context { + if (demoModeController.isInDemoMode) { + return createMobileContextForDemoMode(context) + } + + // Fail back to the given context if no sub exists + val info = subscriptions[subId] ?: return context + + return createCarrierConfigContext(context, info.mcc, info.mnc) + } + + /** For Demo mode (for now), just apply the same MCC/MNC override for all subIds */ + private fun createMobileContextForDemoMode(context: Context): Context { + return createCarrierConfigContext(context, demoMcc ?: 0, demoMnc ?: 0) + } + + override fun dump(pw: PrintWriter, args: Array) { + pw.println( + "Subscriptions below will be inflated with a configuration context with " + + "MCC/MNC overrides" + ) + subscriptions.forEach { (subId, info) -> + pw.println(" Subscription with subId($subId) with MCC/MNC(${info.mcc}/${info.mnc})") + } + pw.println(" MCC override: ${demoMcc ?: "(none)"}") + pw.println(" MNC override: ${demoMnc ?: "(none)"}") + } + + override fun demoCommands(): List { + return listOf(COMMAND_NETWORK) + } + + override fun onDemoModeFinished() { + demoMcc = null + demoMnc = null + } + + override fun dispatchDemoCommand(command: String, args: Bundle) { + val mccmnc = args.getString("mccmnc") ?: return + // Only length 5/6 strings are valid + if (!(mccmnc.length == 5 || mccmnc.length == 6)) { + return + } + + // MCC is always the first 3 digits, and mnc is the last 2 or 3 + demoMcc = mccmnc.subSequence(0, 3).toString().toInt() + demoMnc = mccmnc.subSequence(3, mccmnc.length).toString().toInt() + } + + companion object { + /** + * Creates a context based on this [SubscriptionInfo]'s MCC/MNC values, allowing the overlay + * system to properly load different carrier's iconography + */ + private fun createCarrierConfigContext(context: Context, mcc: Int, mnc: Int): Context { + // Copy the existing configuration + val c = Configuration(context.resources.configuration) + c.mcc = mcc + c.mnc = mnc + + return ContextThemeWrapper(context, context.theme).also { ctx -> + ctx.applyOverrideConfiguration(c) + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index deb6150f773b..1169d3f21e28 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import android.content.Context; +import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.drawable.Icon; import android.os.Bundle; @@ -29,13 +31,13 @@ import android.widget.LinearLayout; import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.R; import com.android.systemui.demomode.DemoMode; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.StatusBarMobileView; import com.android.systemui.statusbar.StatusBarWifiView; import com.android.systemui.statusbar.StatusIconDisplayable; +import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; @@ -49,7 +51,6 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da private final LinearLayout mStatusIcons; private final ArrayList mMobileViews = new ArrayList<>(); private final int mIconSize; - private final FeatureFlags mFeatureFlags; private StatusBarWifiView mWifiView; private boolean mDemoMode; @@ -57,14 +58,12 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da public DemoStatusIcons( LinearLayout statusIcons, - int iconSize, - FeatureFlags featureFlags + int iconSize ) { super(statusIcons.getContext()); mStatusIcons = statusIcons; mIconSize = iconSize; mColor = DarkIconDispatcher.DEFAULT_ICON_TINT; - mFeatureFlags = featureFlags; if (statusIcons instanceof StatusIconContainer) { setShouldRestrictIcons(((StatusIconContainer) statusIcons).isRestrictingIcons()); @@ -253,9 +252,13 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da } } - public void addMobileView(MobileIconState state) { + /** + * Add a new mobile icon view + */ + public void addMobileView(MobileIconState state, Context mobileContext) { Log.d(TAG, "addMobileView: "); - StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, state.slot); + StatusBarMobileView view = StatusBarMobileView + .fromContext(mobileContext, state.slot); view.applyMobileState(state); view.setStaticDrawableColor(mColor); @@ -265,19 +268,24 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da addView(view, getChildCount(), createLayoutParams()); } - public void updateMobileState(MobileIconState state) { - Log.d(TAG, "updateMobileState: "); - // If the view for this subId exists already, use it + /** + * Apply an update to a mobile icon view for the given {@link MobileIconState}. For + * compatibility with {@link MobileContextProvider}, we have to recreate the view every time we + * update it, since the context (and thus the {@link Configuration}) may have changed + */ + public void updateMobileState(MobileIconState state, Context mobileContext) { + Log.d(TAG, "updateMobileState: " + state); + + // The mobile config provided by MobileContextProvider could have changed; always recreate for (int i = 0; i < mMobileViews.size(); i++) { StatusBarMobileView view = mMobileViews.get(i); if (view.getState().subId == state.subId) { - view.applyMobileState(state); - return; + removeView(view); } } - // Else we have to add it - addMobileView(state); + // Add the replacement or new icon + addMobileView(state, mobileContext); } public void onRemoveIcon(StatusIconDisplayable view) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 8273d5737c2f..bd99713e3a69 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -36,7 +36,6 @@ import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.demomode.DemoModeCommandReceiver; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.statusbar.BaseStatusBarWifiView; @@ -44,6 +43,7 @@ import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.StatusBarMobileView; import com.android.systemui.statusbar.StatusBarWifiView; import com.android.systemui.statusbar.StatusIconDisplayable; +import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; @@ -70,6 +70,7 @@ public interface StatusBarIconController { void addIconGroup(IconManager iconManager); /** */ void removeIconGroup(IconManager iconManager); + /** Refresh the state of an IconManager by recreating the views */ void refreshIconGroup(IconManager iconManager); /** */ @@ -82,21 +83,25 @@ public interface StatusBarIconController { void setSignalIcon(String slot, WifiIconState state); /** */ void setMobileIcons(String slot, List states); + /** * Display the no calling & SMS icons. */ void setCallStrengthIcons(String slot, List states); + /** * Display the no calling & SMS icons. */ void setNoCallingIcons(String slot, List states); + public void setIconVisibility(String slot, boolean b); /** * Sets the live region mode for the icon - * @see android.view.View#setAccessibilityLiveRegion(int) - * @param slot Icon slot to set region for + * + * @param slot Icon slot to set region for * @param accessibilityLiveRegion live region mode for the icon + * @see android.view.View#setAccessibilityLiveRegion(int) */ void setIconAccessibilityLiveRegion(String slot, int accessibilityLiveRegion); @@ -115,8 +120,8 @@ public interface StatusBarIconController { static ArraySet getIconHideList(Context context, String hideListStr) { ArraySet ret = new ArraySet<>(); String[] hideList = hideListStr == null - ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude) - : hideListStr.split(","); + ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude) + : hideListStr.split(","); for (String slot : hideList) { if (!TextUtils.isEmpty(slot)) { ret.add(slot); @@ -134,11 +139,14 @@ public interface StatusBarIconController { public DarkIconManager( LinearLayout linearLayout, - FeatureFlags featureFlags, StatusBarPipelineFlags statusBarPipelineFlags, Provider wifiViewModelProvider, + MobileContextProvider mobileContextProvider, DarkIconDispatcher darkIconDispatcher) { - super(linearLayout, featureFlags, statusBarPipelineFlags, wifiViewModelProvider); + super(linearLayout, + statusBarPipelineFlags, + wifiViewModelProvider, + mobileContextProvider); mIconHPadding = mContext.getResources().getDimensionPixelSize( R.dimen.status_bar_icon_padding); mDarkIconDispatcher = darkIconDispatcher; @@ -195,41 +203,49 @@ public interface StatusBarIconController { @SysUISingleton public static class Factory { - private final FeatureFlags mFeatureFlags; private final StatusBarPipelineFlags mStatusBarPipelineFlags; private final Provider mWifiViewModelProvider; + private final MobileContextProvider mMobileContextProvider; private final DarkIconDispatcher mDarkIconDispatcher; @Inject public Factory( - FeatureFlags featureFlags, StatusBarPipelineFlags statusBarPipelineFlags, Provider wifiViewModelProvider, + MobileContextProvider mobileContextProvider, DarkIconDispatcher darkIconDispatcher) { - mFeatureFlags = featureFlags; mStatusBarPipelineFlags = statusBarPipelineFlags; mWifiViewModelProvider = wifiViewModelProvider; + mMobileContextProvider = mobileContextProvider; mDarkIconDispatcher = darkIconDispatcher; } public DarkIconManager create(LinearLayout group) { return new DarkIconManager( - group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider, + group, + mStatusBarPipelineFlags, + mWifiViewModelProvider, + mMobileContextProvider, mDarkIconDispatcher); } } } - /** */ + /** + * + */ class TintedIconManager extends IconManager { private int mColor; public TintedIconManager( ViewGroup group, - FeatureFlags featureFlags, StatusBarPipelineFlags statusBarPipelineFlags, - Provider wifiViewModelProvider) { - super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider); + Provider wifiViewModelProvider, + MobileContextProvider mobileContextProvider) { + super(group, + statusBarPipelineFlags, + wifiViewModelProvider, + mobileContextProvider); } @Override @@ -261,23 +277,26 @@ public interface StatusBarIconController { @SysUISingleton public static class Factory { - private final FeatureFlags mFeatureFlags; private final StatusBarPipelineFlags mStatusBarPipelineFlags; private final Provider mWifiViewModelProvider; + private final MobileContextProvider mMobileContextProvider; @Inject public Factory( - FeatureFlags featureFlags, StatusBarPipelineFlags statusBarPipelineFlags, - Provider wifiViewModelProvider) { - mFeatureFlags = featureFlags; + Provider wifiViewModelProvider, + MobileContextProvider mobileContextProvider) { mStatusBarPipelineFlags = statusBarPipelineFlags; mWifiViewModelProvider = wifiViewModelProvider; + mMobileContextProvider = mobileContextProvider; } public TintedIconManager create(ViewGroup group) { return new TintedIconManager( - group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider); + group, + mStatusBarPipelineFlags, + mWifiViewModelProvider, + mMobileContextProvider); } } } @@ -287,9 +306,9 @@ public interface StatusBarIconController { */ class IconManager implements DemoModeCommandReceiver { protected final ViewGroup mGroup; - private final FeatureFlags mFeatureFlags; private final StatusBarPipelineFlags mStatusBarPipelineFlags; private final Provider mWifiViewModelProvider; + private final MobileContextProvider mMobileContextProvider; protected final Context mContext; protected final int mIconSize; // Whether or not these icons show up in dumpsys @@ -305,13 +324,13 @@ public interface StatusBarIconController { public IconManager( ViewGroup group, - FeatureFlags featureFlags, StatusBarPipelineFlags statusBarPipelineFlags, - Provider wifiViewModelProvider) { + Provider wifiViewModelProvider, + MobileContextProvider mobileContextProvider) { mGroup = group; - mFeatureFlags = featureFlags; mStatusBarPipelineFlags = statusBarPipelineFlags; mWifiViewModelProvider = wifiViewModelProvider; + mMobileContextProvider = mobileContextProvider; mContext = group.getContext(); mIconSize = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); @@ -403,12 +422,15 @@ public interface StatusBarIconController { @VisibleForTesting protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) { - StatusBarMobileView view = onCreateStatusBarMobileView(slot); + // Use the `subId` field as a key to query for the correct context + StatusBarMobileView view = onCreateStatusBarMobileView(state.subId, slot); view.applyMobileState(state); mGroup.addView(view, index, onCreateLayoutParams()); if (mIsInDemoMode) { - mDemoStatusIcons.addMobileView(state); + Context mobileContext = mMobileContextProvider + .getMobileContextForSub(state.subId, mContext); + mDemoStatusIcons.addMobileView(state, mobileContext); } return view; } @@ -427,8 +449,10 @@ public interface StatusBarIconController { mContext, slot, mWifiViewModelProvider.get()); } - private StatusBarMobileView onCreateStatusBarMobileView(String slot) { - StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, slot); + private StatusBarMobileView onCreateStatusBarMobileView(int subId, String slot) { + Context mobileContext = mMobileContextProvider.getMobileContextForSub(subId, mContext); + StatusBarMobileView view = StatusBarMobileView + .fromContext(mobileContext, slot); return view; } @@ -516,7 +540,9 @@ public interface StatusBarIconController { } if (mIsInDemoMode) { - mDemoStatusIcons.updateMobileState(state); + Context mobileContext = mMobileContextProvider + .getMobileContextForSub(state.subId, mContext); + mDemoStatusIcons.updateMobileState(state, mobileContext); } } @@ -553,7 +579,7 @@ public interface StatusBarIconController { } protected DemoStatusIcons createDemoStatusIcons() { - return new DemoStatusIcons((LinearLayout) mGroup, mIconSize, mFeatureFlags); + return new DemoStatusIcons((LinearLayout) mGroup, mIconSize); } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt new file mode 100644 index 000000000000..0fdda62e3b30 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.connectivity.ui + +import android.telephony.SubscriptionInfo +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.demomode.DemoModeController +import com.android.systemui.dump.DumpManager +import com.android.systemui.statusbar.connectivity.NetworkController +import com.android.systemui.statusbar.connectivity.SignalCallback +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations + +@SmallTest +class MobileContextProviderTest : SysuiTestCase() { + @Mock private lateinit var networkController: NetworkController + @Mock private lateinit var dumpManager: DumpManager + @Mock private lateinit var demoModeController: DemoModeController + + private lateinit var provider: MobileContextProvider + private lateinit var signalCallback: SignalCallback + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + provider = + MobileContextProvider( + networkController, + dumpManager, + demoModeController, + ) + + signalCallback = withArgCaptor { verify(networkController).addCallback(capture()) } + } + + @Test + fun test_oneSubscription_contextHasMccMnc() { + // GIVEN there is one SubscriptionInfo + signalCallback.setSubs(listOf(SUB_1)) + + // WHEN we ask for a mobile context + val ctx = provider.getMobileContextForSub(SUB_1_ID, context) + + // THEN the configuration of that context reflect this subscription's MCC/MNC override + val config = ctx.resources.configuration + assertThat(config.mcc).isEqualTo(SUB_1_MCC) + assertThat(config.mnc).isEqualTo(SUB_1_MNC) + } + + @Test + fun test_twoSubscriptions_eachContextReflectsMccMnc() { + // GIVEN there are two SubscriptionInfos + signalCallback.setSubs(listOf(SUB_1, SUB_2)) + + // WHEN we ask for a mobile context for each sub + val ctx1 = provider.getMobileContextForSub(SUB_1_ID, context) + val ctx2 = provider.getMobileContextForSub(SUB_2_ID, context) + + // THEN the configuration of each context reflect this subscription's MCC/MNC override + val config1 = ctx1.resources.configuration + assertThat(config1.mcc).isEqualTo(SUB_1_MCC) + assertThat(config1.mnc).isEqualTo(SUB_1_MNC) + + val config2 = ctx2.resources.configuration + assertThat(config2.mcc).isEqualTo(SUB_2_MCC) + assertThat(config2.mnc).isEqualTo(SUB_2_MNC) + } + + @Test + fun test_requestingContextForNonexistentSubscription_returnsGivenContext() { + // GIVEN no SubscriptionInfos + signalCallback.setSubs(listOf()) + + // WHEN we ask for a mobile context for an unknown subscription + val ctx = provider.getMobileContextForSub(SUB_1_ID, context) + + // THEN we get the original context back + assertThat(ctx).isEqualTo(context) + } + + private val SUB_1_ID = 1 + private val SUB_1_MCC = 123 + private val SUB_1_MNC = 456 + private val SUB_1 = + mock().also { + whenever(it.subscriptionId).thenReturn(SUB_1_ID) + whenever(it.mcc).thenReturn(SUB_1_MCC) + whenever(it.mnc).thenReturn(SUB_1_MNC) + } + + private val SUB_2_ID = 2 + private val SUB_2_MCC = 666 + private val SUB_2_MNC = 777 + private val SUB_2 = + mock().also { + whenever(it.subscriptionId).thenReturn(SUB_2_ID) + whenever(it.mcc).thenReturn(SUB_2_MCC) + whenever(it.mnc).thenReturn(SUB_2_MNC) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java index ca98143044c1..de7db74495af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java @@ -20,7 +20,10 @@ import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; @@ -30,12 +33,12 @@ import android.widget.LinearLayout; import androidx.test.filters.SmallTest; import com.android.internal.statusbar.StatusBarIcon; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.StatusBarMobileView; import com.android.systemui.statusbar.StatusBarWifiView; import com.android.systemui.statusbar.StatusIconDisplayable; +import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider; import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager; import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; @@ -55,15 +58,19 @@ import javax.inject.Provider; @SmallTest public class StatusBarIconControllerTest extends LeakCheckedTest { + private MobileContextProvider mMobileContextProvider = mock(MobileContextProvider.class); + @Before public void setup() { injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); + // For testing, ignore context overrides + when(mMobileContextProvider.getMobileContextForSub(anyInt(), any())).thenReturn(mContext); } @Test public void testSetCalledOnAdd_IconManager() { LinearLayout layout = new LinearLayout(mContext); - TestIconManager manager = new TestIconManager(layout); + TestIconManager manager = new TestIconManager(layout, mMobileContextProvider); testCallOnAdd_forManager(manager); } @@ -72,9 +79,9 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { LinearLayout layout = new LinearLayout(mContext); TestDarkIconManager manager = new TestDarkIconManager( layout, - mock(FeatureFlags.class), mock(StatusBarPipelineFlags.class), () -> mock(WifiViewModel.class), + mMobileContextProvider, mock(DarkIconDispatcher.class)); testCallOnAdd_forManager(manager); } @@ -114,11 +121,14 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { TestDarkIconManager( LinearLayout group, - FeatureFlags featureFlags, StatusBarPipelineFlags statusBarPipelineFlags, Provider wifiViewModelProvider, + MobileContextProvider contextProvider, DarkIconDispatcher darkIconDispatcher) { - super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider, + super(group, + statusBarPipelineFlags, + wifiViewModelProvider, + contextProvider, darkIconDispatcher); } @@ -153,11 +163,11 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { } private static class TestIconManager extends IconManager implements TestableIconManager { - TestIconManager(ViewGroup group) { + TestIconManager(ViewGroup group, MobileContextProvider contextProvider) { super(group, - mock(FeatureFlags.class), mock(StatusBarPipelineFlags.class), - () -> mock(WifiViewModel.class)); + () -> mock(WifiViewModel.class), + contextProvider); } @Override -- cgit v1.2.3-59-g8ed1b