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

Commit e53baccc authored by Matt Pietal's avatar Matt Pietal
Browse files

Use keyguard transitions to ensure correct scrim

Listen for both ALTERNATE_BOUNCER->GONE and PRIMARY_BOUNCER->GONE
transitions, and animate existing notification and behind scrim
values. This will correct an issue where the scrim disappears when
tapping on a notification in the expanded shade.

Bug: 295326104
Test: PrimaryBouncerToGoneTransitionViewModelTest
BouncerToGoneFlowsTest

Change-Id: I03207db36b780b21a6e4d2ea5c87234b7f8ea0c1
parent b3a55a90
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -26,13 +26,13 @@ import com.android.systemui.util.kotlin.Utils.Companion.toQuad
import com.android.systemui.util.kotlin.Utils.Companion.toQuint
import com.android.systemui.util.kotlin.sample
import com.android.wm.shell.animation.Interpolators
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds

@SysUISingleton
class FromAlternateBouncerTransitionInteractor
@@ -130,11 +130,16 @@ constructor(
    override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
        return ValueAnimator().apply {
            interpolator = Interpolators.LINEAR
            duration = TRANSITION_DURATION_MS.inWholeMilliseconds
            duration =
                when (toState) {
                    KeyguardState.GONE -> TO_GONE_DURATION
                    else -> TRANSITION_DURATION_MS
                }.inWholeMilliseconds
        }
    }

    companion object {
        val TRANSITION_DURATION_MS = 300.milliseconds
        val TO_GONE_DURATION = 500.milliseconds
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -143,6 +143,11 @@ constructor(
    val dozingToLockscreenTransition: Flow<TransitionStep> =
        repository.transition(DOZING, LOCKSCREEN)

    /** Receive all [TransitionStep] matching a filter of [from]->[to] */
    fun transition(from: KeyguardState, to: KeyguardState): Flow<TransitionStep> {
        return repository.transition(from, to)
    }

    /**
     * AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
     * Lockscreen (0f).
+42 −0
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.viewmodel

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow

/**
 * Breaks down ALTERNATE_BOUNCER->GONE transition into discrete steps for corresponding views to
 * consume.
 */
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class AlternateBouncerToGoneTransitionViewModel
@Inject
constructor(
    bouncerToGoneFlows: BouncerToGoneFlows,
) {

    /** Scrim alpha values */
    val scrimAlpha: Flow<ScrimAlpha> =
        bouncerToGoneFlows.scrimAlpha(TO_GONE_DURATION, ALTERNATE_BOUNCER)
}
+114 −0
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.viewmodel

import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.SysuiStatusBarStateController
import dagger.Lazy
import javax.inject.Inject
import kotlin.time.Duration
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map

/** ALTERNATE and PRIMARY bouncers common animations */
@OptIn(ExperimentalCoroutinesApi::class)
class BouncerToGoneFlows
@Inject
constructor(
    private val interactor: KeyguardTransitionInteractor,
    private val statusBarStateController: SysuiStatusBarStateController,
    private val primaryBouncerInteractor: PrimaryBouncerInteractor,
    private val keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>,
    private val featureFlags: FeatureFlagsClassic,
    private val shadeInteractor: ShadeInteractor,
) {
    /** Common fade for scrim alpha values during *BOUNCER->GONE */
    fun scrimAlpha(duration: Duration, fromState: KeyguardState): Flow<ScrimAlpha> {
        return if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
            keyguardDismissActionInteractor
                .get()
                .willAnimateDismissActionOnLockscreen
                .flatMapLatest { createScrimAlphaFlow(duration, fromState) { it } }
        } else {
            createScrimAlphaFlow(
                duration,
                fromState,
                primaryBouncerInteractor::willRunDismissFromKeyguard
            )
        }
    }

    private fun createScrimAlphaFlow(
        duration: Duration,
        fromState: KeyguardState,
        willRunAnimationOnKeyguard: () -> Boolean
    ): Flow<ScrimAlpha> {
        var isShadeExpanded = false
        var leaveShadeOpen: Boolean = false
        var willRunDismissFromKeyguard: Boolean = false
        val transitionAnimation =
            KeyguardTransitionAnimationFlow(
                transitionDuration = duration,
                transitionFlow = interactor.transition(fromState, GONE)
            )

        return shadeInteractor.shadeExpansion.flatMapLatest { shadeExpansion ->
            transitionAnimation
                .createFlow(
                    duration = duration,
                    interpolator = EMPHASIZED_ACCELERATE,
                    onStart = {
                        leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
                        willRunDismissFromKeyguard = willRunAnimationOnKeyguard()
                        isShadeExpanded = shadeExpansion > 0f
                    },
                    onStep = { 1f - it },
                )
                .map {
                    if (willRunDismissFromKeyguard) {
                        if (isShadeExpanded) {
                            ScrimAlpha(
                                behindAlpha = it,
                                notificationsAlpha = it,
                            )
                        } else {
                            ScrimAlpha()
                        }
                    } else if (leaveShadeOpen) {
                        ScrimAlpha(
                            behindAlpha = 1f,
                            notificationsAlpha = 1f,
                        )
                    } else {
                        ScrimAlpha(behindAlpha = it)
                    }
                }
        }
    }
}
+5 −36
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.keyguard.ui.viewmodel

import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlagsClassic
@@ -24,6 +23,8 @@ import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -33,7 +34,6 @@ import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map

/**
 * Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
@@ -49,11 +49,12 @@ constructor(
    private val primaryBouncerInteractor: PrimaryBouncerInteractor,
    keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>,
    featureFlags: FeatureFlagsClassic,
    bouncerToGoneFlows: BouncerToGoneFlows,
) {
    private val transitionAnimation =
        KeyguardTransitionAnimationFlow(
            transitionDuration = TO_GONE_DURATION,
            transitionFlow = interactor.primaryBouncerToGoneTransition,
            transitionFlow = interactor.transition(PRIMARY_BOUNCER, GONE)
        )

    private var leaveShadeOpen: Boolean = false
@@ -110,38 +111,6 @@ constructor(
        )
    }

    /** Scrim alpha values */
    val scrimAlpha: Flow<ScrimAlpha> =
        if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
            keyguardDismissActionInteractor
                .get()
                .willAnimateDismissActionOnLockscreen
                .flatMapLatest { createScrimAlphaFlow { it } }
        } else {
            createScrimAlphaFlow(primaryBouncerInteractor::willRunDismissFromKeyguard)
        }
    private fun createScrimAlphaFlow(willRunAnimationOnKeyguard: () -> Boolean): Flow<ScrimAlpha> {
        return transitionAnimation
            .createFlow(
                duration = TO_GONE_DURATION,
                interpolator = EMPHASIZED_ACCELERATE,
                onStart = {
                    leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
                    willRunDismissFromKeyguard = willRunAnimationOnKeyguard()
                },
                onStep = { 1f - it },
            )
            .map {
                if (willRunDismissFromKeyguard) {
                    ScrimAlpha()
                } else if (leaveShadeOpen) {
                    ScrimAlpha(
                        behindAlpha = 1f,
                        notificationsAlpha = 1f,
                    )
                } else {
                    ScrimAlpha(behindAlpha = it)
                }
            }
    }
        bouncerToGoneFlows.scrimAlpha(TO_GONE_DURATION, PRIMARY_BOUNCER)
}
Loading