From cc43d6a8782210bd2284114e7e805078958749c4 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Thu, 1 Dec 2022 17:25:23 -0500 Subject: [PATCH 1/5] Support new pipeline demo mode in the old view presenter Adds support for the new mobile pipeline's demo mode to the old front end. Note that this is kind of hacky because we actually don't have to do anything to support demo mode, since it's implemented entirely at the level of the repository. However, due to the fact that the old implementation of demo mode added a special view, `DemoStatusIcons`, that overlays the regular icons, we have to suport the new pipeline in _that_ icon container. Test: manual Bug: 249790009 Change-Id: Ib02a1eb6f6abaec113a15045f9bd0b151d2a773f --- .../statusbar/phone/DemoStatusIcons.java | 48 ++++++++++++++++++- .../phone/StatusBarIconController.java | 11 +++-- .../phone/StatusBarIconControllerImpl.java | 5 ++ .../repository/MobileConnectionRepository.kt | 2 + .../repository/MobileConnectionsRepository.kt | 2 +- .../demo/DemoMobileConnectionsRepository.kt | 2 +- .../prod/MobileConnectionRepositoryImpl.kt | 2 +- .../ui/view/ModernStatusBarMobileView.kt | 3 ++ .../ui/viewmodel/MobileIconsViewModel.kt | 6 +-- .../FakeMobileConnectionRepository.kt | 2 +- .../FakeMobileConnectionsRepository.kt | 6 +-- .../interactor/MobileIconInteractorTest.kt | 2 +- .../interactor/MobileIconsInteractorTest.kt | 8 ++-- 13 files changed, 77 insertions(+), 22 deletions(-) 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 1169d3f21e280..c7be2193e9b54 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -40,6 +40,8 @@ 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; +import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView; +import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel; import java.util.ArrayList; import java.util.List; @@ -50,20 +52,25 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da private final LinearLayout mStatusIcons; private final ArrayList mMobileViews = new ArrayList<>(); + private final ArrayList mModernMobileViews = new ArrayList<>(); private final int mIconSize; private StatusBarWifiView mWifiView; private boolean mDemoMode; private int mColor; + private final MobileIconsViewModel mMobileIconsViewModel; + public DemoStatusIcons( LinearLayout statusIcons, + MobileIconsViewModel mobileIconsViewModel, int iconSize ) { super(statusIcons.getContext()); mStatusIcons = statusIcons; mIconSize = iconSize; mColor = DarkIconDispatcher.DEFAULT_ICON_TINT; + mMobileIconsViewModel = mobileIconsViewModel; if (statusIcons instanceof StatusIconContainer) { setShouldRestrictIcons(((StatusIconContainer) statusIcons).isRestrictingIcons()); @@ -71,7 +78,7 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da setShouldRestrictIcons(false); } setLayoutParams(mStatusIcons.getLayoutParams()); - setPadding(mStatusIcons.getPaddingLeft(),mStatusIcons.getPaddingTop(), + setPadding(mStatusIcons.getPaddingLeft(), mStatusIcons.getPaddingTop(), mStatusIcons.getPaddingRight(), mStatusIcons.getPaddingBottom()); setOrientation(mStatusIcons.getOrientation()); setGravity(Gravity.CENTER_VERTICAL); // no LL.getGravity() @@ -115,6 +122,8 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da public void onDemoModeFinished() { mDemoMode = false; mStatusIcons.setVisibility(View.VISIBLE); + mModernMobileViews.clear(); + mMobileViews.clear(); setVisibility(View.GONE); } @@ -268,6 +277,24 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da addView(view, getChildCount(), createLayoutParams()); } + /** + * Add a {@link ModernStatusBarMobileView} + * @param mobileContext possibly mcc/mnc overridden mobile context + * @param subId the subscriptionId for this mobile view + */ + public void addModernMobileView(Context mobileContext, int subId) { + Log.d(TAG, "addModernMobileView (subId=" + subId + ")"); + ModernStatusBarMobileView view = ModernStatusBarMobileView.constructAndBind( + mobileContext, + "mobile", + mMobileIconsViewModel.viewModelForSub(subId) + ); + + // mobile always goes at the end + mModernMobileViews.add(view); + addView(view, getChildCount(), createLayoutParams()); + } + /** * 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 @@ -292,12 +319,19 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da if (view.getSlot().equals("wifi")) { removeView(mWifiView); mWifiView = null; - } else { + } else if (view instanceof StatusBarMobileView) { StatusBarMobileView mobileView = matchingMobileView(view); if (mobileView != null) { removeView(mobileView); mMobileViews.remove(mobileView); } + } else if (view instanceof ModernStatusBarMobileView) { + ModernStatusBarMobileView mobileView = matchingModernMobileView( + (ModernStatusBarMobileView) view); + if (mobileView != null) { + removeView(mobileView); + mModernMobileViews.remove(mobileView); + } } } @@ -316,6 +350,16 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da return null; } + private ModernStatusBarMobileView matchingModernMobileView(ModernStatusBarMobileView other) { + for (ModernStatusBarMobileView v : mModernMobileViews) { + if (v.getSubId() == other.getSubId()) { + return v; + } + } + + return null; + } + private LayoutParams createLayoutParams() { return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize); } 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 0a0ded24ef306..df3ab493a4dae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -536,8 +536,7 @@ public interface StatusBarIconController { mGroup.addView(view, index, onCreateLayoutParams()); if (mIsInDemoMode) { - // TODO (b/249790009): demo mode should be handled at the data layer in the - // new pipeline + mDemoStatusIcons.addModernMobileView(mContext, subId); } return view; @@ -565,11 +564,13 @@ public interface StatusBarIconController { private ModernStatusBarMobileView onCreateModernStatusBarMobileView( String slot, int subId) { + Context mobileContext = mMobileContextProvider.getMobileContextForSub(subId, mContext); return ModernStatusBarMobileView .constructAndBind( - mContext, + mobileContext, slot, - mMobileIconsViewModel.viewModelForSub(subId)); + mMobileIconsViewModel.viewModelForSub(subId) + ); } protected LinearLayout.LayoutParams onCreateLayoutParams() { @@ -704,7 +705,7 @@ public interface StatusBarIconController { } protected DemoStatusIcons createDemoStatusIcons() { - return new DemoStatusIcons((LinearLayout) mGroup, mIconSize); + return new DemoStatusIcons((LinearLayout) mGroup, mMobileIconsViewModel, mIconSize); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java index 674e5747e331b..9fbe6cbc0e326 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java @@ -276,6 +276,11 @@ public class StatusBarIconControllerImpl implements Tunable, String slotName = mContext.getString(com.android.internal.R.string.status_bar_mobile); Slot mobileSlot = mStatusBarIconList.getSlot(slotName); + // Because of the way we cache the icon holders, we need to remove everything any time + // we get a new set of subscriptions. This might change in the future, but is required + // to support demo mode for now + removeAllIconsForSlot(slotName); + Collections.reverse(subIds); for (Integer subId : subIds) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt index f09456342f78f..90e531ce49dac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt @@ -36,6 +36,8 @@ import kotlinx.coroutines.flow.StateFlow * eventually becomes a single icon in the status bar. */ interface MobileConnectionRepository { + /** The subscriptionId that this connection represents */ + val subId: Int /** * A flow that aggregates all necessary callbacks from [TelephonyCallback] into a single * listener + model. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt index 14200f090c87c..7684b762fe552 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt @@ -31,7 +31,7 @@ import kotlinx.coroutines.flow.StateFlow */ interface MobileConnectionsRepository { /** Observable list of current mobile subscriptions */ - val subscriptionsFlow: Flow> + val subscriptionsFlow: StateFlow> /** Observable for the subscriptionId of the current mobile data connection */ val activeMobileDataSubscriptionId: StateFlow diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt index 5f2feb26b739a..eeb68e778ad9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt @@ -268,7 +268,7 @@ private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetwork else -> DefaultNetworkType(toNetworkType()) } -class DemoMobileConnectionRepository(val subId: Int) : MobileConnectionRepository { +class DemoMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository { override val subscriptionModelFlow = MutableStateFlow(MobileSubscriptionModel()) override val dataEnabled = MutableStateFlow(true) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index 4c1cf4a3ed08b..fc0eefe0599a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -58,7 +58,7 @@ import kotlinx.coroutines.flow.stateIn @OptIn(ExperimentalCoroutinesApi::class) class MobileConnectionRepositoryImpl( private val context: Context, - private val subId: Int, + override val subId: Int, private val telephonyManager: TelephonyManager, private val globalSettings: GlobalSettings, defaultDataSubId: StateFlow, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt index ec4fa9ca8128f..0ab7bcd968444 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt @@ -32,6 +32,8 @@ class ModernStatusBarMobileView( attrs: AttributeSet?, ) : BaseStatusBarFrameLayout(context, attrs) { + var subId: Int = -1 + private lateinit var slot: String override fun getSlot() = slot @@ -76,6 +78,7 @@ class ModernStatusBarMobileView( as ModernStatusBarMobileView) .also { it.slot = slot + it.subId = viewModel.subscriptionId MobileIconBinder.bind(it, viewModel) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt index 24c1db995d50c..2349cb7c5d801 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt @@ -23,7 +23,7 @@ import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMob import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import javax.inject.Inject import kotlinx.coroutines.InternalCoroutinesApi -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow /** * View model for describing the system's current mobile cellular connections. The result is a list @@ -33,7 +33,7 @@ import kotlinx.coroutines.flow.Flow class MobileIconsViewModel @Inject constructor( - val subscriptionIdsFlow: Flow>, + val subscriptionIdsFlow: StateFlow>, private val interactor: MobileIconsInteractor, private val logger: ConnectivityPipelineLogger, ) { @@ -51,7 +51,7 @@ constructor( private val interactor: MobileIconsInteractor, private val logger: ConnectivityPipelineLogger, ) { - fun create(subscriptionIdsFlow: Flow>): MobileIconsViewModel { + fun create(subscriptionIdsFlow: StateFlow>): MobileIconsViewModel { return MobileIconsViewModel( subscriptionIdsFlow, interactor, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt index 288f54c7d03c0..b06d41b8d5965 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt @@ -19,7 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel import kotlinx.coroutines.flow.MutableStateFlow -class FakeMobileConnectionRepository : MobileConnectionRepository { +class FakeMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository { private val _subscriptionsModelFlow = MutableStateFlow(MobileSubscriptionModel()) override val subscriptionModelFlow = _subscriptionsModelFlow diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt index 533d5d9d5b4a3..e21ab21de6f0c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt @@ -20,12 +20,11 @@ import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import com.android.settingslib.mobile.MobileMappings.Config import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow class FakeMobileConnectionsRepository : MobileConnectionsRepository { private val _subscriptionsFlow = MutableStateFlow>(listOf()) - override val subscriptionsFlow: Flow> = _subscriptionsFlow + override val subscriptionsFlow = _subscriptionsFlow private val _activeMobileDataSubscriptionId = MutableStateFlow(INVALID_SUBSCRIPTION_ID) override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId @@ -41,7 +40,8 @@ class FakeMobileConnectionsRepository : MobileConnectionsRepository { private val subIdRepos = mutableMapOf() override fun getRepoForSubId(subId: Int): MobileConnectionRepository { - return subIdRepos[subId] ?: FakeMobileConnectionRepository().also { subIdRepos[subId] = it } + return subIdRepos[subId] + ?: FakeMobileConnectionRepository(subId).also { subIdRepos[subId] = it } } private val _globalMobileDataSettingChangedEvent = MutableStateFlow(Unit) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt index 7fc1c0f6272cd..9d7d0ed0db084 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt @@ -49,7 +49,7 @@ class MobileIconInteractorTest : SysuiTestCase() { private lateinit var underTest: MobileIconInteractor private val mobileMappingsProxy = FakeMobileMappingsProxy() private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy) - private val connectionRepository = FakeMobileConnectionRepository() + private val connectionRepository = FakeMobileConnectionRepository(SUB_1_ID) private val scope = CoroutineScope(IMMEDIATE) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index b56dcd7525579..5cdfcfd6d1e69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -263,12 +263,12 @@ class MobileIconsInteractorTest : SysuiTestCase() { private const val SUB_1_ID = 1 private val SUB_1 = mock().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) } - private val CONNECTION_1 = FakeMobileConnectionRepository() + private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID) private const val SUB_2_ID = 2 private val SUB_2 = mock().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) } - private val CONNECTION_2 = FakeMobileConnectionRepository() + private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID) private const val SUB_3_ID = 3 private val SUB_3_OPP = @@ -276,7 +276,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { whenever(it.subscriptionId).thenReturn(SUB_3_ID) whenever(it.isOpportunistic).thenReturn(true) } - private val CONNECTION_3 = FakeMobileConnectionRepository() + private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID) private const val SUB_4_ID = 4 private val SUB_4_OPP = @@ -284,6 +284,6 @@ class MobileIconsInteractorTest : SysuiTestCase() { whenever(it.subscriptionId).thenReturn(SUB_4_ID) whenever(it.isOpportunistic).thenReturn(true) } - private val CONNECTION_4 = FakeMobileConnectionRepository() + private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID) } } From f58969d7c195debdc319e40151230bd377fbaf42 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Fri, 2 Dec 2022 12:33:12 -0500 Subject: [PATCH 2/5] Better mapping lookup for demo mode Move the entire lookup into `MobileMappings` to the repository layer. So when network types come down, they are immediately transformed into `ResolvedNetworkType` objects and given a key at that moment, using the default mobile mapping config This allows us to A) better insulate us from external depenencies and B) implement a very trivial mapping for Demo mode. TBD on whether or not we should allow switching to use the real mobile mappings implementation Test: tests in tests/src/com/andrdoid/systemui/statusbar/pipeline/mobile/* Bug: 261185097 Change-Id: I727ad3ca823f3eb225a56f371aa3cef46c340f57 --- .../data/model/MobileSubscriptionModel.kt | 3 +- .../mobile/data/model/ResolvedNetworkType.kt | 21 ++++- .../repository/MobileConnectionsRepository.kt | 12 ++- .../repository/MobileRepositorySwitcher.kt | 15 ++- .../demo/DemoMobileConnectionsRepository.kt | 92 ++++++++++--------- .../prod/MobileConnectionRepositoryImpl.kt | 30 ++++-- .../prod/MobileConnectionsRepositoryImpl.kt | 12 ++- .../domain/interactor/MobileIconInteractor.kt | 12 +-- .../interactor/MobileIconsInteractor.kt | 19 ++-- .../FakeMobileConnectionRepository.kt | 1 + .../FakeMobileConnectionsRepository.kt | 51 ++++++++-- .../MobileRepositorySwitcherTest.kt | 3 + .../prod/MobileConnectionRepositoryTest.kt | 17 ++-- .../prod/MobileConnectionsRepositoryTest.kt | 4 + .../interactor/MobileIconInteractorTest.kt | 35 +++++-- .../interactor/MobileIconsInteractorTest.kt | 3 +- 16 files changed, 215 insertions(+), 115 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt index 6341a114112c5..797a7285f877d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt @@ -27,7 +27,6 @@ import android.telephony.TelephonyCallback.ServiceStateListener import android.telephony.TelephonyCallback.SignalStrengthsListener import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyManager -import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected /** @@ -65,5 +64,5 @@ data class MobileSubscriptionModel( * [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or * [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon */ - val resolvedNetworkType: ResolvedNetworkType = DefaultNetworkType(NETWORK_TYPE_UNKNOWN), + val resolvedNetworkType: ResolvedNetworkType = ResolvedNetworkType.UnknownNetworkType, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt index f385806c1b223..dd93541d7c8f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.model import android.telephony.Annotation.NetworkType +import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy /** @@ -26,8 +27,20 @@ import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy */ sealed interface ResolvedNetworkType { @NetworkType val type: Int + val lookupKey: String + + object UnknownNetworkType : ResolvedNetworkType { + override val type: Int = NETWORK_TYPE_UNKNOWN + override val lookupKey: String = "unknown" + } + + data class DefaultNetworkType( + @NetworkType override val type: Int, + override val lookupKey: String, + ) : ResolvedNetworkType + + data class OverrideNetworkType( + @NetworkType override val type: Int, + override val lookupKey: String, + ) : ResolvedNetworkType } - -data class DefaultNetworkType(@NetworkType override val type: Int) : ResolvedNetworkType - -data class OverrideNetworkType(@NetworkType override val type: Int) : ResolvedNetworkType diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt index 7684b762fe552..58ad423616e11 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt @@ -19,8 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository import android.provider.Settings import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager -import com.android.settingslib.mobile.MobileMappings -import com.android.settingslib.mobile.MobileMappings.Config +import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @@ -36,9 +35,6 @@ interface MobileConnectionsRepository { /** Observable for the subscriptionId of the current mobile data connection */ val activeMobileDataSubscriptionId: StateFlow - /** Observable for [MobileMappings.Config] tracking the defaults */ - val defaultDataSubRatConfig: StateFlow - /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId] */ val defaultDataSubId: StateFlow @@ -50,4 +46,10 @@ interface MobileConnectionsRepository { /** Observe changes to the [Settings.Global.MOBILE_DATA] setting */ val globalMobileDataSettingChangedEvent: Flow + + /** The icon mapping from network type to [MobileIconGroup] for the default subscription */ + val defaultMobileIconMapping: Flow> + + /** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */ + val defaultMobileIconGroup: Flow } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt index e21400525f00b..628f898abb236 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt @@ -19,7 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository import android.os.Bundle import android.telephony.SubscriptionInfo import androidx.annotation.VisibleForTesting -import com.android.settingslib.mobile.MobileMappings +import com.android.settingslib.SignalIcon import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.demomode.DemoMode @@ -127,14 +127,11 @@ constructor( realRepository.activeMobileDataSubscriptionId.value ) - override val defaultDataSubRatConfig: StateFlow = - activeRepo - .flatMapLatest { it.defaultDataSubRatConfig } - .stateIn( - scope, - SharingStarted.WhileSubscribed(), - realRepository.defaultDataSubRatConfig.value - ) + override val defaultMobileIconMapping: Flow> = + activeRepo.flatMapLatest { it.defaultMobileIconMapping } + + override val defaultMobileIconGroup: Flow = + activeRepo.flatMapLatest { it.defaultMobileIconGroup } override val defaultDataSubId: StateFlow = activeRepo diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt index eeb68e778ad9a..45b2c36021212 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt @@ -17,26 +17,18 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo import android.content.Context -import android.telephony.Annotation import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID -import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED -import android.telephony.TelephonyManager.NETWORK_TYPE_GSM -import android.telephony.TelephonyManager.NETWORK_TYPE_LTE -import android.telephony.TelephonyManager.NETWORK_TYPE_NR -import android.telephony.TelephonyManager.NETWORK_TYPE_UMTS -import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import android.util.Log import com.android.settingslib.SignalIcon import com.android.settingslib.mobile.MobileMappings import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState -import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel -import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel @@ -49,7 +41,9 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn @@ -133,8 +127,31 @@ constructor( ) /** Demo mode doesn't currently support modifications to the mobile mappings */ - override val defaultDataSubRatConfig = - MutableStateFlow(MobileMappings.Config.readConfig(context)) + val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config.readConfig(context)) + + override val defaultMobileIconGroup = flowOf(TelephonyIcons.THREE_G) + + override val defaultMobileIconMapping = MutableStateFlow(TelephonyIcons.ICON_NAME_TO_ICON) + + /** + * In order to maintain compatibility with the old demo mode shell command API, reverse the + * [MobileMappings] lookup from (NetworkType: String -> Icon: MobileIconGroup), so that we can + * parse the string from the command line into a preferred icon group, and send _a_ valid + * network type for that icon through the pipeline. + * + * Note: collisions don't matter here, because the data source (the command line) only cares + * about the resulting icon, not the underlying network type. + */ + private val mobileMappingsReverseLookup: StateFlow> = + defaultMobileIconMapping + .mapLatest { networkToIconMap -> networkToIconMap.reverse() } + .stateIn( + scope, + SharingStarted.WhileSubscribed(), + defaultMobileIconMapping.value.reverse() + ) + + private fun Map.reverse() = entries.associateBy({ it.value }) { it.key } // TODO(b/261029387): add a command for this value override val defaultDataSubId = @@ -229,45 +246,34 @@ constructor( private fun subIdsString(): String = _subscriptions.value.joinToString(",") { it.subscriptionId.toString() } + private fun Mobile.toMobileSubscriptionModel(): MobileSubscriptionModel { + return MobileSubscriptionModel( + isEmergencyOnly = false, // TODO(b/261029387): not yet supported + isGsm = false, // TODO(b/261029387): not yet supported + cdmaLevel = level ?: 0, + primaryLevel = level ?: 0, + dataConnectionState = + DataConnectionState.Connected, // TODO(b/261029387): not yet supported + dataActivityDirection = activity, + carrierNetworkChangeActive = carrierNetworkChange, + resolvedNetworkType = dataType.toResolvedNetworkType() + ) + } + + private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType { + val key = mobileMappingsReverseLookup.value[this] ?: "dis" + return DefaultNetworkType(DEMO_NET_TYPE, key) + } + companion object { private const val TAG = "DemoMobileConnectionsRepo" private const val DEFAULT_SUB_ID = 1 + + private const val DEMO_NET_TYPE = 1234 } } -private fun Mobile.toMobileSubscriptionModel(): MobileSubscriptionModel { - return MobileSubscriptionModel( - isEmergencyOnly = false, // TODO(b/261029387): not yet supported - isGsm = false, // TODO(b/261029387): not yet supported - cdmaLevel = level ?: 0, - primaryLevel = level ?: 0, - dataConnectionState = DataConnectionState.Connected, // TODO(b/261029387): not yet supported - dataActivityDirection = activity, - carrierNetworkChangeActive = carrierNetworkChange, - // TODO(b/261185097): once mobile mappings can be mocked at this layer, we can build our - // own demo map - resolvedNetworkType = dataType.toResolvedNetworkType() - ) -} - -@Annotation.NetworkType -private fun SignalIcon.MobileIconGroup?.toNetworkType(): Int = - when (this) { - TelephonyIcons.THREE_G -> NETWORK_TYPE_GSM - TelephonyIcons.LTE -> NETWORK_TYPE_LTE - TelephonyIcons.FOUR_G -> NETWORK_TYPE_UMTS - TelephonyIcons.NR_5G -> NETWORK_TYPE_NR - TelephonyIcons.NR_5G_PLUS -> OVERRIDE_NETWORK_TYPE_NR_ADVANCED - else -> NETWORK_TYPE_UNKNOWN - } - -private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType = - when (this) { - TelephonyIcons.NR_5G_PLUS -> OverrideNetworkType(toNetworkType()) - else -> DefaultNetworkType(toNetworkType()) - } - class DemoMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository { override val subscriptionModelFlow = MutableStateFlow(MobileSubscriptionModel()) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index fc0eefe0599a5..f6be228e0ea66 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -27,18 +27,20 @@ import android.telephony.TelephonyCallback import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE import android.telephony.TelephonyManager +import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel -import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository +import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange import com.android.systemui.util.settings.GlobalSettings -import java.lang.IllegalStateException import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope @@ -63,6 +65,7 @@ class MobileConnectionRepositoryImpl( private val globalSettings: GlobalSettings, defaultDataSubId: StateFlow, globalMobileDataSettingChangedEvent: Flow, + mobileMappingsProxy: MobileMappingsProxy, bgDispatcher: CoroutineDispatcher, logger: ConnectivityPipelineLogger, scope: CoroutineScope, @@ -141,14 +144,27 @@ class MobileConnectionRepositoryImpl( override fun onDisplayInfoChanged( telephonyDisplayInfo: TelephonyDisplayInfo ) { + val networkType = - if ( + if (telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) { + UnknownNetworkType + } else if ( telephonyDisplayInfo.overrideNetworkType == OVERRIDE_NETWORK_TYPE_NONE ) { - DefaultNetworkType(telephonyDisplayInfo.networkType) + DefaultNetworkType( + telephonyDisplayInfo.networkType, + mobileMappingsProxy.toIconKey( + telephonyDisplayInfo.networkType + ) + ) } else { - OverrideNetworkType(telephonyDisplayInfo.overrideNetworkType) + OverrideNetworkType( + telephonyDisplayInfo.overrideNetworkType, + mobileMappingsProxy.toIconKeyOverride( + telephonyDisplayInfo.overrideNetworkType + ) + ) } state = state.copy(resolvedNetworkType = networkType) trySend(state) @@ -211,6 +227,7 @@ class MobileConnectionRepositoryImpl( private val telephonyManager: TelephonyManager, private val logger: ConnectivityPipelineLogger, private val globalSettings: GlobalSettings, + private val mobileMappingsProxy: MobileMappingsProxy, @Background private val bgDispatcher: CoroutineDispatcher, @Application private val scope: CoroutineScope, ) { @@ -226,6 +243,7 @@ class MobileConnectionRepositoryImpl( globalSettings, defaultDataSubId, globalMobileDataSettingChangedEvent, + mobileMappingsProxy, bgDispatcher, logger, scope, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt index 08d6010f0d99d..6582c03d36d9e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt @@ -36,6 +36,7 @@ import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener import android.telephony.TelephonyManager import androidx.annotation.VisibleForTesting import com.android.internal.telephony.PhoneConstants +import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.settingslib.mobile.MobileMappings import com.android.settingslib.mobile.MobileMappings.Config import com.android.systemui.broadcast.BroadcastDispatcher @@ -46,6 +47,7 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository +import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.util.settings.GlobalSettings import javax.inject.Inject @@ -59,6 +61,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach @@ -75,6 +78,7 @@ constructor( private val subscriptionManager: SubscriptionManager, private val telephonyManager: TelephonyManager, private val logger: ConnectivityPipelineLogger, + mobileMappingsProxy: MobileMappingsProxy, broadcastDispatcher: BroadcastDispatcher, private val globalSettings: GlobalSettings, private val context: Context, @@ -157,7 +161,7 @@ constructor( * * This flow will produce whenever the default data subscription or the carrier config changes. */ - override val defaultDataSubRatConfig: StateFlow = + private val defaultDataSubRatConfig: StateFlow = merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent) .mapLatest { Config.readConfig(context) } .stateIn( @@ -166,6 +170,12 @@ constructor( initialValue = Config.readConfig(context) ) + override val defaultMobileIconMapping: Flow> = + defaultDataSubRatConfig.map { mobileMappingsProxy.mapIconSets(it) } + + override val defaultMobileIconGroup: Flow = + defaultDataSubRatConfig.map { mobileMappingsProxy.getDefaultIcons(it) } + override fun getRepoForSubId(subId: Int): MobileConnectionRepository { if (!isValidSubId(subId)) { throw IllegalArgumentException( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index 0da84f0bec9cd..96c5597762578 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -20,10 +20,7 @@ import android.telephony.CarrierConfigManager import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected -import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType -import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository -import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.util.CarrierConfigTracker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -70,7 +67,6 @@ class MobileIconInteractorImpl( defaultMobileIconMapping: StateFlow>, defaultMobileIconGroup: StateFlow, override val isDefaultConnectionFailed: StateFlow, - mobileMappingsProxy: MobileMappingsProxy, connectionRepository: MobileConnectionRepository, ) : MobileIconInteractor { private val mobileStatusInfo = connectionRepository.subscriptionModelFlow @@ -86,13 +82,7 @@ class MobileIconInteractorImpl( defaultMobileIconMapping, defaultMobileIconGroup, ) { info, mapping, defaultGroup -> - val lookupKey = - when (val resolved = info.resolvedNetworkType) { - is DefaultNetworkType -> mobileMappingsProxy.toIconKey(resolved.type) - is OverrideNetworkType -> - mobileMappingsProxy.toIconKeyOverride(resolved.type) - } - mapping[lookupKey] ?: defaultGroup + mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup } .stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt index a4175c3a6ab19..ada3b39620864 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt @@ -27,7 +27,6 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository -import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.util.CarrierConfigTracker import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -79,7 +78,6 @@ class MobileIconsInteractorImpl constructor( private val mobileConnectionsRepo: MobileConnectionsRepository, private val carrierConfigTracker: CarrierConfigTracker, - private val mobileMappingsProxy: MobileMappingsProxy, userSetupRepo: UserSetupRepository, @Application private val scope: CoroutineScope, ) : MobileIconsInteractor { @@ -154,15 +152,19 @@ constructor( * subscription Id. This mapping is the same for every subscription. */ override val defaultMobileIconMapping: StateFlow> = - mobileConnectionsRepo.defaultDataSubRatConfig - .mapLatest { mobileMappingsProxy.mapIconSets(it) } - .stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = mapOf()) + mobileConnectionsRepo.defaultMobileIconMapping.stateIn( + scope, + SharingStarted.WhileSubscribed(), + initialValue = mapOf() + ) /** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */ override val defaultMobileIconGroup: StateFlow = - mobileConnectionsRepo.defaultDataSubRatConfig - .mapLatest { mobileMappingsProxy.getDefaultIcons(it) } - .stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = TelephonyIcons.G) + mobileConnectionsRepo.defaultMobileIconGroup.stateIn( + scope, + SharingStarted.WhileSubscribed(), + initialValue = TelephonyIcons.G + ) /** * We want to show an error state when cellular has actually failed to validate, but not if some @@ -189,7 +191,6 @@ constructor( defaultMobileIconMapping, defaultMobileIconGroup, isDefaultConnectionFailed, - mobileMappingsProxy, mobileConnectionsRepo.getRepoForSubId(subId), ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt index b06d41b8d5965..fcd0f2b126ae1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel import kotlinx.coroutines.flow.MutableStateFlow +// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionRepository class FakeMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository { private val _subscriptionsModelFlow = MutableStateFlow(MobileSubscriptionModel()) override val subscriptionModelFlow = _subscriptionsModelFlow diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt index e21ab21de6f0c..af2dfb015e0be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt @@ -18,20 +18,41 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID -import com.android.settingslib.mobile.MobileMappings.Config +import android.telephony.TelephonyDisplayInfo +import android.telephony.TelephonyManager +import com.android.settingslib.SignalIcon +import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel +import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import kotlinx.coroutines.flow.MutableStateFlow -class FakeMobileConnectionsRepository : MobileConnectionsRepository { +// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionsRepository +class FakeMobileConnectionsRepository(mobileMappings: MobileMappingsProxy) : + MobileConnectionsRepository { + val GSM_KEY = mobileMappings.toIconKey(GSM) + val LTE_KEY = mobileMappings.toIconKey(LTE) + val UMTS_KEY = mobileMappings.toIconKey(UMTS) + val LTE_ADVANCED_KEY = mobileMappings.toIconKeyOverride(LTE_ADVANCED_PRO) + + /** + * To avoid a reliance on [MobileMappings], we'll build a simpler map from network type to + * mobile icon. See TelephonyManager.NETWORK_TYPES for a list of types and [TelephonyIcons] for + * the exhaustive set of icons + */ + val TEST_MAPPING: Map = + mapOf( + GSM_KEY to TelephonyIcons.THREE_G, + LTE_KEY to TelephonyIcons.LTE, + UMTS_KEY to TelephonyIcons.FOUR_G, + LTE_ADVANCED_KEY to TelephonyIcons.NR_5G, + ) + private val _subscriptionsFlow = MutableStateFlow>(listOf()) override val subscriptionsFlow = _subscriptionsFlow private val _activeMobileDataSubscriptionId = MutableStateFlow(INVALID_SUBSCRIPTION_ID) override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId - private val _defaultDataSubRatConfig = MutableStateFlow(Config()) - override val defaultDataSubRatConfig = _defaultDataSubRatConfig - private val _defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID) override val defaultDataSubId = _defaultDataSubId @@ -47,14 +68,16 @@ class FakeMobileConnectionsRepository : MobileConnectionsRepository { private val _globalMobileDataSettingChangedEvent = MutableStateFlow(Unit) override val globalMobileDataSettingChangedEvent = _globalMobileDataSettingChangedEvent + private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING) + override val defaultMobileIconMapping = _defaultMobileIconMapping + + private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON) + override val defaultMobileIconGroup = _defaultMobileIconGroup + fun setSubscriptions(subs: List) { _subscriptionsFlow.value = subs } - fun setDefaultDataSubRatConfig(config: Config) { - _defaultDataSubRatConfig.value = config - } - fun setDefaultDataSubId(id: Int) { _defaultDataSubId.value = id } @@ -74,4 +97,14 @@ class FakeMobileConnectionsRepository : MobileConnectionsRepository { fun setMobileConnectionRepositoryMap(connections: Map) { connections.forEach { entry -> subIdRepos[entry.key] = entry.value } } + + companion object { + val DEFAULT_ICON = TelephonyIcons.G + + // Use [MobileMappings] to define some simple definitions + const val GSM = TelephonyManager.NETWORK_TYPE_GSM + const val LTE = TelephonyManager.NETWORK_TYPE_LTE + const val UMTS = TelephonyManager.NETWORK_TYPE_UMTS + const val LTE_ADVANCED_PRO = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt index 96a280a296edf..516896099491c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoM import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl +import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.kotlinArgumentCaptor @@ -76,6 +77,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() { private val globalSettings = FakeSettings() private val fakeNetworkEventsFlow = MutableStateFlow(null) + private val mobileMappings = FakeMobileMappingsProxy() private val scope = CoroutineScope(IMMEDIATE) @@ -97,6 +99,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() { subscriptionManager, telephonyManager, logger, + mobileMappings, fakeBroadcastDispatcher, globalSettings, context, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index c8df5ac17dff4..099cb660f6595 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -37,10 +37,12 @@ import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState -import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel -import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository +import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -72,8 +74,9 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Mock private lateinit var logger: ConnectivityPipelineLogger private val scope = CoroutineScope(IMMEDIATE) + private val mobileMappings = FakeMobileMappingsProxy() private val globalSettings = FakeSettings() - private val connectionsRepo = FakeMobileConnectionsRepository() + private val connectionsRepo = FakeMobileConnectionsRepository(mobileMappings) @Before fun setUp() { @@ -89,6 +92,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { globalSettings, connectionsRepo.defaultDataSubId, connectionsRepo.globalMobileDataSettingChangedEvent, + mobileMappings, IMMEDIATE, logger, scope, @@ -272,7 +276,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) val type = NETWORK_TYPE_UNKNOWN - val expected = DefaultNetworkType(type) + val expected = UnknownNetworkType assertThat(latest?.resolvedNetworkType).isEqualTo(expected) @@ -287,7 +291,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { val callback = getTelephonyCallbackForType() val type = NETWORK_TYPE_LTE - val expected = DefaultNetworkType(type) + val expected = DefaultNetworkType(type, mobileMappings.toIconKey(type)) val ti = mock().also { whenever(it.networkType).thenReturn(type) } callback.onDisplayInfoChanged(ti) @@ -304,9 +308,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { val callback = getTelephonyCallbackForType() val type = OVERRIDE_NETWORK_TYPE_LTE_CA - val expected = OverrideNetworkType(type) + val expected = OverrideNetworkType(type, mobileMappings.toIconKeyOverride(type)) val ti = mock().also { + whenever(it.networkType).thenReturn(type) whenever(it.overrideNetworkType).thenReturn(type) } callback.onDisplayInfoChanged(ti) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt index 359ea18fcb840..68d85ccca9760 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt @@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest import com.android.internal.telephony.PhoneConstants import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel +import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -65,6 +66,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { @Mock private lateinit var telephonyManager: TelephonyManager @Mock private lateinit var logger: ConnectivityPipelineLogger + private val mobileMappings = FakeMobileMappingsProxy() + private val scope = CoroutineScope(IMMEDIATE) private val globalSettings = FakeSettings() @@ -78,6 +81,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { subscriptionManager, telephonyManager, logger, + mobileMappings, fakeBroadcastDispatcher, globalSettings, context, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt index 9d7d0ed0db084..b20f8fb4c5022 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt @@ -24,9 +24,9 @@ import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState -import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel -import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G @@ -62,7 +62,6 @@ class MobileIconInteractorTest : SysuiTestCase() { mobileIconsInteractor.defaultMobileIconMapping, mobileIconsInteractor.defaultMobileIconGroup, mobileIconsInteractor.isDefaultConnectionFailed, - mobileMappingsProxy, connectionRepository, ) } @@ -138,7 +137,10 @@ class MobileIconInteractorTest : SysuiTestCase() { fun iconGroup_three_g() = runBlocking(IMMEDIATE) { connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel(resolvedNetworkType = DefaultNetworkType(THREE_G)), + MobileSubscriptionModel( + resolvedNetworkType = + DefaultNetworkType(THREE_G, mobileMappingsProxy.toIconKey(THREE_G)) + ), ) var latest: MobileIconGroup? = null @@ -153,7 +155,10 @@ class MobileIconInteractorTest : SysuiTestCase() { fun iconGroup_updates_on_change() = runBlocking(IMMEDIATE) { connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel(resolvedNetworkType = DefaultNetworkType(THREE_G)), + MobileSubscriptionModel( + resolvedNetworkType = + DefaultNetworkType(THREE_G, mobileMappingsProxy.toIconKey(THREE_G)) + ), ) var latest: MobileIconGroup? = null @@ -161,7 +166,11 @@ class MobileIconInteractorTest : SysuiTestCase() { connectionRepository.setMobileSubscriptionModel( MobileSubscriptionModel( - resolvedNetworkType = DefaultNetworkType(FOUR_G), + resolvedNetworkType = + DefaultNetworkType( + FOUR_G, + mobileMappingsProxy.toIconKey(FOUR_G), + ), ), ) yield() @@ -175,7 +184,13 @@ class MobileIconInteractorTest : SysuiTestCase() { fun iconGroup_5g_override_type() = runBlocking(IMMEDIATE) { connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel(resolvedNetworkType = OverrideNetworkType(FIVE_G_OVERRIDE)), + MobileSubscriptionModel( + resolvedNetworkType = + OverrideNetworkType( + FIVE_G_OVERRIDE, + mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE) + ) + ), ) var latest: MobileIconGroup? = null @@ -191,7 +206,11 @@ class MobileIconInteractorTest : SysuiTestCase() { runBlocking(IMMEDIATE) { connectionRepository.setMobileSubscriptionModel( MobileSubscriptionModel( - resolvedNetworkType = DefaultNetworkType(NETWORK_TYPE_UNKNOWN), + resolvedNetworkType = + DefaultNetworkType( + NETWORK_TYPE_UNKNOWN, + mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN) + ), ), ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index 5cdfcfd6d1e69..4e950f5211ace 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -45,8 +45,8 @@ import org.mockito.MockitoAnnotations class MobileIconsInteractorTest : SysuiTestCase() { private lateinit var underTest: MobileIconsInteractor private val userSetupRepository = FakeUserSetupRepository() - private val connectionsRepository = FakeMobileConnectionsRepository() private val mobileMappingsProxy = FakeMobileMappingsProxy() + private val connectionsRepository = FakeMobileConnectionsRepository(mobileMappingsProxy) private val scope = CoroutineScope(IMMEDIATE) @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker @@ -69,7 +69,6 @@ class MobileIconsInteractorTest : SysuiTestCase() { MobileIconsInteractorImpl( connectionsRepository, carrierConfigTracker, - mobileMappingsProxy, userSetupRepository, scope ) From 9014672cd8ade57293a14fe6007510cf8114e2a0 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Sat, 3 Dec 2022 00:57:31 -0500 Subject: [PATCH 3/5] Rename MobileSubscriptionModel to MobileConnectionModel Also rename `subscriptionModelFlow` to `connectionInfo`, which is more clear given that `MobileConnectionRepository` is the provider of that information. This paves the way to remove `SubscriptionInfo` from our internal representation in lieu of a `SubscriptionModel` based off of it Test: tests in tests/src/com/android/systemui/statusbar/pipeline/mobile/* Bug: 261029387 Change-Id: If4bd3e31d2f8a7400e31e4acd8776750eee22ad6 --- ...ptionModel.kt => MobileConnectionModel.kt} | 2 +- .../repository/MobileConnectionRepository.kt | 4 +- .../demo/DemoMobileConnectionsRepository.kt | 10 ++-- .../prod/MobileConnectionRepositoryImpl.kt | 6 +- .../domain/interactor/MobileIconInteractor.kt | 20 +++---- .../FakeMobileConnectionRepository.kt | 10 ++-- .../DemoMobileConnectionParameterizedTest.kt | 18 +++--- .../DemoMobileConnectionsRepositoryTest.kt | 18 +++--- .../prod/MobileConnectionRepositoryTest.kt | 60 +++++++++---------- .../interactor/MobileIconInteractorTest.kt | 46 +++++++------- 10 files changed, 97 insertions(+), 97 deletions(-) rename packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/{MobileSubscriptionModel.kt => MobileConnectionModel.kt} (98%) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt similarity index 98% rename from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt rename to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt index 797a7285f877d..1d00c330c420f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt @@ -38,7 +38,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionS * any new field that needs to be tracked should be copied into this data class rather than * threading complex system objects through the pipeline. */ -data class MobileSubscriptionModel( +data class MobileConnectionModel( /** From [ServiceStateListener.onServiceStateChanged] */ val isEmergencyOnly: Boolean = false, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt index 90e531ce49dac..2621f997d4865 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt @@ -20,7 +20,7 @@ import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager import android.telephony.TelephonyCallback import android.telephony.TelephonyManager -import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @@ -42,7 +42,7 @@ interface MobileConnectionRepository { * A flow that aggregates all necessary callbacks from [TelephonyCallback] into a single * listener + model. */ - val subscriptionModelFlow: Flow + val connectionInfo: Flow /** Observable tracking [TelephonyManager.isDataConnectionAllowed] */ val dataEnabled: StateFlow /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt index 45b2c36021212..f1f42b8e33484 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt @@ -25,8 +25,8 @@ import com.android.settingslib.mobile.MobileMappings import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState +import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel -import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository @@ -206,7 +206,7 @@ constructor( connection.dataEnabled.value = true connection.isDefaultDataSubscription.value = state.dataType != null - connection.subscriptionModelFlow.value = state.toMobileSubscriptionModel() + connection.connectionInfo.value = state.toMobileConnectionModel() } private fun processDisabledMobileState(state: MobileDisabled) { @@ -246,8 +246,8 @@ constructor( private fun subIdsString(): String = _subscriptions.value.joinToString(",") { it.subscriptionId.toString() } - private fun Mobile.toMobileSubscriptionModel(): MobileSubscriptionModel { - return MobileSubscriptionModel( + private fun Mobile.toMobileConnectionModel(): MobileConnectionModel { + return MobileConnectionModel( isEmergencyOnly = false, // TODO(b/261029387): not yet supported isGsm = false, // TODO(b/261029387): not yet supported cdmaLevel = level ?: 0, @@ -275,7 +275,7 @@ constructor( } class DemoMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository { - override val subscriptionModelFlow = MutableStateFlow(MobileSubscriptionModel()) + override val connectionInfo = MutableStateFlow(MobileConnectionModel()) override val dataEnabled = MutableStateFlow(true) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index f6be228e0ea66..15505fd3d9e52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -31,7 +31,7 @@ import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType @@ -81,8 +81,8 @@ class MobileConnectionRepositoryImpl( private val telephonyCallbackEvent = MutableSharedFlow(extraBufferCapacity = 1) - override val subscriptionModelFlow: StateFlow = run { - var state = MobileSubscriptionModel() + override val connectionInfo: StateFlow = run { + var state = MobileConnectionModel() conflatedCallbackFlow { // TODO (b/240569788): log all of these into the connectivity logger val callback = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index 96c5597762578..8e1197ca7c5c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -69,7 +69,7 @@ class MobileIconInteractorImpl( override val isDefaultConnectionFailed: StateFlow, connectionRepository: MobileConnectionRepository, ) : MobileIconInteractor { - private val mobileStatusInfo = connectionRepository.subscriptionModelFlow + private val connectionInfo = connectionRepository.connectionInfo override val isDataEnabled: StateFlow = connectionRepository.dataEnabled @@ -78,7 +78,7 @@ class MobileIconInteractorImpl( /** Observable for the current RAT indicator icon ([MobileIconGroup]) */ override val networkTypeIconGroup: StateFlow = combine( - mobileStatusInfo, + connectionInfo, defaultMobileIconMapping, defaultMobileIconGroup, ) { info, mapping, defaultGroup -> @@ -87,18 +87,18 @@ class MobileIconInteractorImpl( .stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value) override val isEmergencyOnly: StateFlow = - mobileStatusInfo + connectionInfo .mapLatest { it.isEmergencyOnly } .stateIn(scope, SharingStarted.WhileSubscribed(), false) override val level: StateFlow = - mobileStatusInfo - .mapLatest { mobileModel -> + connectionInfo + .mapLatest { connection -> // TODO: incorporate [MobileMappings.Config.alwaysShowCdmaRssi] - if (mobileModel.isGsm) { - mobileModel.primaryLevel + if (connection.isGsm) { + connection.primaryLevel } else { - mobileModel.cdmaLevel + connection.cdmaLevel } } .stateIn(scope, SharingStarted.WhileSubscribed(), 0) @@ -110,7 +110,7 @@ class MobileIconInteractorImpl( override val numberOfLevels: StateFlow = MutableStateFlow(4) override val isDataConnected: StateFlow = - mobileStatusInfo - .mapLatest { subscriptionModel -> subscriptionModel.dataConnectionState == Connected } + connectionInfo + .mapLatest { connection -> connection.dataConnectionState == Connected } .stateIn(scope, SharingStarted.WhileSubscribed(), false) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt index fcd0f2b126ae1..5265ec66bc246 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt @@ -16,13 +16,13 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository -import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import kotlinx.coroutines.flow.MutableStateFlow // TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionRepository class FakeMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository { - private val _subscriptionsModelFlow = MutableStateFlow(MobileSubscriptionModel()) - override val subscriptionModelFlow = _subscriptionsModelFlow + private val _connectionInfo = MutableStateFlow(MobileConnectionModel()) + override val connectionInfo = _connectionInfo private val _dataEnabled = MutableStateFlow(true) override val dataEnabled = _dataEnabled @@ -30,8 +30,8 @@ class FakeMobileConnectionRepository(override val subId: Int) : MobileConnection private val _isDefaultDataSubscription = MutableStateFlow(true) override val isDefaultDataSubscription = _isDefaultDataSubscription - fun setMobileSubscriptionModel(model: MobileSubscriptionModel) { - _subscriptionsModelFlow.value = model + fun setConnectionInfo(model: MobileConnectionModel) { + _connectionInfo.value = model } fun setDataEnabled(enabled: Boolean) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt index bf5ecd895c409..e943de25c15fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt @@ -23,7 +23,7 @@ import com.android.settingslib.SignalIcon import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState -import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever @@ -109,18 +109,18 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC ) { when (model) { is FakeNetworkEventModel.Mobile -> { - val subscriptionModel: MobileSubscriptionModel = conn.subscriptionModelFlow.value + val connectionInfo: MobileConnectionModel = conn.connectionInfo.value assertThat(conn.subId).isEqualTo(model.subId) - assertThat(subscriptionModel.cdmaLevel).isEqualTo(model.level) - assertThat(subscriptionModel.primaryLevel).isEqualTo(model.level) - assertThat(subscriptionModel.dataActivityDirection).isEqualTo(model.activity) - assertThat(subscriptionModel.carrierNetworkChangeActive) + assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level) + assertThat(connectionInfo.primaryLevel).isEqualTo(model.level) + assertThat(connectionInfo.dataActivityDirection).isEqualTo(model.activity) + assertThat(connectionInfo.carrierNetworkChangeActive) .isEqualTo(model.carrierNetworkChange) // TODO(b/261029387): check these once we start handling them - assertThat(subscriptionModel.isEmergencyOnly).isFalse() - assertThat(subscriptionModel.isGsm).isFalse() - assertThat(subscriptionModel.dataConnectionState) + assertThat(connectionInfo.isEmergencyOnly).isFalse() + assertThat(connectionInfo.isGsm).isFalse() + assertThat(connectionInfo.dataConnectionState) .isEqualTo(DataConnectionState.Connected) } // MobileDisabled isn't combinatorial in nature, and is tested in diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt index a8f6993373d25..0eb28c1adf8ac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt @@ -24,7 +24,7 @@ import com.android.settingslib.SignalIcon import com.android.settingslib.mobile.TelephonyIcons.THREE_G import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState -import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled import com.android.systemui.util.mockito.mock @@ -266,18 +266,18 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { ) { when (model) { is FakeNetworkEventModel.Mobile -> { - val subscriptionModel: MobileSubscriptionModel = conn.subscriptionModelFlow.value + val connectionInfo: MobileConnectionModel = conn.connectionInfo.value assertThat(conn.subId).isEqualTo(model.subId) - assertThat(subscriptionModel.cdmaLevel).isEqualTo(model.level) - assertThat(subscriptionModel.primaryLevel).isEqualTo(model.level) - assertThat(subscriptionModel.dataActivityDirection).isEqualTo(model.activity) - assertThat(subscriptionModel.carrierNetworkChangeActive) + assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level) + assertThat(connectionInfo.primaryLevel).isEqualTo(model.level) + assertThat(connectionInfo.dataActivityDirection).isEqualTo(model.activity) + assertThat(connectionInfo.carrierNetworkChangeActive) .isEqualTo(model.carrierNetworkChange) // TODO(b/261029387) check these once we start handling them - assertThat(subscriptionModel.isEmergencyOnly).isFalse() - assertThat(subscriptionModel.isGsm).isFalse() - assertThat(subscriptionModel.dataConnectionState) + assertThat(connectionInfo.isEmergencyOnly).isFalse() + assertThat(connectionInfo.isGsm).isFalse() + assertThat(connectionInfo.dataConnectionState) .isEqualTo(DataConnectionState.Connected) } else -> {} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index 099cb660f6595..1fc9c60cd9ced 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -37,7 +37,7 @@ import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState -import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType @@ -107,10 +107,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_default() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(MobileSubscriptionModel()) + assertThat(latest).isEqualTo(MobileConnectionModel()) job.cancel() } @@ -118,8 +118,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_emergencyOnly() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val serviceState = ServiceState() serviceState.isEmergencyOnly = true @@ -134,8 +134,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_emergencyOnly_toggles() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() val serviceState = ServiceState() @@ -152,8 +152,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_signalStrengths_levelsUpdate() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() val strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true) @@ -169,8 +169,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_dataConnectionState_connected() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() @@ -184,8 +184,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_dataConnectionState_connecting() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() @@ -199,8 +199,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_dataConnectionState_disconnected() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() @@ -214,8 +214,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_dataConnectionState_disconnecting() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() @@ -229,8 +229,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_dataConnectionState_unknown() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() @@ -244,8 +244,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_dataActivity() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() callback.onDataActivity(3) @@ -258,8 +258,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun testFlowForSubId_carrierNetworkChange() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() callback.onCarrierNetworkChange(true) @@ -272,8 +272,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun subscriptionFlow_networkType_default() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val type = NETWORK_TYPE_UNKNOWN val expected = UnknownNetworkType @@ -286,8 +286,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun subscriptionFlow_networkType_updatesUsingDefault() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() val type = NETWORK_TYPE_LTE @@ -303,8 +303,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Test fun subscriptionFlow_networkType_updatesUsingOverride() = runBlocking(IMMEDIATE) { - var latest: MobileSubscriptionModel? = null - val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this) + var latest: MobileConnectionModel? = null + val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType() val type = OVERRIDE_NETWORK_TYPE_LTE_CA diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt index b20f8fb4c5022..fd41b5bebd390 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt @@ -24,7 +24,7 @@ import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState -import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository @@ -69,8 +69,8 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun gsm_level_default_unknown() = runBlocking(IMMEDIATE) { - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel(isGsm = true), + connectionRepository.setConnectionInfo( + MobileConnectionModel(isGsm = true), ) var latest: Int? = null @@ -84,8 +84,8 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun gsm_usesGsmLevel() = runBlocking(IMMEDIATE) { - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel( + connectionRepository.setConnectionInfo( + MobileConnectionModel( isGsm = true, primaryLevel = GSM_LEVEL, cdmaLevel = CDMA_LEVEL @@ -103,8 +103,8 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun cdma_level_default_unknown() = runBlocking(IMMEDIATE) { - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel(isGsm = false), + connectionRepository.setConnectionInfo( + MobileConnectionModel(isGsm = false), ) var latest: Int? = null @@ -117,8 +117,8 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun cdma_usesCdmaLevel() = runBlocking(IMMEDIATE) { - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel( + connectionRepository.setConnectionInfo( + MobileConnectionModel( isGsm = false, primaryLevel = GSM_LEVEL, cdmaLevel = CDMA_LEVEL @@ -136,8 +136,8 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun iconGroup_three_g() = runBlocking(IMMEDIATE) { - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel( + connectionRepository.setConnectionInfo( + MobileConnectionModel( resolvedNetworkType = DefaultNetworkType(THREE_G, mobileMappingsProxy.toIconKey(THREE_G)) ), @@ -154,8 +154,8 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun iconGroup_updates_on_change() = runBlocking(IMMEDIATE) { - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel( + connectionRepository.setConnectionInfo( + MobileConnectionModel( resolvedNetworkType = DefaultNetworkType(THREE_G, mobileMappingsProxy.toIconKey(THREE_G)) ), @@ -164,8 +164,8 @@ class MobileIconInteractorTest : SysuiTestCase() { var latest: MobileIconGroup? = null val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel( + connectionRepository.setConnectionInfo( + MobileConnectionModel( resolvedNetworkType = DefaultNetworkType( FOUR_G, @@ -183,8 +183,8 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun iconGroup_5g_override_type() = runBlocking(IMMEDIATE) { - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel( + connectionRepository.setConnectionInfo( + MobileConnectionModel( resolvedNetworkType = OverrideNetworkType( FIVE_G_OVERRIDE, @@ -204,8 +204,8 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun iconGroup_default_if_no_lookup() = runBlocking(IMMEDIATE) { - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel( + connectionRepository.setConnectionInfo( + MobileConnectionModel( resolvedNetworkType = DefaultNetworkType( NETWORK_TYPE_UNKNOWN, @@ -257,8 +257,8 @@ class MobileIconInteractorTest : SysuiTestCase() { var latest: Boolean? = null val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this) - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel(dataConnectionState = DataConnectionState.Connected) + connectionRepository.setConnectionInfo( + MobileConnectionModel(dataConnectionState = DataConnectionState.Connected) ) yield() @@ -273,8 +273,8 @@ class MobileIconInteractorTest : SysuiTestCase() { var latest: Boolean? = null val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this) - connectionRepository.setMobileSubscriptionModel( - MobileSubscriptionModel(dataConnectionState = DataConnectionState.Disconnected) + connectionRepository.setConnectionInfo( + MobileConnectionModel(dataConnectionState = DataConnectionState.Disconnected) ) assertThat(latest).isFalse() From bee622f1eb95fc7c2064616831f2ee7682a52983 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Sat, 3 Dec 2022 01:33:43 -0500 Subject: [PATCH 4/5] Add a SubscriptionModel We currently only need 2 bits from `SubscriptionInfo`: subscriptionId and isOpportunistic. This CL moves those into a `SubscriptionModel` class and updates all of the usages. Test: existing tests Bug: 249790009 Change-Id: I87686213e68b199b7d4c998f02d6687dcb276a27 --- .../mobile/data/model/SubscriptionModel.kt | 32 +++++++++++++++ .../repository/MobileConnectionsRepository.kt | 4 +- .../repository/MobileRepositorySwitcher.kt | 12 ++---- .../demo/DemoMobileConnectionsRepository.kt | 40 +++++-------------- .../prod/MobileConnectionsRepositoryImpl.kt | 15 +++++-- .../interactor/MobileIconsInteractor.kt | 10 ++--- .../pipeline/mobile/ui/MobileUiAdapter.kt | 4 +- .../FakeMobileConnectionsRepository.kt | 10 ++--- .../MobileRepositorySwitcherTest.kt | 11 +++-- .../DemoMobileConnectionsRepositoryTest.kt | 34 ++++++++-------- .../prod/MobileConnectionsRepositoryTest.kt | 23 ++++++----- .../interactor/FakeMobileIconsInteractor.kt | 7 ++-- .../interactor/MobileIconsInteractorTest.kt | 35 ++++++---------- 13 files changed, 124 insertions(+), 113 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt new file mode 100644 index 0000000000000..2f34516285cf2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt @@ -0,0 +1,32 @@ +/* + * 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.pipeline.mobile.data.model + +/** + * SystemUI representation of [SubscriptionInfo]. Currently we only use two fields on the + * subscriptions themselves: subscriptionId and isOpportunistic. Any new fields that we need can be + * added below and provided in the repository classes + */ +data class SubscriptionModel( + val subscriptionId: Int, + /** + * True if the subscription that this model represents has [SubscriptionInfo.isOpportunistic]. + * Opportunistic networks are networks with limited coverage, and we use this bit to determine + * filtering in certain cases. See [MobileIconsInteractor] for the filtering logic + */ + val isOpportunistic: Boolean = false, +) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt index 58ad423616e11..aea85eb020bd9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt @@ -17,10 +17,10 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository import android.provider.Settings -import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @@ -30,7 +30,7 @@ import kotlinx.coroutines.flow.StateFlow */ interface MobileConnectionsRepository { /** Observable list of current mobile subscriptions */ - val subscriptionsFlow: StateFlow> + val subscriptions: StateFlow> /** Observable for the subscriptionId of the current mobile data connection */ val activeMobileDataSubscriptionId: StateFlow diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt index 628f898abb236..d8e0e81837c10 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository import android.os.Bundle -import android.telephony.SubscriptionInfo import androidx.annotation.VisibleForTesting import com.android.settingslib.SignalIcon import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow @@ -25,6 +24,7 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.demomode.DemoMode import com.android.systemui.demomode.DemoModeController import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl import javax.inject.Inject @@ -109,14 +109,10 @@ constructor( } .stateIn(scope, SharingStarted.WhileSubscribed(), realRepository) - override val subscriptionsFlow: StateFlow> = + override val subscriptions: StateFlow> = activeRepo - .flatMapLatest { it.subscriptionsFlow } - .stateIn( - scope, - SharingStarted.WhileSubscribed(), - realRepository.subscriptionsFlow.value - ) + .flatMapLatest { it.subscriptions } + .stateIn(scope, SharingStarted.WhileSubscribed(), realRepository.subscriptions.value) override val activeMobileDataSubscriptionId: StateFlow = activeRepo diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt index f1f42b8e33484..b463796671b69 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo import android.content.Context -import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import android.util.Log import com.android.settingslib.SignalIcon @@ -29,6 +28,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectio import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel @@ -62,16 +62,16 @@ constructor( private var demoCommandJob: Job? = null private val connectionRepoCache = mutableMapOf() - private val subscriptionInfoCache = mutableMapOf() + private val subscriptionInfoCache = mutableMapOf() val demoModeFinishedEvent = MutableSharedFlow(extraBufferCapacity = 1) - private val _subscriptions = MutableStateFlow>(listOf()) - override val subscriptionsFlow = + private val _subscriptions = MutableStateFlow>(listOf()) + override val subscriptions = _subscriptions .onEach { infos -> dropUnusedReposFromCache(infos) } .stateIn(scope, SharingStarted.WhileSubscribed(), _subscriptions.value) - private fun dropUnusedReposFromCache(newInfos: List) { + private fun dropUnusedReposFromCache(newInfos: List) { // Remove any connection repository from the cache that isn't in the new set of IDs. They // will get garbage collected once their subscribers go away val currentValidSubscriptionIds = newInfos.map { it.subscriptionId } @@ -85,37 +85,17 @@ constructor( private fun maybeCreateSubscription(subId: Int) { if (!subscriptionInfoCache.containsKey(subId)) { - createSubscriptionForSubId(subId, subId).also { subscriptionInfoCache[subId] = it } + SubscriptionModel(subscriptionId = subId, isOpportunistic = false).also { + subscriptionInfoCache[subId] = it + } _subscriptions.value = subscriptionInfoCache.values.toList() } } - /** Mimics the old NetworkControllerImpl for now */ - private fun createSubscriptionForSubId(subId: Int, slotIndex: Int): SubscriptionInfo { - return SubscriptionInfo( - subId, - "", - slotIndex, - "", - "", - 0, - 0, - "", - 0, - null, - null, - null, - "", - false, - null, - null, - ) - } - // TODO(b/261029387): add a command for this value override val activeMobileDataSubscriptionId = - subscriptionsFlow + subscriptions .mapLatest { infos -> // For now, active is just the first in the list infos.firstOrNull()?.subscriptionId ?: INVALID_SUBSCRIPTION_ID @@ -123,7 +103,7 @@ constructor( .stateIn( scope, SharingStarted.WhileSubscribed(), - subscriptionsFlow.value.firstOrNull()?.subscriptionId ?: INVALID_SUBSCRIPTION_ID + subscriptions.value.firstOrNull()?.subscriptionId ?: INVALID_SUBSCRIPTION_ID ) /** Demo mode doesn't currently support modifications to the mobile mappings */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt index 6582c03d36d9e..5c0b40f073e83 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt @@ -45,6 +45,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy @@ -93,7 +94,7 @@ constructor( * [SubscriptionInfo]. We probably only need the [SubscriptionInfo.getSubscriptionId] of each * info object, but for now we keep track of the infos themselves. */ - override val subscriptionsFlow: StateFlow> = + override val subscriptions: StateFlow> = conflatedCallbackFlow { val callback = object : SubscriptionManager.OnSubscriptionsChangedListener() { @@ -109,7 +110,7 @@ constructor( awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) } } - .mapLatest { fetchSubscriptionsList() } + .mapLatest { fetchSubscriptionsList().map { it.toSubscriptionModel() } } .onEach { infos -> dropUnusedReposFromCache(infos) } .stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf()) @@ -239,7 +240,7 @@ constructor( .stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectivityModel()) private fun isValidSubId(subId: Int): Boolean { - subscriptionsFlow.value.forEach { + subscriptions.value.forEach { if (it.subscriptionId == subId) { return true } @@ -258,7 +259,7 @@ constructor( ) } - private fun dropUnusedReposFromCache(newInfos: List) { + private fun dropUnusedReposFromCache(newInfos: List) { // Remove any connection repository from the cache that isn't in the new set of IDs. They // will get garbage collected once their subscribers go away val currentValidSubscriptionIds = newInfos.map { it.subscriptionId } @@ -272,4 +273,10 @@ constructor( private suspend fun fetchSubscriptionsList(): List = withContext(bgDispatcher) { subscriptionManager.completeActiveSubscriptionInfoList } + + private fun SubscriptionInfo.toSubscriptionModel(): SubscriptionModel = + SubscriptionModel( + subscriptionId = subscriptionId, + isOpportunistic = isOpportunistic, + ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt index ada3b39620864..6f8fb2e2332b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt @@ -17,13 +17,13 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor import android.telephony.CarrierConfigManager -import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository @@ -52,7 +52,7 @@ import kotlinx.coroutines.flow.stateIn */ interface MobileIconsInteractor { /** List of subscriptions, potentially filtered for CBRS */ - val filteredSubscriptions: Flow> + val filteredSubscriptions: Flow> /** True if the active mobile data subscription has data enabled */ val activeDataConnectionHasDataEnabled: StateFlow /** The icon mapping from network type to [MobileIconGroup] for the default subscription */ @@ -100,8 +100,8 @@ constructor( .flatMapLatest { it?.dataEnabled ?: flowOf(false) } .stateIn(scope, SharingStarted.WhileSubscribed(), false) - private val unfilteredSubscriptions: Flow> = - mobileConnectionsRepo.subscriptionsFlow + private val unfilteredSubscriptions: Flow> = + mobileConnectionsRepo.subscriptions /** * Generally, SystemUI wants to show iconography for each subscription that is listed by @@ -116,7 +116,7 @@ constructor( * [CarrierConfigManager.KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN], * and by checking which subscription is opportunistic, or which one is active. */ - override val filteredSubscriptions: Flow> = + override val filteredSubscriptions: Flow> = combine(unfilteredSubscriptions, activeMobileDataSubscriptionId) { unfilteredSubs, activeId -> // Based on the old logic, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt index d9487bf922609..62fa723dbf04e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt @@ -56,8 +56,8 @@ constructor( private val statusBarPipelineFlags: StatusBarPipelineFlags, ) : CoreStartable { private val mobileSubIds: Flow> = - interactor.filteredSubscriptions.mapLatest { infos -> - infos.map { subscriptionInfo -> subscriptionInfo.subscriptionId } + interactor.filteredSubscriptions.mapLatest { subscriptions -> + subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId } } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt index af2dfb015e0be..d6af0e6b3a82d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt @@ -16,13 +16,13 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository -import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyManager import com.android.settingslib.SignalIcon import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import kotlinx.coroutines.flow.MutableStateFlow @@ -47,8 +47,8 @@ class FakeMobileConnectionsRepository(mobileMappings: MobileMappingsProxy) : LTE_ADVANCED_KEY to TelephonyIcons.NR_5G, ) - private val _subscriptionsFlow = MutableStateFlow>(listOf()) - override val subscriptionsFlow = _subscriptionsFlow + private val _subscriptions = MutableStateFlow>(listOf()) + override val subscriptions = _subscriptions private val _activeMobileDataSubscriptionId = MutableStateFlow(INVALID_SUBSCRIPTION_ID) override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId @@ -74,8 +74,8 @@ class FakeMobileConnectionsRepository(mobileMappings: MobileMappingsProxy) : private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON) override val defaultMobileIconGroup = _defaultMobileIconGroup - fun setSubscriptions(subs: List) { - _subscriptionsFlow.value = subs + fun setSubscriptions(subs: List) { + _subscriptions.value = subs } fun setDefaultDataSubId(id: Int) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt index 516896099491c..18ae90db881a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt @@ -24,6 +24,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.demomode.DemoMode import com.android.systemui.demomode.DemoModeController +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoModeMobileConnectionDataSource import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel @@ -158,15 +159,15 @@ class MobileRepositorySwitcherTest : SysuiTestCase() { whenever(subscriptionManager.completeActiveSubscriptionInfoList) .thenReturn(listOf(SUB_1, SUB_2)) - var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + var latest: List? = null + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) // The real subscriptions has 2 subs whenever(subscriptionManager.completeActiveSubscriptionInfoList) .thenReturn(listOf(SUB_1, SUB_2)) getSubscriptionCallback().onSubscriptionsChanged() - assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2)) + assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2)) // Demo mode turns on, and we should see only the demo subscriptions startDemoMode() @@ -179,7 +180,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() { finishDemoMode() - assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2)) + assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2)) job.cancel() } @@ -214,9 +215,11 @@ class MobileRepositorySwitcherTest : SysuiTestCase() { private const val SUB_1_ID = 1 private val SUB_1 = mock().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) } + private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID) private const val SUB_2_ID = 2 private val SUB_2 = mock().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) } + private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt index 0eb28c1adf8ac..4171cf39a5add 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo -import android.telephony.SubscriptionInfo import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID import androidx.test.filters.SmallTest @@ -25,6 +24,7 @@ import com.android.settingslib.mobile.TelephonyIcons.THREE_G import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled import com.android.systemui.util.mockito.mock @@ -73,8 +73,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun `network event - create new subscription`() = testScope.runTest { - var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + var latest: List? = null + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) assertThat(latest).isEmpty() @@ -89,8 +89,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun `network event - reuses subscription when same Id`() = testScope.runTest { - var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + var latest: List? = null + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) assertThat(latest).isEmpty() @@ -111,8 +111,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun `multiple subscriptions`() = testScope.runTest { - var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + var latest: List? = null + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) fakeNetworkEventFlow.value = validMobileEvent(subId = 1) fakeNetworkEventFlow.value = validMobileEvent(subId = 2) @@ -125,8 +125,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun `mobile disabled event - disables connection - subId specified - single conn`() = testScope.runTest { - var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + var latest: List? = null + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1) @@ -140,8 +140,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun `mobile disabled event - disables connection - subId not specified - single conn`() = testScope.runTest { - var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + var latest: List? = null + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1) @@ -155,8 +155,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun `mobile disabled event - disables connection - subId specified - multiple conn`() = testScope.runTest { - var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + var latest: List? = null + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1) fakeNetworkEventFlow.value = validMobileEvent(subId = 2, level = 1) @@ -171,8 +171,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun `mobile disabled event - subId not specified - multiple conn - ignores command`() = testScope.runTest { - var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + var latest: List? = null + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1) fakeNetworkEventFlow.value = validMobileEvent(subId = 2, level = 1) @@ -190,7 +190,7 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { var currentEvent: FakeNetworkEventModel = validMobileEvent(subId = 1) var connections: List? = null val job = - underTest.subscriptionsFlow + underTest.subscriptions .onEach { infos -> connections = infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) } @@ -222,7 +222,7 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { var connection2: DemoMobileConnectionRepository? = null var connections: List? = null val job = - underTest.subscriptionsFlow + underTest.subscriptions .onEach { infos -> connections = infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt index 68d85ccca9760..7870807b93bf9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt @@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest import com.android.internal.telephony.PhoneConstants import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.util.mockito.any @@ -99,21 +100,21 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun testSubscriptions_initiallyEmpty() = runBlocking(IMMEDIATE) { - assertThat(underTest.subscriptionsFlow.value).isEqualTo(listOf()) + assertThat(underTest.subscriptions.value).isEqualTo(listOf()) } @Test fun testSubscriptions_listUpdates() = runBlocking(IMMEDIATE) { - var latest: List? = null + var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) whenever(subscriptionManager.completeActiveSubscriptionInfoList) .thenReturn(listOf(SUB_1, SUB_2)) getSubscriptionCallback().onSubscriptionsChanged() - assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2)) + assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2)) job.cancel() } @@ -121,9 +122,9 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun testSubscriptions_removingSub_updatesList() = runBlocking(IMMEDIATE) { - var latest: List? = null + var latest: List? = null - val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this) + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) // WHEN 2 networks show up whenever(subscriptionManager.completeActiveSubscriptionInfoList) @@ -136,7 +137,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { getSubscriptionCallback().onSubscriptionsChanged() // THEN the subscriptions list represents the newest change - assertThat(latest).isEqualTo(listOf(SUB_2)) + assertThat(latest).isEqualTo(listOf(MODEL_2)) job.cancel() } @@ -166,7 +167,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun testConnectionRepository_validSubId_isCached() = runBlocking(IMMEDIATE) { - val job = underTest.subscriptionsFlow.launchIn(this) + val job = underTest.subscriptions.launchIn(this) whenever(subscriptionManager.completeActiveSubscriptionInfoList) .thenReturn(listOf(SUB_1)) @@ -183,7 +184,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun testConnectionCache_clearsInvalidSubscriptions() = runBlocking(IMMEDIATE) { - val job = underTest.subscriptionsFlow.launchIn(this) + val job = underTest.subscriptions.launchIn(this) whenever(subscriptionManager.completeActiveSubscriptionInfoList) .thenReturn(listOf(SUB_1, SUB_2)) @@ -209,7 +210,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { @Test fun testConnectionRepository_invalidSubId_throws() = runBlocking(IMMEDIATE) { - val job = underTest.subscriptionsFlow.launchIn(this) + val job = underTest.subscriptions.launchIn(this) assertThrows(IllegalArgumentException::class.java) { underTest.getRepoForSubId(SUB_1_ID) @@ -375,10 +376,12 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { private const val SUB_1_ID = 1 private val SUB_1 = mock().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) } + private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID) private const val SUB_2_ID = 2 private val SUB_2 = mock().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) } + private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID) private const val NET_ID = 123 private val NETWORK = mock().apply { whenever(getNetId()).thenReturn(NET_ID) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt index 061c3b54650e6..0d4044db71e03 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt @@ -16,14 +16,15 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor -import android.telephony.SubscriptionInfo import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO import android.telephony.TelephonyManager.NETWORK_TYPE_GSM import android.telephony.TelephonyManager.NETWORK_TYPE_LTE import android.telephony.TelephonyManager.NETWORK_TYPE_UMTS import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.settingslib.mobile.TelephonyIcons +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow class FakeMobileIconsInteractor(mobileMappings: MobileMappingsProxy) : MobileIconsInteractor { @@ -47,8 +48,8 @@ class FakeMobileIconsInteractor(mobileMappings: MobileMappingsProxy) : MobileIco override val isDefaultConnectionFailed = MutableStateFlow(false) - private val _filteredSubscriptions = MutableStateFlow>(listOf()) - override val filteredSubscriptions = _filteredSubscriptions + private val _filteredSubscriptions = MutableStateFlow>(listOf()) + override val filteredSubscriptions: Flow> = _filteredSubscriptions private val _activeDataConnectionHasDataEnabled = MutableStateFlow(false) override val activeDataConnectionHasDataEnabled = _activeDataConnectionHasDataEnabled diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index 4e950f5211ace..58e57e298e512 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -16,17 +16,16 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor -import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel +import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.util.CarrierConfigTracker -import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope @@ -79,10 +78,10 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_default() = runBlocking(IMMEDIATE) { - var latest: List? = null + var latest: List? = null val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(listOf()) + assertThat(latest).isEqualTo(listOf()) job.cancel() } @@ -92,7 +91,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { runBlocking(IMMEDIATE) { connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2)) - var latest: List? = null + var latest: List? = null val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2)) @@ -108,7 +107,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(false) - var latest: List? = null + var latest: List? = null val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) // Filtered subscriptions should show the active one when the config is false @@ -125,7 +124,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(false) - var latest: List? = null + var latest: List? = null val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) // Filtered subscriptions should show the active one when the config is false @@ -142,7 +141,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(true) - var latest: List? = null + var latest: List? = null val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) // Filtered subscriptions should show the primary (non-opportunistic) if the config is @@ -160,7 +159,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(true) - var latest: List? = null + var latest: List? = null val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) // Filtered subscriptions should show the primary (non-opportunistic) if the config is @@ -260,29 +259,19 @@ class MobileIconsInteractorTest : SysuiTestCase() { private val IMMEDIATE = Dispatchers.Main.immediate private const val SUB_1_ID = 1 - private val SUB_1 = - mock().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) } + private val SUB_1 = SubscriptionModel(subscriptionId = SUB_1_ID) private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID) private const val SUB_2_ID = 2 - private val SUB_2 = - mock().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) } + private val SUB_2 = SubscriptionModel(subscriptionId = SUB_2_ID) private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID) private const val SUB_3_ID = 3 - private val SUB_3_OPP = - mock().also { - whenever(it.subscriptionId).thenReturn(SUB_3_ID) - whenever(it.isOpportunistic).thenReturn(true) - } + private val SUB_3_OPP = SubscriptionModel(subscriptionId = SUB_3_ID, isOpportunistic = true) private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID) private const val SUB_4_ID = 4 - private val SUB_4_OPP = - mock().also { - whenever(it.subscriptionId).thenReturn(SUB_4_ID) - whenever(it.isOpportunistic).thenReturn(true) - } + private val SUB_4_OPP = SubscriptionModel(subscriptionId = SUB_4_ID, isOpportunistic = true) private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID) } } From 25ac426406355636c178e1e43c81cce9fe188d75 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Wed, 7 Dec 2022 09:13:17 -0500 Subject: [PATCH 5/5] [Status bar refactor] Fix cache removal exception The old method of removing unused subscriptions from the repo cache was causing a CME Test: DemoMobileConnectionsRepositoryTest Test: MobileConnectionsRepositoryTest Fixes: 261706421 Change-Id: I4977aa47591a7d4888c176e420cc1a0c7f783591 --- .../demo/DemoMobileConnectionsRepository.kt | 11 ++--- .../prod/MobileConnectionsRepositoryImpl.kt | 11 ++--- .../DemoMobileConnectionsRepositoryTest.kt | 19 ++++++++ .../prod/MobileConnectionsRepositoryTest.kt | 47 ++++++++++++++++++- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt index b463796671b69..1e7fae717a2de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt @@ -61,7 +61,7 @@ constructor( private var demoCommandJob: Job? = null - private val connectionRepoCache = mutableMapOf() + private var connectionRepoCache = mutableMapOf() private val subscriptionInfoCache = mutableMapOf() val demoModeFinishedEvent = MutableSharedFlow(extraBufferCapacity = 1) @@ -76,11 +76,10 @@ constructor( // will get garbage collected once their subscribers go away val currentValidSubscriptionIds = newInfos.map { it.subscriptionId } - connectionRepoCache.keys.forEach { - if (!currentValidSubscriptionIds.contains(it)) { - connectionRepoCache.remove(it) - } - } + connectionRepoCache = + connectionRepoCache + .filter { currentValidSubscriptionIds.contains(it.key) } + .toMutableMap() } private fun maybeCreateSubscription(subId: Int) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt index 5c0b40f073e83..f27a9c9cca987 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt @@ -87,7 +87,7 @@ constructor( @Application private val scope: CoroutineScope, private val mobileConnectionRepositoryFactory: MobileConnectionRepositoryImpl.Factory ) : MobileConnectionsRepository { - private val subIdRepositoryCache: MutableMap = mutableMapOf() + private var subIdRepositoryCache: MutableMap = mutableMapOf() /** * State flow that emits the set of mobile data subscriptions, each represented by its own @@ -264,11 +264,10 @@ constructor( // will get garbage collected once their subscribers go away val currentValidSubscriptionIds = newInfos.map { it.subscriptionId } - subIdRepositoryCache.keys.forEach { - if (!currentValidSubscriptionIds.contains(it)) { - subIdRepositoryCache.remove(it) - } - } + subIdRepositoryCache = + subIdRepositoryCache + .filter { currentValidSubscriptionIds.contains(it.key) } + .toMutableMap() } private suspend fun fetchSubscriptionsList(): List = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt index 4171cf39a5add..32d0410d589d8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt @@ -184,6 +184,25 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() { job.cancel() } + /** Regression test for b/261706421 */ + @Test + fun `multiple connections - remove all - does not throw`() = + testScope.runTest { + var latest: List? = null + val job = underTest.subscriptions.onEach { latest = it }.launchIn(this) + + // Two subscriptions are added + fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1) + fakeNetworkEventFlow.value = validMobileEvent(subId = 2, level = 1) + + // Then both are removed by turning off demo mode + underTest.stopProcessingCommands() + + assertThat(latest).isEmpty() + + job.cancel() + } + @Test fun `demo connection - single subscription`() = testScope.runTest { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt index 7870807b93bf9..4b82b398360d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt @@ -52,6 +52,7 @@ import org.junit.After import org.junit.Assert.assertThrows import org.junit.Before import org.junit.Test +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -76,6 +77,24 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) + // Set up so the individual connection repositories + whenever(telephonyManager.createForSubscriptionId(anyInt())).thenAnswer { invocation -> + telephonyManager.also { + whenever(telephonyManager.subscriptionId).thenReturn(invocation.getArgument(0)) + } + } + + val connectionFactory: MobileConnectionRepositoryImpl.Factory = + MobileConnectionRepositoryImpl.Factory( + context = context, + telephonyManager = telephonyManager, + bgDispatcher = IMMEDIATE, + globalSettings = globalSettings, + logger = logger, + mobileMappingsProxy = mobileMappings, + scope = scope, + ) + underTest = MobileConnectionsRepositoryImpl( connectivityManager, @@ -88,7 +107,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { context, IMMEDIATE, scope, - mock(), + connectionFactory, ) } @@ -207,6 +226,32 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { job.cancel() } + /** Regression test for b/261706421 */ + @Test + fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() = + runBlocking(IMMEDIATE) { + val job = underTest.subscriptions.launchIn(this) + + whenever(subscriptionManager.completeActiveSubscriptionInfoList) + .thenReturn(listOf(SUB_1, SUB_2)) + getSubscriptionCallback().onSubscriptionsChanged() + + // Get repos to trigger caching + val repo1 = underTest.getRepoForSubId(SUB_1_ID) + val repo2 = underTest.getRepoForSubId(SUB_2_ID) + + assertThat(underTest.getSubIdRepoCache()) + .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2) + + // All subscriptions disappear + whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf()) + getSubscriptionCallback().onSubscriptionsChanged() + + assertThat(underTest.getSubIdRepoCache()).isEmpty() + + job.cancel() + } + @Test fun testConnectionRepository_invalidSubId_throws() = runBlocking(IMMEDIATE) {