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

Commit 12dc2abb authored by Ahmed Mehfooz's avatar Ahmed Mehfooz Committed by Android (Google) Code Review
Browse files

Merge changes Ifa524666,I8d7118e8,Ic0cc0577 into main

* changes:
  [DesktopStatusBar] Add NotificationsChip
  [DesktopStatusBar] Add QuickSettings chip
  [DesktopStatusBar] Add Time and Date
parents b8def990 6b309071
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ class FakeHomeStatusBarViewModel(

    override fun onChipBoundsChanged(key: String, bounds: RectF) {}

    override fun onSystemIconChipClicked() {}
    override fun onQuickSettingsChipClicked() {}

    override fun onNotificationIconChipClicked() {}

+4 −4
Original line number Diff line number Diff line
@@ -1907,7 +1907,7 @@ class HomeStatusBarViewModelImplTest(flags: FlagsParameterization) : SysuiTestCa
    @Test
    @EnableSceneContainer
    @EnableFlags(StatusBarForDesktop.FLAG_NAME)
    fun onSystemIconChipClicked_qsShadeIsOpen_collapsesShade() =
    fun onQuickSettingsChipClicked_qsShadeIsOpen_collapsesShade() =
        kosmos.runTest {
            enableDualShade()
            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
@@ -1921,21 +1921,21 @@ class HomeStatusBarViewModelImplTest(flags: FlagsParameterization) : SysuiTestCa
            )
            assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade)

            underTest.onSystemIconChipClicked()
            underTest.onQuickSettingsChipClicked()
            assertThat(currentOverlays).doesNotContain(Overlays.QuickSettingsShade)
        }

    @Test
    @EnableSceneContainer
    @EnableFlags(StatusBarForDesktop.FLAG_NAME)
    fun onSystemIconChipClicked_qsShadeIsClosed_expandsShade() =
    fun onQuickSettingsChipClicked_qsShadeIsClosed_expandsShade() =
        kosmos.runTest {
            enableDualShade()
            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)

            assertThat(currentOverlays).doesNotContain(Overlays.QuickSettingsShade)

            underTest.onSystemIconChipClicked()
            underTest.onQuickSettingsChipClicked()

            assertThat(currentOverlays).contains(Overlays.QuickSettingsShade)
        }
+45 −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.clock.ui.composable

import android.view.ContextThemeWrapper
import androidx.compose.foundation.clickable
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.viewinterop.AndroidView
import com.android.compose.modifiers.thenIf
import com.android.systemui.res.R

/**
 * Composable wrapper around the legacy [com.android.systemui.statusbar.policy.Clock] view. Will be
 * replaced by the fully composable [Clock].
 */
@Composable
fun ClockLegacy(textColor: Color, onClick: (() -> Unit)?, modifier: Modifier = Modifier) {
    AndroidView(
        factory = { context ->
            com.android.systemui.statusbar.policy.Clock(
                ContextThemeWrapper(context, R.style.Theme_SystemUI),
                null,
            )
        },
        update = { view -> view.setTextColor(textColor.toArgb()) },
        modifier = modifier.thenIf(onClick != null) { Modifier.clickable { onClick?.invoke() } },
    )
}
+174 −3
Original line number Diff line number Diff line
@@ -16,13 +16,184 @@

package com.android.systemui.statusbar.pipeline.shared.ui.composable

import androidx.compose.material3.Text
import android.view.ContextThemeWrapper
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.android.compose.theme.colorAttr
import com.android.settingslib.Utils
import com.android.systemui.clock.ui.composable.ClockLegacy
import com.android.systemui.clock.ui.viewmodel.AmPmStyle
import com.android.systemui.clock.ui.viewmodel.ClockViewModel
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.res.R
import com.android.systemui.shade.ui.composable.ShadeHighlightChip
import com.android.systemui.shade.ui.composable.VariableDayDate
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
import com.android.systemui.statusbar.pipeline.battery.ui.composable.UnifiedBattery
import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel
import com.android.systemui.statusbar.systemstatusicons.SystemStatusIconsInCompose
import com.android.systemui.statusbar.systemstatusicons.ui.compose.SystemStatusIcons
import com.android.systemui.statusbar.systemstatusicons.ui.compose.SystemStatusIconsLegacy

