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

Commit 6baf78f2 authored by Ale Nijamkin's avatar Ale Nijamkin Committed by Android (Google) Code Review
Browse files

Merge "[flexiglass] Rewrites lockscreen scene's DefaultBlueprint" into main

parents 448895f3 f4b87662
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -20,11 +20,13 @@ import android.content.res.Configuration
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntRect
@@ -42,6 +44,7 @@ import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.keyguard.ui.composable.layout.LockIconAlignmentLines
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
import javax.inject.Inject
import kotlin.math.min
@@ -97,7 +100,12 @@ constructor(
                    }
                    with(bottomAreaSection) {
                        IndicationArea(
                            Modifier.element(Communal.Elements.IndicationArea).fillMaxWidth()
                            Modifier.element(Communal.Elements.IndicationArea)
                                .fillMaxWidth()
                                .padding(
                                    bottom =
                                        dimensionResource(R.dimen.keyguard_indication_margin_bottom)
                                )
                        )
                    }
                },
+67 −208
Original line number Diff line number Diff line
@@ -17,39 +17,26 @@
package com.android.systemui.keyguard.ui.composable.blueprint

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.padding
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.keyguard.ui.composable.LockscreenTouchHandling
import com.android.systemui.keyguard.ui.composable.layout.LockIconAlignmentLines
import com.android.systemui.keyguard.ui.composable.layout.LockscreenSceneLayout
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.composable.section.TopAreaSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel.NotificationsPlacement.BelowClock
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel.NotificationsPlacement.BesideClock
import com.android.systemui.res.R
import java.util.Optional
import javax.inject.Inject
import kotlin.math.roundToInt

