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) } }