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

Commit e991d44d authored by Lucas Silva's avatar Lucas Silva
Browse files

Initial implementation of HUB<->OCCLUDED transitions.

This allows us to go directly from HUB->OCCLUDED and back, with a custom
fade animation instead of the default fade+translate animation.

Known issues:
1. Keyguard wallpaper occasionally flickers before hub becomes visible.
   Occluded activity is getting removed before hub is visible.
2. Hub fade isn't smooth
3. Expanding activities from widgets while the dream is active is
   broken.
4. Occasional notification flicker when exiting an activity to go back
   to the hub.

Bug: 332591536
Test: atest KeyguardTransitionScenariosTest
Test: atest CommunalSceneStartableTest
Flag: ACONFIG com.android.systemui.communal_hub TEAMFOOD
Change-Id: I5db502a46127a68d709656d2678af76a6dbd12b3
parent 8c29213b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.transitions
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.res.R
@@ -41,6 +42,11 @@ object Communal {
}

val sceneTransitions = transitions {
    to(CommunalScenes.Communal, key = CommunalTransitionKeys.SimpleFade) {
        spec = tween(durationMillis = 250)
        fade(Communal.Elements.Scrim)
        fade(Communal.Elements.Content)
    }
    to(CommunalScenes.Communal) {
        spec = tween(durationMillis = 1000)
        translate(Communal.Elements.Content, Edge.Right)
+6 −5
Original line number Diff line number Diff line
@@ -120,19 +120,20 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        }

    @Test
    fun exitingDream_forceCommunalScene() =
    fun occluded_forceBlankScene() =
        with(kosmos) {
            testScope.runTest {
                val scene by collectLastValue(communalInteractor.desiredScene)
                assertThat(scene).isEqualTo(CommunalScenes.Blank)
                communalInteractor.changeScene(CommunalScenes.Communal)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)

                updateDocked(true)
                fakeKeyguardTransitionRepository.sendTransitionSteps(
                    from = KeyguardState.DREAMING,
                    to = KeyguardState.LOCKSCREEN,
                    from = KeyguardState.GLANCEABLE_HUB,
                    to = KeyguardState.OCCLUDED,
                    testScope = this
                )
                assertThat(scene).isEqualTo(CommunalScenes.Communal)
                assertThat(scene).isEqualTo(CommunalScenes.Blank)
            }
        }

+12 −4
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import com.android.compose.animation.scene.SceneKey
import com.android.systemui.CoreStartable
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -70,9 +71,9 @@ constructor(
        keyguardTransitionInteractor.startedKeyguardTransitionStep
            .mapLatest(::determineSceneAfterTransition)
            .filterNotNull()
            // TODO(b/322787129): Also set a custom transition animation here to avoid the regular
            // slide-in animation when setting the scene programmatically
            .onEach { nextScene -> communalInteractor.changeScene(nextScene) }
            .onEach { nextScene ->
                communalInteractor.changeScene(nextScene, CommunalTransitionKeys.SimpleFade)
            }
            .launchIn(applicationScope)

        // TODO(b/322787129): re-enable once custom animations are in place
@@ -143,7 +144,14 @@ constructor(
        val docked = dockManager.isDocked

        return when {
            docked && to == KeyguardState.LOCKSCREEN && from == KeyguardState.DREAMING -> {
            to == KeyguardState.OCCLUDED -> {
                // Hide communal when an activity is started on keyguard, to ensure the activity
                // underneath the hub is shown.
                CommunalScenes.Blank
            }
            to == KeyguardState.GLANCEABLE_HUB && from == KeyguardState.OCCLUDED -> {
                // When transitioning to the hub from an occluded state, fade out the hub without
                // doing any translation.
                CommunalScenes.Communal
            }
            to == KeyguardState.GONE -> CommunalScenes.Blank
+7 −1
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dock.DockManager
import com.android.systemui.dock.retrieveIsDocked
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
@@ -103,6 +105,7 @@ constructor(
    private val userTracker: UserTracker,
    private val activityStarter: ActivityStarter,
    private val userManager: UserManager,
    private val dockManager: DockManager,
    sceneInteractor: SceneInteractor,
    sceneContainerFlags: SceneContainerFlags,
    @CommunalLog logBuffer: LogBuffer,
@@ -123,7 +126,7 @@ constructor(
        and(
                communalSettingsInteractor.isCommunalEnabled,
                not(keyguardInteractor.isEncryptedOrLockdown),
                or(keyguardInteractor.isKeyguardVisible, keyguardInteractor.isDreaming)
                or(keyguardInteractor.isKeyguardShowing, keyguardInteractor.isDreaming)
            )
            .distinctUntilChanged()
            .onEach { available ->
@@ -143,6 +146,9 @@ constructor(
                replay = 1,
            )

    /** Whether to show communal by default */
    val showByDefault: Flow<Boolean> = and(isCommunalAvailable, dockManager.retrieveIsDocked())

    /**
     * Target scene as requested by the underlying [SceneTransitionLayout] or through [changeScene].
     *
+29 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.communal.shared.model

import com.android.compose.animation.scene.TransitionKey

/**
 * Defines all known named transitions for [CommunalScenes].
 *
 * These transitions can be referenced by key when changing scenes programmatically.
 */
object CommunalTransitionKeys {
    /** Fades the glanceable hub without any translation */
    val SimpleFade = TransitionKey("SimpleFade")
}
Loading