summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt137
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java86
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt122
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java26
7 files changed, 368 insertions, 52 deletions
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<Int, SubscriptionInfo>()
+ private val signalCallback =
+ object : SignalCallback {
+ override fun setSubs(subs: List<SubscriptionInfo>) {
+ 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<out String>) {
+ 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<String> {
+ 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<StatusBarMobileView> 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<MobileIconState> states);
+
/**
* Display the no calling & SMS icons.
*/
void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states);
+
/**
* Display the no calling & SMS icons.
*/
void setNoCallingIcons(String slot, List<CallIndicatorIconState> 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<String> getIconHideList(Context context, String hideListStr) {
ArraySet<String> 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<WifiViewModel> 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<WifiViewModel> mWifiViewModelProvider;
+ private final MobileContextProvider mMobileContextProvider;
private final DarkIconDispatcher mDarkIconDispatcher;
@Inject
public Factory(
- FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> 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<WifiViewModel> wifiViewModelProvider) {
- super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider);
+ Provider<WifiViewModel> 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<WifiViewModel> mWifiViewModelProvider;
+ private final MobileContextProvider mMobileContextProvider;
@Inject
public Factory(
- FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
- Provider<WifiViewModel> wifiViewModelProvider) {
- mFeatureFlags = featureFlags;
+ Provider<WifiViewModel> 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<WifiViewModel> 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<WifiViewModel> wifiViewModelProvider) {
+ Provider<WifiViewModel> 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<SubscriptionInfo>().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<SubscriptionInfo>().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<WifiViewModel> 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