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

Commit 1d62a718 authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "Animation of Edit mode in scene container" into main

parents a45774e5 bbc93975
Loading
Loading
Loading
Loading
+20 −1
Original line number Diff line number Diff line
@@ -17,6 +17,11 @@
package com.android.systemui.qs.footer.ui.compose

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.LocalIndication
@@ -87,10 +92,24 @@ import kotlinx.coroutines.launch
fun SceneScope.FooterActionsWithAnimatedVisibility(
    viewModel: FooterActionsViewModel,
    isCustomizing: Boolean,
    customizingAnimationDuration: Int,
    lifecycleOwner: LifecycleOwner,
    modifier: Modifier = Modifier,
) {
    AnimatedVisibility(visible = !isCustomizing, modifier = modifier.fillMaxWidth()) {
    AnimatedVisibility(
        visible = !isCustomizing,
        enter =
            expandVertically(
                animationSpec = tween(customizingAnimationDuration),
                initialHeight = { 0 },
            ) + fadeIn(tween(customizingAnimationDuration)),
        exit =
            shrinkVertically(
                animationSpec = tween(customizingAnimationDuration),
                targetHeight = { 0 },
            ) + fadeOut(tween(customizingAnimationDuration)),
        modifier = modifier.fillMaxWidth()
    ) {
        QuickSettingsTheme {
            // This view has its own horizontal padding
            // TODO(b/321716470) This should use a lifecycle tied to the scene.
+2 −1
Original line number Diff line number Diff line
@@ -162,7 +162,8 @@ private fun QuickSettingsContent(
    modifier: Modifier = Modifier,
) {
    val qsView by qsSceneAdapter.qsView.collectAsState(null)
    val isCustomizing by qsSceneAdapter.isCustomizing.collectAsState()
    val isCustomizing by
        qsSceneAdapter.isCustomizerShowing.collectAsState(qsSceneAdapter.isCustomizerShowing.value)
    QuickSettingsTheme {
        val context = LocalContext.current

+37 −14
Original line number Diff line number Diff line
@@ -19,12 +19,15 @@ package com.android.systemui.qs.ui.composable
import android.view.ViewGroup
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.clipScrollableContainer
import androidx.compose.foundation.gestures.Orientation
@@ -178,6 +181,9 @@ private fun SceneScope.QuickSettingsScene(
                }
    ) {
        val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
        val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState()
        val customizingAnimationDuration by
            viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsState()
        val screenHeight = LocalRawScreenHeight.current

        BackHandler(
@@ -217,6 +223,18 @@ private fun SceneScope.QuickSettingsScene(
        val navBarBottomHeight =
            WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
        val density = LocalDensity.current
        val bottomPadding by
            animateDpAsState(
                targetValue = if (isCustomizing) 0.dp else navBarBottomHeight,
                animationSpec = tween(customizingAnimationDuration),
                label = "animateQSSceneBottomPaddingAsState"
            )
        val topPadding by
            animateDpAsState(
                targetValue = if (isCustomizing) ShadeHeader.Dimensions.CollapsedHeight else 0.dp,
                animationSpec = tween(customizingAnimationDuration),
                label = "animateQSSceneTopPaddingAsState"
            )

        LaunchedEffect(navBarBottomHeight, density) {
            with(density) {
@@ -236,17 +254,14 @@ private fun SceneScope.QuickSettingsScene(
            horizontalAlignment = Alignment.CenterHorizontally,
            modifier =
                Modifier.fillMaxSize()
                    .then(
                        if (isCustomizing) {
                            Modifier.padding(top = 48.dp)
                        } else {
                            Modifier.padding(bottom = navBarBottomHeight)
                        }
                    .padding(
                        top = topPadding.coerceAtLeast(0.dp),
                        bottom = bottomPadding.coerceAtLeast(0.dp)
                    )
        ) {
            Box(modifier = Modifier.fillMaxSize().weight(1f)) {
                val shadeHeaderAndQuickSettingsModifier =
                    if (isCustomizing) {
                    if (isCustomizerShowing) {
                        Modifier.fillMaxHeight().align(Alignment.TopCenter)
                    } else {
                        Modifier.verticalNestedScrollToScene()
@@ -269,15 +284,22 @@ private fun SceneScope.QuickSettingsScene(
                                visible = !isCustomizing,
                                enter =
                                    expandVertically(
                                        animationSpec = tween(100),
                                        initialHeight = { collapsedHeaderHeight },
                                    ) + fadeIn(tween(100)),
                                        animationSpec = tween(customizingAnimationDuration),
                                        expandFrom = Alignment.Top,
                                    ) +
                                        slideInVertically(
                                            animationSpec = tween(customizingAnimationDuration),
                                        ) +
                                        fadeIn(tween(customizingAnimationDuration)),
                                exit =
                                    shrinkVertically(
                                        animationSpec = tween(100),
                                        targetHeight = { collapsedHeaderHeight },
                                        animationSpec = tween(customizingAnimationDuration),
                                        shrinkTowards = Alignment.Top,
                                    ) + fadeOut(tween(100)),
                                    ) +
                                        slideOutVertically(
                                            animationSpec = tween(customizingAnimationDuration),
                                        ) +
                                        fadeOut(tween(customizingAnimationDuration)),
                            ) {
                                ExpandedShadeHeader(
                                    viewModel = viewModel.shadeHeaderViewModel,
@@ -303,7 +325,7 @@ private fun SceneScope.QuickSettingsScene(
                        viewModel.qsSceneAdapter,
                        { viewModel.qsSceneAdapter.qsHeight },
                        isSplitShade = false,
                        modifier = Modifier.sysuiResTag("expanded_qs_scroll_view"),
                        modifier = Modifier.sysuiResTag("expanded_qs_scroll_view")
                    )

                    MediaCarousel(
@@ -318,6 +340,7 @@ private fun SceneScope.QuickSettingsScene(
            FooterActionsWithAnimatedVisibility(
                viewModel = footerActionsViewModel,
                isCustomizing = isCustomizing,
                customizingAnimationDuration = customizingAnimationDuration,
                lifecycleOwner = lifecycleOwner,
                modifier = Modifier.align(Alignment.CenterHorizontally),
            )
+14 −5
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@
package com.android.systemui.shade.ui.composable

import android.view.ViewGroup
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.clipScrollableContainer
@@ -301,6 +303,9 @@ private fun SceneScope.SplitShade(
    modifier: Modifier = Modifier,
) {
    val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
    val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState()
    val customizingAnimationDuration by
        viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsState()
    val lifecycleOwner = LocalLifecycleOwner.current
    val footerActionsViewModel =
        remember(lifecycleOwner, viewModel) { viewModel.getFooterActionsViewModel(lifecycleOwner) }
@@ -320,6 +325,12 @@ private fun SceneScope.SplitShade(
            .collectAsState(0f)

    val navBarBottomHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
    val bottomPadding by
        animateDpAsState(
            targetValue = if (isCustomizing) 0.dp else navBarBottomHeight,
            animationSpec = tween(customizingAnimationDuration),
            label = "animateQSSceneBottomPaddingAsState"
        )
    val density = LocalDensity.current
    LaunchedEffect(navBarBottomHeight, density) {
        with(density) {
@@ -390,16 +401,13 @@ private fun SceneScope.SplitShade(
                    )
                    Column(
                        verticalArrangement = Arrangement.Top,
                        modifier =
                            Modifier.fillMaxSize().thenIf(!isCustomizing) {
                                Modifier.padding(bottom = navBarBottomHeight)
                            },
                        modifier = Modifier.fillMaxSize().padding(bottom = bottomPadding),
                    ) {
                        Column(
                            modifier =
                                Modifier.fillMaxSize()
                                    .weight(1f)
                                    .thenIf(!isCustomizing) {
                                    .thenIf(!isCustomizerShowing) {
                                        Modifier.verticalNestedScrollToScene()
                                            .verticalScroll(
                                                quickSettingsScrollState,
@@ -432,6 +440,7 @@ private fun SceneScope.SplitShade(
                        FooterActionsWithAnimatedVisibility(
                            viewModel = footerActionsViewModel,
                            isCustomizing = isCustomizing,
                            customizingAnimationDuration = customizingAnimationDuration,
                            lifecycleOwner = lifecycleOwner,
                            modifier =
                                Modifier.align(Alignment.CenterHorizontally)
+40 −5
Original line number Diff line number Diff line
@@ -273,21 +273,56 @@ class QSSceneAdapterImplTest : SysuiTestCase() {
        }

    @Test
    fun customizing_QS() =
    fun customizing_QS_noAnimations() =
        testScope.runTest {
            val customizing by collectLastValue(underTest.isCustomizing)
            val customizerState by collectLastValue(underTest.customizerState)

            underTest.inflate(context)
            runCurrent()
            underTest.setState(QSSceneAdapter.State.QS)

            assertThat(customizing).isFalse()
            assertThat(customizerState).isEqualTo(CustomizerState.Hidden)

            underTest.setCustomizerShowing(true)
            assertThat(customizing).isTrue()
            assertThat(customizerState).isEqualTo(CustomizerState.Showing)

            underTest.setCustomizerShowing(false)
            assertThat(customizing).isFalse()
            assertThat(customizerState).isEqualTo(CustomizerState.Hidden)
        }

    // This matches the calls made by QSCustomizer
    @Test
    fun customizing_QS_animations_correctStates() =
        testScope.runTest {
            val customizerState by collectLastValue(underTest.customizerState)
            val animatingInDuration = 100L
            val animatingOutDuration = 50L

            underTest.inflate(context)
            runCurrent()
            underTest.setState(QSSceneAdapter.State.QS)

            assertThat(customizerState).isEqualTo(CustomizerState.Hidden)

            // Start showing customizer with animation
            underTest.setCustomizerAnimating(true)
            underTest.setCustomizerShowing(true, animatingInDuration)
            assertThat(customizerState)
                .isEqualTo(CustomizerState.AnimatingIntoCustomizer(animatingInDuration))

            // Finish animation
            underTest.setCustomizerAnimating(false)
            assertThat(customizerState).isEqualTo(CustomizerState.Showing)

            // Start closing customizer with animation
            underTest.setCustomizerAnimating(true)
            underTest.setCustomizerShowing(false, animatingOutDuration)
            assertThat(customizerState)
                .isEqualTo(CustomizerState.AnimatingOutOfCustomizer(animatingOutDuration))

            // Finish animation
            underTest.setCustomizerAnimating(false)
            assertThat(customizerState).isEqualTo(CustomizerState.Hidden)
        }

    @Test
Loading