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

Commit 0f6a4de2 authored by Aaron Liu's avatar Aaron Liu Committed by Android (Google) Code Review
Browse files

Merge "Add Centering animation for large clock" into main

parents dd808f63 a1cfdf6d
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.composable
import com.android.systemui.keyguard.ui.composable.blueprint.CommunalBlueprintModule
import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule
import com.android.systemui.keyguard.ui.composable.blueprint.ShortcutsBesideUdfpsBlueprintModule
import com.android.systemui.keyguard.ui.composable.blueprint.SplitShadeBlueprintModule
import com.android.systemui.keyguard.ui.composable.blueprint.SplitShadeWeatherClockBlueprintModule
import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockBlueprintModule
import com.android.systemui.keyguard.ui.composable.section.OptionalSectionModule
@@ -32,7 +31,6 @@ import dagger.Module
            DefaultBlueprintModule::class,
            OptionalSectionModule::class,
            ShortcutsBesideUdfpsBlueprintModule::class,
            SplitShadeBlueprintModule::class,
            SplitShadeWeatherClockBlueprintModule::class,
            WeatherClockBlueprintModule::class,
        ],
+5 −0
Original line number Diff line number Diff line
@@ -38,6 +38,9 @@ object ClockTransition {
        from(ClockScenes.largeClockScene, to = ClockScenes.smallClockScene) {
            transitioningToSmallClock()
        }
        from(ClockScenes.splitShadeLargeClockScene, to = ClockScenes.largeClockScene) {
            spec = tween(1000)
        }
    }

    private fun TransitionBuilder.transitioningToLargeClock() {
@@ -70,6 +73,8 @@ object ClockTransition {
object ClockScenes {
    val smallClockScene = SceneKey("small-clock-scene")
    val largeClockScene = SceneKey("large-clock-scene")
    val splitShadeSmallClockScene = SceneKey("split-shade-small-clock-scene")
    val splitShadeLargeClockScene = SceneKey("split-shade-large-clock-scene")
}

object ClockElementKeys {
+3 −19
Original line number Diff line number Diff line
@@ -22,18 +22,15 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.IntRect
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
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.StatusBarSection
import com.android.systemui.keyguard.ui.composable.section.TopAreaSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import dagger.Binds
import dagger.Module
@@ -50,13 +47,11 @@ class DefaultBlueprint
constructor(
    private val viewModel: LockscreenContentViewModel,
    private val statusBarSection: StatusBarSection,
    private val clockSection: DefaultClockSection,
    private val notificationSection: NotificationSection,
    private val lockSection: LockSection,
    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
    private val bottomAreaSection: BottomAreaSection,
    private val settingsMenuSection: SettingsMenuSection,
    private val mediaCarouselSection: MediaCarouselSection,
    private val topAreaSection: TopAreaSection,
) : ComposableLockscreenSceneBlueprint {

    override val id: String = "default"
@@ -64,7 +59,6 @@ constructor(
    @Composable
    override fun SceneScope.Content(modifier: Modifier) {
        val isUdfpsVisible = viewModel.isUdfpsVisible
        val resources = LocalContext.current.resources

        LockscreenLongPress(
            viewModel = viewModel.longPress,
@@ -77,17 +71,7 @@ constructor(
                        modifier = Modifier.fillMaxWidth(),
                    ) {
                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
                        with(clockSection) { DefaultClockLayout() }
                        with(mediaCarouselSection) { MediaCarousel() }

                        if (viewModel.areNotificationsVisible(resources = resources)) {
                            with(notificationSection) {
                                Notifications(
                                    modifier = Modifier.fillMaxWidth().weight(weight = 1f)
                                )
                            }
                        }

                        with(topAreaSection) { DefaultClockLayoutWithNotifications() }
                        if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
                            with(ambientIndicationSectionOptional.get()) {
                                AmbientIndication(modifier = Modifier.fillMaxWidth())
+3 −18
Original line number Diff line number Diff line
@@ -22,18 +22,15 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.IntRect
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
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.StatusBarSection
import com.android.systemui.keyguard.ui.composable.section.TopAreaSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import dagger.Binds
import dagger.Module
@@ -50,13 +47,11 @@ class ShortcutsBesideUdfpsBlueprint
constructor(
    private val viewModel: LockscreenContentViewModel,
    private val statusBarSection: StatusBarSection,
    private val clockSection: DefaultClockSection,
    private val notificationSection: NotificationSection,
    private val lockSection: LockSection,
    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
    private val bottomAreaSection: BottomAreaSection,
    private val settingsMenuSection: SettingsMenuSection,
    private val mediaCarouselSection: MediaCarouselSection,
    private val topAreaSection: TopAreaSection,
) : ComposableLockscreenSceneBlueprint {

    override val id: String = "shortcuts-besides-udfps"
@@ -64,7 +59,6 @@ constructor(
    @Composable
    override fun SceneScope.Content(modifier: Modifier) {
        val isUdfpsVisible = viewModel.isUdfpsVisible
        val resources = LocalContext.current.resources

        LockscreenLongPress(
            viewModel = viewModel.longPress,
@@ -77,16 +71,7 @@ constructor(
                        modifier = Modifier.fillMaxWidth(),
                    ) {
                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
                        with(clockSection) { DefaultClockLayout() }
                        with(mediaCarouselSection) { MediaCarousel() }

                        if (viewModel.areNotificationsVisible(resources = resources)) {
                            with(notificationSection) {
                                Notifications(
                                    modifier = Modifier.fillMaxWidth().weight(weight = 1f)
                                )
                            }
                        }
                        with(topAreaSection) { DefaultClockLayoutWithNotifications() }

                        if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
                            with(ambientIndicationSectionOptional.get()) {
+0 −222
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.keyguard.ui.composable.blueprint

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.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.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.Flags
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
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.StatusBarSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.res.R
import com.android.systemui.shade.LargeScreenHeaderHelper
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoSet
import java.util.Optional
import javax.inject.Inject

/**
 * Renders the lockscreen scene when showing with a split shade (e.g. unfolded foldable and/or
 * tablet form factor).
 */
class SplitShadeBlueprint
@Inject
constructor(
    private val viewModel: LockscreenContentViewModel,
    private val statusBarSection: StatusBarSection,
    private val clockSection: DefaultClockSection,
    private val notificationSection: NotificationSection,
    private val lockSection: LockSection,
    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
    private val bottomAreaSection: BottomAreaSection,
    private val settingsMenuSection: SettingsMenuSection,
    private val mediaCarouselSection: MediaCarouselSection,
    private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
) : ComposableLockscreenSceneBlueprint {

    override val id: String = "split-shade"

    @Composable
    override fun SceneScope.Content(modifier: Modifier) {
        val isUdfpsVisible = viewModel.isUdfpsVisible

        LockscreenLongPress(
            viewModel = viewModel.longPress,
            modifier = modifier,
        ) { onSettingsMenuPlaced ->
            Layout(
                content = {
                    // Constrained to above the lock icon.
                    Column(
                        modifier = Modifier.fillMaxSize(),
                    ) {
                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
                        Row(
                            modifier = Modifier.fillMaxSize(),
                        ) {
                            Column(
                                modifier = Modifier.fillMaxHeight().weight(weight = 1f),
                                horizontalAlignment = Alignment.CenterHorizontally,
                            ) {
                                with(clockSection) { DefaultClockLayout() }
                                with(mediaCarouselSection) { MediaCarousel() }
                            }
                            with(notificationSection) {
                                val splitShadeTopMargin: Dp =
                                    if (Flags.centralizedStatusBarHeightFix()) {
                                        largeScreenHeaderHelper.getLargeScreenHeaderHeight().dp
                                    } else {
                                        dimensionResource(
                                            id = R.dimen.large_screen_shade_header_height
                                        )
                                    }
                                Notifications(
                                    modifier =
                                        Modifier.fillMaxHeight()
                                            .weight(weight = 1f)
                                            .padding(top = splitShadeTopMargin)
                                )
                            }
                        }

                        if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
                            with(ambientIndicationSectionOptional.get()) {
                                AmbientIndication(modifier = Modifier.fillMaxWidth())
                            }
                        }
                    }

                    with(lockSection) { LockIcon() }

                    // Aligned to bottom and constrained to below the lock icon.
                    Column(modifier = Modifier.fillMaxWidth()) {
                        if (isUdfpsVisible && 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)
                        Shortcut(isStart = false, applyPadding = true)
                    }
                    with(settingsMenuSection) { SettingsMenu(onSettingsMenuPlaced) }
                },
                modifier = Modifier.fillMaxSize(),
            ) { measurables, constraints ->
                check(measurables.size == 6)
                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[BlueprintAlignmentLines.LockIcon.Left],
                        top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top],
                        right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right],
                        bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.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,
                    )
                }
            }
        }
    }
}

@Module
interface SplitShadeBlueprintModule {
    @Binds
    @IntoSet
    fun blueprint(blueprint: SplitShadeBlueprint): ComposableLockscreenSceneBlueprint
}
Loading