Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a2bbf95 authored by burakov's avatar burakov
Browse files

[flexiglass] Use the new compose battery icon in the shade header.

This is a re-implementation of ag/32105358.

Fix: 414597673
Fix: 413766503
Test: atest ShadeHeaderViewModelTest
Test: Manually tested by opening the shade with the old and new
 icon enabled, and observing it is rendered correctly in both cases.
Flag: com.android.systemui.scene_container
Flag: com.android.settingslib.flags.new_status_bar_icons
Change-Id: Iba184e50c0f6cedfdfe2ffce98a70e6d3860d99e
parent 151c0f2b
Loading
Loading
Loading
Loading
+33 −15
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.core.NewStatusBarIcons
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.pipeline.battery.ui.composable.BatteryWithEstimate
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModelKairosComposeWrapper
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
@@ -172,7 +173,7 @@ object ShadeHeader {
    }
}

/** The status bar that appears above the Shade scene on small screens */
/** The status bar that appears above the Shade scene on small screens. */
@Composable
fun ContentScope.CollapsedShadeHeader(
    viewModel: ShadeHeaderViewModel,
@@ -243,8 +244,7 @@ fun ContentScope.CollapsedShadeHeader(
                            modifier = Modifier.padding(end = paddingEnd).weight(1f, fill = false),
                        )
                        BatteryIcon(
                            createBatteryMeterViewController =
                                viewModel.createBatteryMeterViewController,
                            viewModel = viewModel,
                            useExpandedFormat = useExpandedTextFormat,
                            modifier = Modifier.padding(vertical = 8.dp),
                        )
@@ -255,7 +255,7 @@ fun ContentScope.CollapsedShadeHeader(
    )
}

/** The status bar that appears above the Quick Settings scene on small screens */
/** The status bar that appears above the Quick Settings scene on small screens. */
@Composable
fun ContentScope.ExpandedShadeHeader(
    viewModel: ShadeHeaderViewModel,
@@ -316,11 +316,7 @@ fun ContentScope.ExpandedShadeHeader(
                        useExpandedFormat = useExpandedFormat,
                        modifier = Modifier.padding(end = paddingEnd).weight(1f, fill = false),
                    )
                    BatteryIcon(
                        useExpandedFormat = useExpandedFormat,
                        createBatteryMeterViewController =
                            viewModel.createBatteryMeterViewController,
                    )
                    BatteryIcon(viewModel = viewModel, useExpandedFormat = useExpandedFormat)
                }
            }
        }
@@ -413,8 +409,7 @@ fun ContentScope.OverlayShadeHeader(
                        isHighlighted = isHighlighted,
                    )
                    BatteryIcon(
                        createBatteryMeterViewController =
                            viewModel.createBatteryMeterViewController,
                        viewModel = viewModel,
                        useExpandedFormat = false,
                        isHighlighted = isHighlighted,
                    )
@@ -441,10 +436,7 @@ fun QuickSettingsOverlayHeader(viewModel: ShadeHeaderViewModel, modifier: Modifi
        modifier = modifier.fillMaxWidth(),
    ) {
        ShadeCarrierGroup(viewModel = viewModel)
        BatteryIcon(
            createBatteryMeterViewController = viewModel.createBatteryMeterViewController,
            useExpandedFormat = true,
        )
        BatteryIcon(viewModel = viewModel, useExpandedFormat = true)
    }
}

