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

Commit 99404d72 authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

Fixes quick affordance visibility bug.

In the new implementation of the KeyguardBottomAreaView, when the user
locks their device, moving directly from the unlocked state into
AOD/doze, we erroneously show the home controls quick affordance button
for a moment/frame before hiding it.

This was caused by our reliance on isDozing and dozeAmount where, what
we should really look at is isDozing and isKeyguardShowing - like the CL
is doing.

The approach taken here is actually refactored out of the wallet quick
affordance config implementation and applied generically to all quick
affordance config implementation at the use-case layer. The reason I
thought this could work is because I was only seeing the home controls
button exhibit this bug while the wallet one was not. I didn't test the
QR Code scanner one, but I bet it would have worked just like the home
controls one.

Bug: 240969525
Fix: 240969525
Test: locking from the unlocked home-screen proves that the fix works
because it no longer flickers the quick affordance view over the AOD
screen. Also, unit tests were added/modified to capture this.

Change-Id: Id2917989991802825d1024d5a0d9161d4452265f
parent a9f3033f
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -17,14 +17,12 @@

package com.android.systemui.keyguard.data.quickaffordance

import android.content.Context
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.containeddrawable.ContainedDrawable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
@@ -35,12 +33,9 @@ import kotlinx.coroutines.flow.Flow
class QrCodeScannerKeyguardQuickAffordanceConfig
@Inject
constructor(
    @Application context: Context,
    private val controller: QRCodeScannerController,
) : KeyguardQuickAffordanceConfig {

    private val appContext = context.applicationContext

    override val state: Flow<KeyguardQuickAffordanceConfig.State> = conflatedCallbackFlow {
        val callback =
            object : QRCodeScannerController.Callback {
+37 −57
Original line number Diff line number Diff line
@@ -29,51 +29,21 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.containeddrawable.ContainedDrawable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.policy.KeyguardStateControllerExt.isKeyguardShowing
import com.android.systemui.wallet.controller.QuickAccessWalletController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf

/** Quick access wallet quick affordance data source. */
@SysUISingleton
class QuickAccessWalletKeyguardQuickAffordanceConfig
@Inject
constructor(
    private val keyguardStateController: KeyguardStateController,
    private val walletController: QuickAccessWalletController,
    private val activityStarter: ActivityStarter,
) : KeyguardQuickAffordanceConfig {

    override val state: Flow<KeyguardQuickAffordanceConfig.State> =
        keyguardStateController
            .isKeyguardShowing(TAG)
            .flatMapLatest { isKeyguardShowing ->
                stateInternal(isKeyguardShowing)
            }

    override fun onQuickAffordanceClicked(
        animationController: ActivityLaunchAnimator.Controller?,
    ): KeyguardQuickAffordanceConfig.OnClickedResult {
        walletController.startQuickAccessUiIntent(
            activityStarter,
            animationController,
            /* hasCard= */ true,
        )
        return KeyguardQuickAffordanceConfig.OnClickedResult.Handled
    }

    private fun stateInternal(
        isKeyguardShowing: Boolean
    ): Flow<KeyguardQuickAffordanceConfig.State> {
        if (!isKeyguardShowing) {
            return flowOf(KeyguardQuickAffordanceConfig.State.Hidden)
        }

        return conflatedCallbackFlow {
    override val state: Flow<KeyguardQuickAffordanceConfig.State> = conflatedCallbackFlow {
        val callback =
            object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
                override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) {
@@ -111,6 +81,16 @@ constructor(
            )
        }
    }

    override fun onQuickAffordanceClicked(
        animationController: ActivityLaunchAnimator.Controller?,
    ): KeyguardQuickAffordanceConfig.OnClickedResult {
        walletController.startQuickAccessUiIntent(
            activityStarter,
            animationController,
            /* hasCard= */ true,
        )
        return KeyguardQuickAffordanceConfig.OnClickedResult.Handled
    }

    private fun state(
+34 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.common.data.model.Position
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -49,6 +50,15 @@ interface KeyguardRepository {
     */
    val clockPosition: StateFlow<Position>

    /**
     * Observable for whether the keyguard is showing.
     *
     * Note: this is also `true` when the lock-screen is occluded with an `Activity` "above" it in
     * the z-order (which is not really above the system UI window, but rather - the lock-screen
     * becomes invisible to reveal the "occluding activity").
     */
    val isKeyguardShowing: Flow<Boolean>

    /**
     * Observable for whether we are in doze state.
     *
@@ -91,6 +101,7 @@ class KeyguardRepositoryImpl
@Inject
constructor(
    statusBarStateController: StatusBarStateController,
    keyguardStateController: KeyguardStateController,
) : KeyguardRepository {
    private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
    override val animateBottomAreaDozingTransitions =
@@ -102,6 +113,29 @@ constructor(
    private val _clockPosition = MutableStateFlow(Position(0, 0))
    override val clockPosition = _clockPosition.asStateFlow()

    override val isKeyguardShowing: Flow<Boolean> = conflatedCallbackFlow {
        val callback =
            object : KeyguardStateController.Callback {
                override fun onKeyguardShowingChanged() {
                    trySendWithFailureLogging(
                        keyguardStateController.isShowing,
                        TAG,
                        "updated isKeyguardShowing"
                    )
                }
            }

        keyguardStateController.addCallback(callback)
        // Adding the callback does not send an initial update.
        trySendWithFailureLogging(
            keyguardStateController.isShowing,
            TAG,
            "initial isKeyguardShowing"
        )

        awaitClose { keyguardStateController.removeCallback(callback) }
    }

    override val isDozing: Flow<Boolean> = conflatedCallbackFlow {
        val callback =
            object : StatusBarStateController.StateListener {
+2 −1
Original line number Diff line number Diff line
@@ -30,7 +30,8 @@ interface KeyguardRepositoryModule {
        impl: KeyguardQuickAffordanceRepositoryImpl
    ): KeyguardQuickAffordanceRepository

    @Binds fun keyguardQuickAffordanceConfigs(
    @Binds
    fun keyguardQuickAffordanceConfigs(
        impl: KeyguardQuickAffordanceConfigsImpl
    ): KeyguardQuickAffordanceConfigs
}
+39 −0
Original line number Diff line number Diff line
@@ -15,32 +15,25 @@
 *
 */

package com.android.systemui.statusbar.policy
package com.android.systemui.keyguard.domain.usecase

import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow
import kotlinx.coroutines.channels.awaitClose
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow

object KeyguardStateControllerExt {
/**
     * Returns an observable for whether the keyguard is currently shown or not.
 * Use-case for observing whether the keyguard is currently being shown.
 *
 * Note: this is also `true` when the lock-screen is occluded with an `Activity` "above" it in the
 * z-order (which is not really above the system UI window, but rather - the lock-screen becomes
 * invisible to reveal the "occluding activity").
 */
    fun KeyguardStateController.isKeyguardShowing(loggingTag: String): Flow<Boolean> {
        return ConflatedCallbackFlow.conflatedCallbackFlow {
            val callback =
                object : KeyguardStateController.Callback {
                    override fun onKeyguardShowingChanged() {
                        trySendWithFailureLogging(
                            isShowing, loggingTag, "updated isKeyguardShowing")
                    }
                }

            addCallback(callback)
            // Adding the callback does not send an initial update.
            trySendWithFailureLogging(isShowing, loggingTag, "initial isKeyguardShowing")

            awaitClose { removeCallback(callback) }
        }
class ObserveIsKeyguardShowingUseCase
@Inject
constructor(
    private val repository: KeyguardRepository,
) {
    operator fun invoke(): Flow<Boolean> {
        return repository.isKeyguardShowing
    }
}
Loading