/**
 * Renders the lockscreen scene when showing with the default layout (e.g. vertical phone form
@@ -63,17 +50,18 @@ constructor(
    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
    private val bottomAreaSection: BottomAreaSection,
    private val settingsMenuSection: SettingsMenuSection,
    private val topAreaSection: TopAreaSection,
    private val notificationSection: NotificationSection,
    private val clockSection: DefaultClockSection,
    private val keyguardClockViewModel: KeyguardClockViewModel,
    private val smartSpaceSection: SmartSpaceSection,
    private val mediaSection: MediaCarouselSection,
) : ComposableLockscreenSceneBlueprint {

    override val id: String = "default"

    @Composable
    override fun ContentScope.Content(viewModel: LockscreenContentViewModel, modifier: Modifier) {
        val isUdfpsVisible = viewModel.isUdfpsVisible
        val isBypassEnabled = viewModel.isBypassEnabled
        val notificationsPlacement = viewModel.notificationsPlacement

        if (isBypassEnabled) {
            with(notificationSection) { HeadsUpNotifications() }
@@ -83,199 +71,70 @@ constructor(
            viewModelFactory = viewModel.touchHandlingFactory,
            modifier = modifier,
        ) { onSettingsMenuPlaced ->
            Layout(
                content = {
                    // Constrained to above the lock icon.
                    Column(modifier = Modifier.fillMaxSize()) {
                        with(statusBarSection) {
                            StatusBar(
                                modifier =
                                    Modifier.fillMaxWidth()
                                        .padding(
                                            horizontal = {
                                                viewModel.unfoldTranslations.start.roundToInt()
                                            }
                                        )
                            )
                        }
            val burnIn = rememberBurnIn(keyguardClockViewModel)

                        Box(modifier = Modifier.fillMaxWidth()) {
                            with(topAreaSection) {
                                DefaultClockLayout(
                                    smartSpacePaddingTop = viewModel::getSmartSpacePaddingTop,
                                    modifier =
                                        Modifier.fillMaxWidth().graphicsLayer {
                                            translationX = viewModel.unfoldTranslations.start
            LockscreenSceneLayout(
                viewModel = viewModel.layout,
                statusBar = {
                    with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
                },
                smallClock = {
                    with(clockSection) {
                        SmallClock(
                            burnInParams = burnIn.parameters,
                            onTopChanged = burnIn.onSmallClockTopChanged,
                        )
                    }
                            if (notificationsPlacement is BesideClock && !isBypassEnabled) {
                                with(notificationSection) {
                                    Box(modifier = Modifier.fillMaxHeight()) {
                                        AodPromotedNotificationArea(
                                            modifier =
                                                Modifier.fillMaxWidth(0.5f)
                                                    .align(notificationsPlacement.alignment)
                                        )
                                        Notifications(
                                            areNotificationsVisible =
                                                viewModel.areNotificationsVisible,
                                            burnInParams = null,
                                            modifier =
                                                Modifier.fillMaxWidth(0.5f)
                                                    .fillMaxHeight()
                                                    .align(notificationsPlacement.alignment)
                                                    .padding(top = 12.dp),
                },
                largeClock = {
                    with(clockSection) { LargeClock(burnInParams = burnIn.parameters) }
                },
                dateAndWeather = { orientation ->
                    with(smartSpaceSection) { DateAndWeather(orientation) }
                },
                smartSpace = {
                    with(smartSpaceSection) {
                        SmartSpace(
                            burnInParams = burnIn.parameters,
                            onTopChanged = burnIn.onSmartspaceTopChanged,
                            smartSpacePaddingTop = { 0 },
                        )
                    }
                },
                media = {
                    with(mediaSection) {
                        KeyguardMediaCarousel(isShadeLayoutWide = viewModel.isShadeLayoutWide)
                    }
                            }
                        }

                        // Not a mistake; reusing below_clock_padding_start_icons as AOD RON top
                        // padding for now.
                        val aodPromotedNotifTopPadding: Dp =
                            dimensionResource(R.dimen.below_clock_padding_start_icons)
                        val aodIconPadding: Dp =
                            dimensionResource(R.dimen.below_clock_padding_start_icons)

                },
                notifications = {
                    with(notificationSection) {
                            if (notificationsPlacement is BelowClock && !isBypassEnabled) {
                                Box(modifier = Modifier.weight(weight = 1f)) {
                                    Column(Modifier.align(alignment = Alignment.TopStart)) {
                                        AodPromotedNotificationArea(
                                            modifier =
                                                Modifier.padding(top = aodPromotedNotifTopPadding)
                                        )
                                        AodNotificationIcons(
                                            modifier = Modifier.padding(start = aodIconPadding)
                                        )
                                    }
                                    Notifications(
                                        areNotificationsVisible = viewModel.areNotificationsVisible,
                                        burnInParams = null,
                                    )
                                }
                            } else {
                                Column {
                                    if (viewModel.notificationsPlacement is BelowClock) {
                                        AodPromotedNotificationArea(
                                            modifier =
                                                Modifier.padding(top = aodPromotedNotifTopPadding)
                                        )
                                    }
                                    AodNotificationIcons(
                                        modifier =
                                            Modifier.padding(
                                                top =
                                                    dimensionResource(
                                                        R.dimen.keyguard_status_view_bottom_margin
                                                    ),
                                                start = aodIconPadding,
                                            )
                                    )
                                }
                            }
                        }
                        if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
                            with(ambientIndicationSectionOptional.get()) {
                                AmbientIndication(modifier = Modifier.fillMaxWidth())
                            }
                        Box(modifier = Modifier.fillMaxHeight()) {
                            AodPromotedNotificationArea()
                            Notifications(areNotificationsVisible = true, burnInParams = null)
                        }
                    }

                    with(lockSection) { LockIcon() }

                    // Aligned to bottom and constrained to below the lock icon.
                    Column(modifier = Modifier.fillMaxWidth().sysuiResTag("keyguard_root_view")) {
                        if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
                },
                lockIcon = { with(lockSection) { LockIcon() } },
                startShortcut = {
                    with(bottomAreaSection) { Shortcut(isStart = true, applyPadding = false) }
                },
                ambientIndication = {
                    if (ambientIndicationSectionOptional.isPresent) {
                        with(ambientIndicationSectionOptional.get()) {
                            AmbientIndication(modifier = Modifier.fillMaxWidth())
                        }
                    }

                        with(bottomAreaSection) {
                            IndicationArea(modifier = Modifier.fillMaxWidth())
                        }
                    }

                    // Aligned to bottom and NOT constrained by the lock icon.
                    with(bottomAreaSection) {
                        Shortcut(
                            isStart = true,
                            applyPadding = true,
                            modifier =
                                Modifier.graphicsLayer {
                                    translationX = viewModel.unfoldTranslations.start
                },
                        )
                        Shortcut(
                            isStart = false,
                            applyPadding = true,
                            modifier =
                                Modifier.graphicsLayer {
                                    translationX = viewModel.unfoldTranslations.end
                bottomIndication = {
                    with(bottomAreaSection) { IndicationArea(modifier = Modifier.fillMaxWidth()) }
                },
                        )
                    }
                    with(settingsMenuSection) { SettingsMenu(onSettingsMenuPlaced) }
                endShortcut = {
                    with(bottomAreaSection) { Shortcut(isStart = false, applyPadding = false) }
                },
                settingsMenu = {
                    with(settingsMenuSection) { SettingsMenu(onPlaced = onSettingsMenuPlaced) }
                },
                modifier = Modifier.fillMaxSize(),
            ) { measurables, constraints ->
                check(measurables.size == 6) { "Expected 6 measurables, got: ${measurables.size}" }
                val aboveLockIconMeasurable = measurables[0]
                val lockIconMeasurable = measurables[1]
                val belowLockIconMeasurable = measurables[2]
                val startShortcutMeasurable = measurables[3]
                val endShortcutMeasurable = measurables[4]
                val settingsMenuMeasurable = measurables[5]

                val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0)
                val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints)
                val lockIconBounds =
                    IntRect(
                        left = lockIconPlaceable[LockIconAlignmentLines.Left],
                        top = lockIconPlaceable[LockIconAlignmentLines.Top],
                        right = lockIconPlaceable[LockIconAlignmentLines.Right],
                        bottom = lockIconPlaceable[LockIconAlignmentLines.Bottom],
                    )

                val aboveLockIconPlaceable =
                    aboveLockIconMeasurable.measure(
                        noMinConstraints.copy(maxHeight = lockIconBounds.top)
                    )
                val belowLockIconPlaceable =
                    belowLockIconMeasurable.measure(
                        noMinConstraints.copy(
                            maxHeight =
                                (constraints.maxHeight - lockIconBounds.bottom).coerceAtLeast(0)
                        )
                    )
                val startShortcutPleaceable = startShortcutMeasurable.measure(noMinConstraints)
                val endShortcutPleaceable = endShortcutMeasurable.measure(noMinConstraints)
                val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints)

                layout(constraints.maxWidth, constraints.maxHeight) {
                    aboveLockIconPlaceable.place(x = 0, y = 0)
                    lockIconPlaceable.place(x = lockIconBounds.left, y = lockIconBounds.top)
                    belowLockIconPlaceable.place(
                        x = 0,
                        y = constraints.maxHeight - belowLockIconPlaceable.height,
                    )
                    startShortcutPleaceable.place(
                        x = 0,
                        y = constraints.maxHeight - startShortcutPleaceable.height,
                    )
                    endShortcutPleaceable.place(
                        x = constraints.maxWidth - endShortcutPleaceable.width,
                        y = constraints.maxHeight - endShortcutPleaceable.height,
                    )
                    settingsMenuPlaceable.place(
                        x = (constraints.maxWidth - settingsMenuPlaceable.width) / 2,
                        y = constraints.maxHeight - settingsMenuPlaceable.height,
            )
        }
    }
}
    }
}
+1 −6
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ constructor(

    @Composable
    fun ContentScope.IndicationArea(modifier: Modifier = Modifier) {
        Element(key = IndicationAreaElementKey, modifier = modifier.indicationAreaPadding()) {
        Element(key = IndicationAreaElementKey, modifier = modifier) {
            IndicationArea(
                indicationAreaViewModel = indicationAreaViewModel,
                indicationController = indicationController,
@@ -189,11 +189,6 @@ constructor(
            )
            .padding(bottom = dimensionResource(R.dimen.keyguard_affordance_vertical_offset))
    }

    @Composable
    private fun Modifier.indicationAreaPadding(): Modifier {
        return this.padding(bottom = dimensionResource(R.dimen.keyguard_indication_margin_bottom))
    }
}

private val StartButtonElementKey = ElementKey("StartButton")
+6 −10
Original line number Diff line number Diff line
@@ -22,8 +22,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import com.android.compose.animation.scene.ContentScope
import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
@@ -37,24 +35,22 @@ class MediaCarouselSection
constructor(
    private val mediaCarouselController: MediaCarouselController,
    @param:Named(MediaModule.KEYGUARD) private val mediaHost: MediaHost,
    private val keyguardMediaViewModelFactory: KeyguardMediaViewModel.Factory,
) {

    @Composable
    fun ContentScope.KeyguardMediaCarousel(modifier: Modifier = Modifier) {
        val viewModel =
            rememberViewModel(traceName = "KeyguardMediaCarousel") {
                keyguardMediaViewModelFactory.create()
            }
    fun ContentScope.KeyguardMediaCarousel(
        isShadeLayoutWide: Boolean,
        modifier: Modifier = Modifier,
    ) {
        val horizontalPadding =
            if (viewModel.isShadeLayoutWide) {
            if (isShadeLayoutWide) {
                dimensionResource(id = R.dimen.notification_side_paddings)
            } else {
                dimensionResource(id = R.dimen.notification_side_paddings) +
                    dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
            }
        MediaCarousel(
            isVisible = viewModel.isMediaVisible,
            isVisible = true,
            mediaHost = mediaHost,
            modifier = modifier.fillMaxWidth().padding(horizontal = horizontalPadding),
            carouselController = mediaCarouselController,
+32 −7
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.systemui.keyguard.ui.composable.section

import android.content.res.Resources
import android.widget.FrameLayout
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
@@ -125,6 +127,27 @@ constructor(
        }
    }

    @Composable
    fun DateAndWeather(orientation: Orientation, modifier: Modifier = Modifier) {
        when (orientation) {
            Orientation.Horizontal ->
                Row(
                    horizontalArrangement = Arrangement.spacedBy(8.dp),
                    verticalAlignment = Alignment.CenterVertically,
                    modifier = modifier,
                ) {
                    Date()
                    Weather()
                }

            Orientation.Vertical ->
                Column(verticalArrangement = Arrangement.spacedBy(4.dp), modifier = modifier) {
                    Date()
                    Weather()
                }
        }
    }

    @Composable
    private fun Card(modifier: Modifier = Modifier) {
        AndroidView(
@@ -159,7 +182,9 @@ constructor(
            factory = { context ->
                FrameLayout(context).apply {
                    addView(
                        lockscreenSmartspaceController.buildAndConnectWeatherView(this, false).apply {
                        lockscreenSmartspaceController
                            .buildAndConnectWeatherView(this, false)
                            .apply {
                                layoutParams =
                                    FrameLayout.LayoutParams(
                                        FrameLayout.LayoutParams.WRAP_CONTENT,
Loading