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

Commit 3a5b6545 authored by Darrell Shi's avatar Darrell Shi
Browse files

Improve transition between hub and edit mode

This change improves the transition between hub and edit mode by
introducing a background in the SystemUI hub to hide the edit mode
activity launching and exiting animations, making the visible transition
much cleaner.

Test: atest CommunalViewModelTest
Test: atest CommunalEditModeViewModelTest
Test: atest FromPrimaryBouncerTransitionInteractorTest
Test: atest FromAlternateBouncerTransitionInteractorTest
Test: manual; see recordings in bug
Bug: 419361764
Flag: com.android.systemui.hub_edit_mode_transition
Change-Id: Ia366ce34d88acc74b7f063e5f8710415ba49e9cd
parent 4390a3d3
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -87,6 +87,10 @@ object TransitionDuration {
        EDIT_MODE_TO_HUB_GRID_DELAY_MS + EDIT_MODE_TO_HUB_CONTENT_MS
    const val HUB_TO_EDIT_MODE_CONTENT_MS = 250
    const val TO_GLANCEABLE_HUB_DURATION_MS = 1000

    // The duration in milliseconds to animate in and our of the background for edit mode
    // transition.
    const val EDIT_MODE_BACKGROUND_ANIM_DURATION_MS = 300
}

val sceneTransitionsV2 = transitions {
@@ -141,6 +145,14 @@ val sceneTransitionsV2 = transitions {
        }
        timestampRange(startMillis = 167, endMillis = 334) { fade(Communal.Elements.Scrim) }
    }
    to(CommunalScenes.Blank, key = CommunalTransitionKeys.ToEditMode) {
        spec = tween(durationMillis = TransitionDuration.BETWEEN_HUB_AND_EDIT_MODE_MS)
        fade(AllElements)
    }
    to(CommunalScenes.Communal, key = CommunalTransitionKeys.FromEditMode) {
        spec = tween(durationMillis = TransitionDuration.BETWEEN_HUB_AND_EDIT_MODE_MS)
        fade(AllElements)
    }
}