@@ -547,11 +539,37 @@ private fun ContentScope.Clock(

@Composable
private fun BatteryIcon(
    viewModel: ShadeHeaderViewModel,
    useExpandedFormat: Boolean,
    modifier: Modifier = Modifier,
    isHighlighted: Boolean = false,
) {
    if (NewStatusBarIcons.isEnabled) {
        BatteryWithEstimate(
            viewModelFactory = viewModel.batteryViewModelFactory,
            isDarkProvider = { viewModel.isShadeAreaDark },
            showEstimate = useExpandedFormat,
            modifier = modifier,
        )
    } else {
        BatteryIconLegacy(
            createBatteryMeterViewController = viewModel.createBatteryMeterViewController,
            useExpandedFormat = useExpandedFormat,
            modifier = modifier,
            isHighlighted = isHighlighted,
        )
    }
}

@Composable
private fun BatteryIconLegacy(
    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
    useExpandedFormat: Boolean,
    modifier: Modifier = Modifier,
    isHighlighted: Boolean = false,
) {
    NewStatusBarIcons.assertInLegacyMode()

    val localContext = LocalContext.current
    val themedContext =
        ContextThemeWrapper(localContext, R.style.Theme_SystemUI_QuickSettings_Header)
+1 −1
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ abstract class ExclusiveActivatable : Activatable {

    final override suspend fun activate(): Nothing {
        val allowed = _isActive.compareAndSet(false, true)
        check(allowed) { "Cannot activate an already active ExclusiveActivatable!" }
        check(allowed) { "Cannot activate an already active ExclusiveActivatable! $this" }

        try {
            onActivated()
+7 −0
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackRebind
import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHiderImpl
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
import com.android.systemui.statusbar.phone.ConfigurationForwarder
import com.android.systemui.statusbar.phone.domain.interactor.ShadeDarkIconInteractor
import com.android.systemui.statusbar.phone.domain.interactor.ShadeDarkIconInteractorImpl
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.utils.windowmanager.WindowManagerProvider
import com.android.window.flags.Flags
@@ -341,6 +343,11 @@ object ShadeDisplayAwareWithShadeWindowModule {
    fun bindNotificationStackRebindingHider(
        impl: NotificationStackRebindingHiderImpl
    ): NotificationStackRebindingHider = impl

    @Provides
    @SysUISingleton
    fun bindShadeDarkIconInteractor(impl: ShadeDarkIconInteractorImpl): ShadeDarkIconInteractor =
        impl
}

/**
+12 −0
Original line number Diff line number Diff line
@@ -48,8 +48,11 @@ import com.android.systemui.shade.domain.interactor.ShadeHeaderClockInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.phone.domain.interactor.IsAreaDark
import com.android.systemui.statusbar.phone.domain.interactor.ShadeDarkIconInteractor
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.UnifiedBatteryViewModel
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModelKairos
@@ -75,6 +78,7 @@ constructor(
    private val sceneInteractor: SceneInteractor,
    private val shadeInteractor: ShadeInteractor,
    private val shadeModeInteractor: ShadeModeInteractor,
    shadeDarkIconInteractor: ShadeDarkIconInteractor,
    mobileIconsInteractor: MobileIconsInteractor,
    val mobileIconsViewModel: MobileIconsViewModel,
    private val privacyChipInteractor: PrivacyChipInteractor,
@@ -82,6 +86,7 @@ constructor(
    private val tintedIconManagerFactory: TintedIconManager.Factory,
    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
    val statusBarIconController: StatusBarIconController,
    val batteryViewModelFactory: UnifiedBatteryViewModel.Factory,
    val kairosNetwork: KairosNetwork,
    val mobileIconsViewModelKairos: dagger.Lazy<MobileIconsViewModelKairos>,
    private val dualShadeEducationInteractor: DualShadeEducationInteractor,
@@ -89,6 +94,13 @@ constructor(

    private val hydrator = Hydrator("ShadeHeaderViewModel.hydrator")

    val isShadeAreaDark: IsAreaDark by
        hydrator.hydratedStateOf(
            traceName = "isShadeAreaDark",
            initialValue = IsAreaDark { true },
            source = shadeDarkIconInteractor.isShadeAreaDark,
        )

    val createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager =
        tintedIconManagerFactory::create

+49 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.phone.domain.interactor

import android.graphics.Rect
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest

/** States pertaining to calculating colors for shade header icons in dark mode. */
interface ShadeDarkIconInteractor {
    /**
     * Returns a flow of [IsAreaDark], a function that answers whether a given [Rect] should be
     * tinted dark or not, on the display where the shade window is present.
     *
     * This flow ignores [DarkChange.tint] and [DarkChange.darkIntensity].
     */
    val isShadeAreaDark: Flow<IsAreaDark>
}

@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class ShadeDarkIconInteractorImpl
@Inject
constructor(
    darkIconInteractor: DarkIconInteractor,
    shadeDisplaysInteractor: ShadeDisplaysInteractor,
) : ShadeDarkIconInteractor {
    override val isShadeAreaDark: Flow<IsAreaDark> =
        shadeDisplaysInteractor.displayId.flatMapLatest(darkIconInteractor::isAreaDark)
}
Loading