diff options
9 files changed, 127 insertions, 12 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt index 4759c081de5f..183cd8f1ae8b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt @@ -19,6 +19,9 @@ package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel import android.graphics.Color import android.graphics.Rect import android.view.View +import androidx.compose.runtime.getValue +import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.lifecycle.Hydrator import com.android.systemui.plugins.DarkIconDispatcher import com.android.systemui.statusbar.chips.mediaprojection.domain.model.MediaProjectionStopDialogModel import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel @@ -26,15 +29,20 @@ import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChip import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel +import com.android.systemui.statusbar.phone.domain.interactor.IsAreaDark +import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel import com.android.systemui.statusbar.pipeline.shared.ui.model.SystemInfoCombinedVisibilityModel import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import org.mockito.Mockito.mock class FakeHomeStatusBarViewModel( override val operatorNameViewModel: StatusBarOperatorNameViewModel -) : HomeStatusBarViewModel { +) : HomeStatusBarViewModel, ExclusiveActivatable() { + private val hydrator = Hydrator("FakeHomeStatusBarViewModel.hydrator") + override val areNotificationsLightsOut = MutableStateFlow(false) override val isTransitioningFromLockscreenToOccluded = MutableStateFlow(false) @@ -56,6 +64,11 @@ class FakeHomeStatusBarViewModel( override val isHomeStatusBarAllowedByScene = MutableStateFlow(false) + override val batteryViewModelFactory: BatteryViewModel.Factory = + object : BatteryViewModel.Factory { + override fun create(): BatteryViewModel = mock(BatteryViewModel::class.java) + } + override val shouldShowOperatorNameView = MutableStateFlow(false) override val isClockVisible = @@ -80,6 +93,7 @@ class FakeHomeStatusBarViewModel( var darkIconTint = Color.BLACK var lightIconTint = Color.WHITE + var darkIntensity = 0f override val areaTint: Flow<StatusBarTintColor> = MutableStateFlow( @@ -91,4 +105,22 @@ class FakeHomeStatusBarViewModel( } } ) + + val isAreaDarkSource = + MutableStateFlow( + IsAreaDark { viewBounds -> + if (DarkIconDispatcher.isInAreas(darkRegions, viewBounds)) { + darkIntensity < 0.5f + } else { + false + } + } + ) + + override val areaDark: IsAreaDark by + hydrator.hydratedStateOf(traceName = "areaDark", source = isAreaDarkSource) + + override suspend fun onActivated(): Nothing { + hydrator.activate() + } } diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml index c28dc50cc1dc..bb99d581c0b0 100644 --- a/packages/SystemUI/res/layout/system_icons.xml +++ b/packages/SystemUI/res/layout/system_icons.xml @@ -34,12 +34,17 @@ android:orientation="horizontal"/> <!-- PaddingEnd is added to balance hover padding, compensating for paddingStart in statusIcons. - See b/339589733 --> + See b/339589733. + + Default visibility is now "gone" to make space for the new battery icon + --> <com.android.systemui.battery.BatteryMeterView android:id="@+id/battery" android:layout_height="wrap_content" android:layout_width="wrap_content" android:clipToPadding="false" android:clipChildren="false" android:paddingEnd="@dimen/status_bar_battery_end_padding" + android:visibility="gone" systemui:textAppearance="@style/TextAppearance.StatusBar.Clock" /> + </LinearLayout> diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java index 9a30c213a2f9..fcf51051940c 100644 --- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java +++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java @@ -46,7 +46,10 @@ import java.io.PrintWriter; import javax.inject.Inject; -/** Controller for {@link BatteryMeterView}. **/ +/** + * Controller for {@link BatteryMeterView}. + * @deprecated once [NewStatusBarIcons] is rolled out, this class is no longer needed + */ public class BatteryMeterViewController extends ViewController<BatteryMeterView> { private final ConfigurationController mConfigurationController; private final TunerService mTunerService; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java index 7207d0aef3ee..4d531b512dd9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java @@ -20,6 +20,7 @@ import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.dagger.qualifiers.DisplaySpecific; import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.plugins.DarkIconDispatcher; +import com.android.systemui.statusbar.core.NewStatusBarIcons; import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController; import com.android.systemui.statusbar.layout.StatusBarBoundsProvider; import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor; @@ -85,7 +86,9 @@ public interface HomeStatusBarComponent { default void init() { // No one accesses these controllers, so we need to make sure we reference them here so they // do get initialized. - getBatteryMeterViewController().init(); + if (!NewStatusBarIcons.isEnabled()) { + getBatteryMeterViewController().init(); + } getHeadsUpAppearanceController().init(); getPhoneStatusBarViewController().init(); if (!NotificationsLiveDataStoreRefactor.isEnabled()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModel.kt index d0d099e74cb1..afd4bb1f36c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModel.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.battery.ui.viewmodel import android.content.Context import androidx.compose.runtime.getValue +import androidx.compose.ui.unit.dp import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.lifecycle.ExclusiveActivatable @@ -223,6 +224,10 @@ constructor(interactor: BatteryInteractor, @Application context: Context) : Excl } companion object { + // Status bar battery height, based on a 21x12 base canvas + val STATUS_BAR_BATTERY_HEIGHT = 13.dp + val STATUS_BAR_BATTERY_WIDTH = 22.75.dp + fun Int.glyphRepresentation(): List<BatteryGlyph> = toString().map { it.toGlyph() } private fun Char.toGlyph(): BatteryGlyph = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt index 9d72daf01831..c34fa464cc3a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt @@ -23,6 +23,8 @@ import android.widget.LinearLayout import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment @@ -34,9 +36,11 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.theme.PlatformTheme import com.android.keyguard.AlphaOptimizedLinearLayout +import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.plugins.DarkIconDispatcher import com.android.systemui.res.R import com.android.systemui.statusbar.chips.ui.compose.OngoingActivityChips +import com.android.systemui.statusbar.core.NewStatusBarIcons import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore import com.android.systemui.statusbar.events.domain.interactor.SystemStatusEventAnimationInteractor @@ -51,6 +55,9 @@ import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.statusbar.phone.ui.DarkIconManager import com.android.systemui.statusbar.phone.ui.StatusBarIconController +import com.android.systemui.statusbar.pipeline.battery.ui.composable.UnifiedBattery +import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel.Companion.STATUS_BAR_BATTERY_HEIGHT +import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel.Companion.STATUS_BAR_BATTERY_WIDTH import com.android.systemui.statusbar.pipeline.shared.ui.binder.HomeStatusBarIconBlockListBinder import com.android.systemui.statusbar.pipeline.shared.ui.binder.HomeStatusBarViewBinder import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel @@ -73,14 +80,13 @@ constructor( ) { fun create(root: ViewGroup, andThen: (ViewGroup) -> Unit): ComposeView { val composeView = ComposeView(root.context) - val displayId = root.context.displayId val darkIconDispatcher = darkIconDispatcherStore.forDisplay(root.context.displayId) ?: return composeView composeView.apply { setContent { StatusBarRoot( parent = root, - statusBarViewModel = homeStatusBarViewModelFactory.create(displayId), + statusBarViewModelFactory = homeStatusBarViewModelFactory, statusBarViewBinder = homeStatusBarViewBinder, notificationIconsBinder = notificationIconsBinder, darkIconManagerFactory = darkIconManagerFactory, @@ -110,7 +116,7 @@ constructor( @Composable fun StatusBarRoot( parent: ViewGroup, - statusBarViewModel: HomeStatusBarViewModel, + statusBarViewModelFactory: HomeStatusBarViewModelFactory, statusBarViewBinder: HomeStatusBarViewBinder, notificationIconsBinder: NotificationIconContainerStatusBarViewBinder, darkIconManagerFactory: DarkIconManager.Factory, @@ -120,6 +126,10 @@ fun StatusBarRoot( eventAnimationInteractor: SystemStatusEventAnimationInteractor, onViewCreated: (ViewGroup) -> Unit, ) { + val displayId = parent.context.displayId + val statusBarViewModel = + rememberViewModel("HomeStatusBar") { statusBarViewModelFactory.create(displayId) } + Box(Modifier.fillMaxSize()) { // TODO(b/364360986): remove this before rolling the flag forward if (StatusBarRootModernization.SHOW_DISAMBIGUATION) { @@ -159,10 +169,6 @@ fun StatusBarRoot( LinearLayout.LayoutParams.WRAP_CONTENT, ) - setViewCompositionStrategy( - ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed - ) - setContent { PlatformTheme { val chips by @@ -241,6 +247,12 @@ fun StatusBarRoot( endSideContent.addView(composeView, 0) } + // If the flag is enabled, create and add a compose battery view to the end + // of the system_icons container + if (NewStatusBarIcons.isEnabled) { + addBatteryComposable(phoneStatusBarView, statusBarViewModel) + } + notificationIconsBinder.bindWhileAttached( notificationIconContainer, context.displayId, @@ -263,6 +275,27 @@ fun StatusBarRoot( } } +/** Create a new [UnifiedBattery] and add it to the end of the system_icons container */ +private fun addBatteryComposable( + phoneStatusBarView: PhoneStatusBarView, + statusBarViewModel: HomeStatusBarViewModel, +) { + val batteryComposeView = + ComposeView(phoneStatusBarView.context).apply { + setContent { + UnifiedBattery( + modifier = + Modifier.height(STATUS_BAR_BATTERY_HEIGHT).width(STATUS_BAR_BATTERY_WIDTH), + viewModelFactory = statusBarViewModel.batteryViewModelFactory, + isDark = statusBarViewModel.areaDark, + ) + } + } + phoneStatusBarView.findViewById<ViewGroup>(R.id.system_icons).apply { + addView(batteryComposeView, -1) + } +} + /** * This is our analog of the flexi "ribbon", which just shows some text so we know if the flag is on */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt index 1bc45a95044c..f396cbfc8000 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel import android.annotation.ColorInt import android.graphics.Rect import android.view.View +import androidx.compose.runtime.getValue import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor @@ -28,6 +29,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.lifecycle.Hydrator import com.android.systemui.log.table.TableLogBufferFactory import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.plugins.DarkIconDispatcher @@ -55,8 +58,10 @@ import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNoti import com.android.systemui.statusbar.notification.headsup.PinnedStatus import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor import com.android.systemui.statusbar.phone.domain.interactor.DarkIconInteractor +import com.android.systemui.statusbar.phone.domain.interactor.IsAreaDark import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel import com.android.systemui.statusbar.pipeline.shared.domain.interactor.HomeStatusBarIconBlockListInteractor import com.android.systemui.statusbar.pipeline.shared.domain.interactor.HomeStatusBarInteractor import com.android.systemui.statusbar.pipeline.shared.ui.model.SystemInfoCombinedVisibilityModel @@ -90,6 +95,9 @@ import kotlinx.coroutines.flow.stateIn * so that it's all in one place and easily testable outside of the fragment. */ interface HomeStatusBarViewModel { + /** Factory to create the view model for the battery icon */ + val batteryViewModelFactory: BatteryViewModel.Factory + /** * True if the device is currently transitioning from lockscreen to occluded and false * otherwise. @@ -171,6 +179,9 @@ interface HomeStatusBarViewModel { */ val areaTint: Flow<StatusBarTintColor> + /** [IsAreaDark] applicable for this status bar's display and content area */ + val areaDark: IsAreaDark + /** Interface for the assisted factory, to allow for providing a fake in tests */ interface HomeStatusBarViewModelFactory { fun create(displayId: Int): HomeStatusBarViewModel @@ -181,6 +192,7 @@ class HomeStatusBarViewModelImpl @AssistedInject constructor( @Assisted thisDisplayId: Int, + override val batteryViewModelFactory: BatteryViewModel.Factory, tableLoggerFactory: TableLogBufferFactory, homeStatusBarInteractor: HomeStatusBarInteractor, homeStatusBarIconBlockListInteractor: HomeStatusBarIconBlockListInteractor, @@ -201,7 +213,9 @@ constructor( statusBarContentInsetsViewModelStore: StatusBarContentInsetsViewModelStore, @Background bgScope: CoroutineScope, @Background bgDispatcher: CoroutineDispatcher, -) : HomeStatusBarViewModel { +) : HomeStatusBarViewModel, ExclusiveActivatable() { + + private val hydrator = Hydrator(traceName = "HomeStatusBarViewModel.hydrator") val tableLogger = tableLoggerFactory.getOrCreate(tableLogBufferName(thisDisplayId), 200) @@ -294,6 +308,13 @@ constructor( .distinctUntilChanged() .flowOn(bgDispatcher) + override val areaDark: IsAreaDark by + hydrator.hydratedStateOf( + traceName = "areaDark", + initialValue = IsAreaDark { true }, + source = darkIconInteractor.isAreaDark(thisDisplayId), + ) + /** * True if the current SysUI state can show the home status bar (aka this status bar), and false * if we shouldn't be showing any part of the home status bar. @@ -473,6 +494,10 @@ constructor( @View.Visibility private fun Boolean.toVisibleOrInvisible(): Int = if (this) View.VISIBLE else View.INVISIBLE + override suspend fun onActivated(): Nothing { + hydrator.activate() + } + /** Inject this to create the display-dependent view model */ @AssistedFactory interface HomeStatusBarViewModelFactoryImpl : diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelKosmos.kt index c6cf0063986a..7dd0103e9f5a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelKosmos.kt @@ -22,3 +22,10 @@ import com.android.systemui.statusbar.pipeline.battery.domain.interactor.battery val Kosmos.batteryViewModel by Kosmos.Fixture { BatteryViewModel(batteryInteractor, testableContext) } + +val Kosmos.batteryViewModelFactory by + Kosmos.Fixture { + object : BatteryViewModel.Factory { + override fun create(): BatteryViewModel = batteryViewModel + } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt index bc29dba3442c..fbada934c9d4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.notification.domain.interactor.activeNotif import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor import com.android.systemui.statusbar.phone.domain.interactor.darkIconInteractor import com.android.systemui.statusbar.phone.domain.interactor.lightsOutInteractor +import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.batteryViewModelFactory import com.android.systemui.statusbar.pipeline.shared.domain.interactor.homeStatusBarIconBlockListInteractor import com.android.systemui.statusbar.pipeline.shared.domain.interactor.homeStatusBarInteractor @@ -42,6 +43,7 @@ var Kosmos.homeStatusBarViewModel: HomeStatusBarViewModel by Kosmos.Fixture { HomeStatusBarViewModelImpl( testableContext.displayId, + batteryViewModelFactory, tableLogBufferFactory, homeStatusBarInteractor, homeStatusBarIconBlockListInteractor, |