val sceneTransitions = transitions {
+21 −0
Original line number Diff line number Diff line
@@ -17,6 +17,11 @@
package com.android.systemui.communal.ui.compose

import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -37,6 +42,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.thenIf
import com.android.systemui.Flags
@@ -76,6 +82,21 @@ constructor(
        CommunalTouchableSurface(viewModel = viewModel, modifier = modifier) {
            val orientation = LocalConfiguration.current.orientation
            var gridRegion by remember { mutableStateOf<Rect?>(null) }
            val showBackgroundForEditModeTransition by
                viewModel.showBackgroundForEditModeTransition.collectAsStateWithLifecycle(
                    initialValue = false
                )

            // The animated background here matches the color scheme of the edit mode activity and
            // facilitates the transition to and from edit mode.
            AnimatedVisibility(
                visible = showBackgroundForEditModeTransition,
                enter = fadeIn(tween(TransitionDuration.EDIT_MODE_BACKGROUND_ANIM_DURATION_MS)),
                exit = fadeOut(tween(TransitionDuration.EDIT_MODE_BACKGROUND_ANIM_DURATION_MS)),
            ) {
                Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surfaceDim))
            }

            Layout(
                modifier =
                    Modifier.fillMaxSize().thenIf(communalSettingsInteractor.isV2FlagEnabled()) {
+6 −6
Original line number Diff line number Diff line
@@ -186,6 +186,7 @@ import com.android.systemui.Flags
import com.android.systemui.Flags.communalResponsiveGrid
import com.android.systemui.Flags.communalTimerFlickerFix
import com.android.systemui.Flags.communalWidgetResizing
import com.android.systemui.Flags.hubEditModeTransition
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
@@ -252,7 +253,7 @@ fun CommunalHub(
    val isEmptyState by viewModel.isEmptyState.collectAsStateWithLifecycle(initialValue = false)
    val isCommunalContentVisible by
        viewModel.isCommunalContentVisible.collectAsStateWithLifecycle(
            initialValue = !viewModel.isEditMode
            initialValue = hubEditModeTransition() || !viewModel.isEditMode
        )

    val minContentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
@@ -2012,14 +2013,13 @@ private fun toolbarPadding(): PaddingValues {
        )
    }
    val displayCutoutPaddings = WindowInsets.displayCutout.asPaddingValues()
    val horizontalPadding = hubDimensions.toolbarHorizontalPadding
    val bottomPadding = hubDimensions.toolbarBottomPadding

    return remember(displayCutoutPaddings, horizontalPadding, bottomPadding) {
    // Depending on camera location, there can be no cutout paddings, set a min value
    val topPadding =
        displayCutoutPaddings.calculateTopPadding().coerceAtLeast(Dimensions.ToolbarPaddingTop)
    val horizontalPadding = hubDimensions.toolbarHorizontalPadding
    val bottomPadding = hubDimensions.toolbarBottomPadding

    return remember(topPadding, horizontalPadding, bottomPadding) {
        PaddingValues(
            start = horizontalPadding,
            top = topPadding,
+23 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.pm.PackageManager
import android.content.pm.UserInfo
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.accessibilityManager
@@ -29,6 +31,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.uiEventLogger
import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.Flags.FLAG_HUB_EDIT_MODE_TRANSITION
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
@@ -173,6 +176,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
            assertThat(isCommunalContentVisible).isEqualTo(true)
        }

    @DisableFlags(FLAG_HUB_EDIT_MODE_TRANSITION)
    @Test
    fun isCommunalContentVisible_isFalse_whenEditModeNotShowing() =
        kosmos.runTest {
@@ -181,6 +185,25 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
            assertThat(isCommunalContentVisible).isEqualTo(false)
        }

    @EnableFlags(FLAG_HUB_EDIT_MODE_TRANSITION)
    @Test
    fun isCommunalContentVisible_flagEnabled_alwaysTrue() =
        kosmos.runTest {
            val isCommunalContentVisible by collectLastValue(underTest.isCommunalContentVisible)

            communalSceneInteractor.setEditModeState(null)
            assertThat(isCommunalContentVisible).isTrue()

            communalSceneInteractor.setEditModeState(EditModeState.STARTING)
            assertThat(isCommunalContentVisible).isTrue()

            communalSceneInteractor.setEditModeState(EditModeState.CREATED)
            assertThat(isCommunalContentVisible).isTrue()

            communalSceneInteractor.setEditModeState(EditModeState.SHOWING)
            assertThat(isCommunalContentVisible).isTrue()
        }

    @Test
    fun deleteWidget() =
        kosmos.runTest {
+48 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_COMMUNAL_RESPONSIVE_GRID
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_DIRECT_EDIT_MODE
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.Flags.FLAG_HUB_EDIT_MODE_TRANSITION
import com.android.systemui.Flags.FLAG_NOTIFICATION_SHADE_BLUR
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
@@ -55,6 +56,7 @@ import com.android.systemui.communal.shared.log.CommunalMetricsLogger
import com.android.systemui.communal.shared.log.communalSceneLogger
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS
import com.android.systemui.communal.ui.viewmodel.PopupType
@@ -1008,6 +1010,52 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
            assertThat(swipeToHubEnabled).isFalse()
        }

    @Test
    @EnableFlags(FLAG_HUB_EDIT_MODE_TRANSITION)
    fun showBackgroundForEditModeTransition_flagEnabled() =
        kosmos.runTest {
            val showBackground by collectLastValue(underTest.showBackgroundForEditModeTransition)

            // Do not show background when not interacting with edit mode.
            communalSceneInteractor.setEditModeState(null)
            assertThat(showBackground).isFalse()

            // Do not show background yet when edit mode is just starting; user may need to
            // authenticate first.
            communalSceneInteractor.setEditModeState(EditModeState.STARTING)
            assertThat(showBackground).isFalse()

            // Show background when edit mode activity has been created to hide the launching
            // animation below.
            communalSceneInteractor.setEditModeState(EditModeState.CREATED)
            assertThat(showBackground).isTrue()

            // Continue to show background when edit mode activity is showing, though the SystemUI
            // window will be hidden. This ensures that when SystemUI is visible again the
            // background hides the edit mode activity finish animation below.
            communalSceneInteractor.setEditModeState(EditModeState.SHOWING)
            assertThat(showBackground).isTrue()
        }

    @Test
    @DisableFlags(FLAG_HUB_EDIT_MODE_TRANSITION)
    fun showBackgroundForEditModeTransition_flagDisabled_alwaysFalse() =
        kosmos.runTest {
            val showBackground by collectLastValue(underTest.showBackgroundForEditModeTransition)

            communalSceneInteractor.setEditModeState(null)
            assertThat(showBackground).isFalse()

            communalSceneInteractor.setEditModeState(EditModeState.STARTING)
            assertThat(showBackground).isFalse()

            communalSceneInteractor.setEditModeState(EditModeState.CREATED)
            assertThat(showBackground).isFalse()

            communalSceneInteractor.setEditModeState(EditModeState.SHOWING)
            assertThat(showBackground).isFalse()
        }

    private suspend fun setIsMainUser(isMainUser: Boolean) {
        val user = if (isMainUser) MAIN_USER_INFO else SECONDARY_USER_INFO
        with(kosmos.fakeUserRepository) {
Loading