object DesktopStatusBar {
    object Dimensions {
        val ElementSpacing = 8.dp
        val ChipInternalSpacing = 6.dp
    }
}

// TODO(433589833): Add support for color themes in this composable.
/** Top level composable responsible for all UI shown for the Status Bar for DesktopMode. */
@Composable
fun DesktopStatusBar(viewModel: HomeStatusBarViewModel, modifier: Modifier = Modifier) {
    Text("Desktop Status Bar", modifier = modifier)
fun DesktopStatusBar(
    viewModel: HomeStatusBarViewModel,
    clockViewModelFactory: ClockViewModel.Factory,
    statusBarIconController: StatusBarIconController,
    iconManagerFactory: TintedIconManager.Factory,
    modifier: Modifier = Modifier,
) {
    // TODO(433589833): Update padding values to match UX specs.
    Row(modifier = modifier.fillMaxWidth().padding(top = 8.dp, start = 12.dp, end = 12.dp)) {
        Row(
            horizontalArrangement =
                Arrangement.spacedBy(DesktopStatusBar.Dimensions.ElementSpacing, Alignment.Start),
            modifier = Modifier.padding(vertical = 4.dp),
        ) {
            ClockLegacy(textColor = Color.White, onClick = null)

            val clockViewModel =
                rememberViewModel("HomeStatusBar.Clock") {
                    clockViewModelFactory.create(AmPmStyle.Gone)
                }
            VariableDayDate(
                longerDateText = clockViewModel.longerDateText,
                shorterDateText = clockViewModel.shorterDateText,
                textColor = colorAttr(R.attr.wallpaperTextColor),
            )
        }

        Spacer(modifier = Modifier.weight(1f))

        Row(
            horizontalArrangement =
                Arrangement.spacedBy(DesktopStatusBar.Dimensions.ElementSpacing, Alignment.End)
        ) {
            NotificationsChip(viewModel = viewModel)

            QuickSettingsChip(
                viewModel = viewModel,
                statusBarIconController = statusBarIconController,
                iconManagerFactory = iconManagerFactory,
            )
        }
    }
}

@Composable
private fun NotificationsChip(viewModel: HomeStatusBarViewModel) {
    ShadeHighlightChip(
        onClick = { viewModel.onNotificationIconChipClicked() },
        // TODO(433589833): Add support for ChipHighlight when Notifications Panel is visible.
        backgroundColor = Color.Transparent,
        horizontalArrangement =
            Arrangement.spacedBy(DesktopStatusBar.Dimensions.ChipInternalSpacing, Alignment.Start),
    ) {
        // TODO(433589833): Add new icon resources for the notification chip icon.
        Icon(
            icon = Icon.Resource(res = R.drawable.ic_volume_ringer, contentDescription = null),
            tint = Color.White,
        )
    }
}

@Composable
private fun QuickSettingsChip(
    viewModel: HomeStatusBarViewModel,
    statusBarIconController: StatusBarIconController,
    iconManagerFactory: TintedIconManager.Factory,
    modifier: Modifier = Modifier,
) {

    ShadeHighlightChip(
        onClick = { viewModel.onQuickSettingsChipClicked() },
        // TODO(433589833): Add support for ChipHighlight when QS Panel is visible.
        backgroundColor = Color.Transparent,
        horizontalArrangement =
            Arrangement.spacedBy(DesktopStatusBar.Dimensions.ChipInternalSpacing, Alignment.Start),
    ) {
        if (SystemStatusIconsInCompose.isEnabled) {
            SystemStatusIcons(
                viewModelFactory = viewModel.systemStatusIconsViewModelFactory,
                tint = Color.White,
                modifier = modifier,
            )
        } else {
            val localContext = LocalContext.current
            val themedContext = ContextThemeWrapper(localContext, R.style.Theme_SystemUI)
            val foregroundColor =
                Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimary)
            val backgroundColor =
                Utils.getColorAttrDefaultColor(
                    themedContext,
                    android.R.attr.textColorPrimaryInverse,
                )

            val iconContainer =
                remember(localContext, iconManagerFactory) {
                    StatusIconContainer(
                        ContextThemeWrapper(localContext, R.style.Theme_SystemUI),
                        null,
                    )
                }
            val iconManager =
                remember(iconContainer) {
                    iconManagerFactory.create(iconContainer, StatusBarLocation.HOME)
                }

            SystemStatusIconsLegacy(
                statusBarIconController = statusBarIconController,
                iconContainer = iconContainer,
                iconManager = iconManager,
                useExpandedFormat = true,
                foregroundColor = foregroundColor,
                backgroundColor = backgroundColor,
                isSingleCarrier = true,
                isMicCameraIndicationEnabled = true,
                isPrivacyChipEnabled = true,
                isTransitioning = false,
                isLocationIndicationEnabled = true,
            )
        }

        val batteryHeight =
            with(LocalDensity.current) {
                BatteryViewModel.getStatusBarBatteryHeight(LocalContext.current).toDp()
            }
        UnifiedBattery(
            viewModel =
                rememberViewModel("DesktopStatusBar.BatteryViewModel") {
                    viewModel.unifiedBatteryViewModel.create()
                },
            isDarkProvider = { viewModel.areaDark },
            modifier = Modifier.height(batteryHeight),
        )
    }
}
+11 −1
Original line number Diff line number Diff line
@@ -91,6 +91,8 @@ 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.phone.ui.TintedIconManager
import com.android.systemui.statusbar.phone.ui.TintedIconManager.Factory
import com.android.systemui.statusbar.pipeline.battery.ui.composable.BatteryWithChargeStatus
import com.android.systemui.statusbar.pipeline.battery.ui.composable.ShowPercentMode
import com.android.systemui.statusbar.pipeline.battery.ui.composable.UnifiedBattery
@@ -118,6 +120,7 @@ constructor(
    private val iconViewStoreFactory: ConnectedDisplaysStatusBarNotificationIconViewStore.Factory,
    private val clockViewModelFactory: ClockViewModel.Factory,
    private val darkIconManagerFactory: DarkIconManager.Factory,
    private val tintedIconManagerFactory: TintedIconManager.Factory,
    private val iconController: StatusBarIconController,
    private val ongoingCallController: OngoingCallController,
    private val eventAnimationInteractor: SystemStatusEventAnimationInteractor,
@@ -141,6 +144,7 @@ constructor(
                        iconViewStoreFactory = iconViewStoreFactory,
                        clockViewModelFactory = clockViewModelFactory,
                        darkIconManagerFactory = darkIconManagerFactory,
                        tintedIconManagerFactory = tintedIconManagerFactory,
                        iconController = iconController,
                        ongoingCallController = ongoingCallController,
                        darkIconDispatcher = darkIconDispatcher,
@@ -179,6 +183,7 @@ fun StatusBarRoot(
    iconViewStoreFactory: ConnectedDisplaysStatusBarNotificationIconViewStore.Factory,
    clockViewModelFactory: ClockViewModel.Factory,
    darkIconManagerFactory: DarkIconManager.Factory,
    tintedIconManagerFactory: TintedIconManager.Factory,
    iconController: StatusBarIconController,
    ongoingCallController: OngoingCallController,
    darkIconDispatcher: DarkIconDispatcher,
@@ -207,7 +212,12 @@ fun StatusBarRoot(

    // Let the DesktopStatusBar compose all the UI if [isDesktopStatusBarEnabled] is true.
    if (StatusBarForDesktop.isEnabled && statusBarViewModel.isDesktopStatusBarEnabled) {
        DesktopStatusBar(viewModel = statusBarViewModel)
        DesktopStatusBar(
            viewModel = statusBarViewModel,
            clockViewModelFactory = clockViewModelFactory,
            statusBarIconController = iconController,
            iconManagerFactory = tintedIconManagerFactory,
        )
        return
    }

Loading