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

Commit caed3833 authored by Brad Hinegardner's avatar Brad Hinegardner
Browse files

Avoid using the same previewMode logic between lockscreen and WPP

Previously `previewMode` lived inside `KeyguardInteractor` which is a SysuiSingleton.
This caused issues as even though we had different copies of `KeyguardRootView` for lockscreen and WallpaperPicker, both Views were using the same value of previewMode, which is never explicitly disabled upon leaving WPP.

Split up the enabling of previewMode between the KeyguardRootView and the Quick affordances, as the KeyguardRootView doesn't need to know about the quick affordances.

Fixes: 296249943
Test: atest KeyguardQuickAffordancesCombinedViewModel.kt
Test: atest KeyguardRootViewModelTest.kt
Test: manual -- go to WPP and shortcuts customization, leave, go back to lockscreen. The UI is now different between them as intended
Change-Id: I81a059002e179bb80be40617ce427d595b58b616
parent 9fbfb01e
Loading
Loading
Loading
Loading
+1 −14
Original line number Diff line number Diff line
@@ -40,10 +40,10 @@ import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -53,7 +53,6 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import javax.inject.Inject

/**
 * Encapsulates business-logic related to the keyguard but not to a more specific part within it.
@@ -68,18 +67,6 @@ constructor(
    bouncerRepository: KeyguardBouncerRepository,
    configurationRepository: ConfigurationRepository,
) {

    data class PreviewMode(
        val isInPreviewMode: Boolean = false,
        val shouldHighlightSelectedAffordance: Boolean = false,
    )

    /**
     * Whether this view-model instance is powering the preview experience that renders exclusively
     * in the wallpaper picker application. This should _always_ be `false` for the real lock screen
     * experience.
     */
    val previewMode = MutableStateFlow(PreviewMode())
    /**
     * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
     * all.
+49 −22
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
@@ -56,25 +57,31 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel
import com.android.systemui.monet.ColorScheme
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.systemui.shared.clocks.DefaultClockController
import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants
import com.android.systemui.statusbar.KeyguardIndicationController
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking

/** Renders the preview of the lock screen. */
class KeyguardPreviewRenderer
@OptIn(ExperimentalCoroutinesApi::class)
@AssistedInject
constructor(
    @Application private val context: Context,
@@ -99,6 +106,9 @@ constructor(
    @Assisted bundle: Bundle,
    private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
    private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
    private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
    private val chipbarCoordinator: ChipbarCoordinator,
    private val keyguardStateController: KeyguardStateController,
) {

    val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
@@ -130,11 +140,13 @@ constructor(

    init {
        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
            keyguardRootViewModel.enablePreviewMode(
            keyguardRootViewModel.enablePreviewMode()
            quickAffordancesCombinedViewModel.enablePreviewMode(
                initiallySelectedSlotId =
                    bundle.getString(
                        KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID,
                ),
                    )
                        ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
                shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
            )
        } else {
@@ -163,17 +175,8 @@ constructor(
            val rootView = FrameLayout(context)

            if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                val keyguardRootView = KeyguardRootView(context, null)
                rootView.addView(
                    keyguardRootView,
                    FrameLayout.LayoutParams(
                        FrameLayout.LayoutParams.MATCH_PARENT,
                        FrameLayout.LayoutParams.MATCH_PARENT,
                    ),
                )
                setupShortcuts(keyguardRootView)
                KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel)
                keyguardBlueprintInteractor.refreshBlueprint()
                setupKeyguardRootView(rootView)
                setupShortcuts(rootView)
            } else {
                setUpBottomArea(rootView)
            }
@@ -325,10 +328,34 @@ constructor(
        )
    }

    private fun setupShortcuts(keyguardRootView: KeyguardRootView) {
    @OptIn(ExperimentalCoroutinesApi::class)
    private fun setupKeyguardRootView(rootView: FrameLayout) {
        val keyguardRootView = KeyguardRootView(context, null)
        disposables.add(
            KeyguardRootViewBinder.bind(
                keyguardRootView,
                keyguardRootViewModel,
                featureFlags,
                occludingAppDeviceEntryMessageViewModel,
                chipbarCoordinator,
                keyguardStateController,
            )
        )
        rootView.addView(
            keyguardRootView,
            FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT,
            ),
        )
        KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel)
        keyguardBlueprintInteractor.refreshBlueprint()
    }

    private fun setupShortcuts(rootView: FrameLayout) {
        shortcutsBindings.add(
            KeyguardQuickAffordanceViewBinder.bind(
                keyguardRootView.requireViewById(R.id.start_button),
                rootView.requireViewById(R.id.start_button),
                quickAffordancesCombinedViewModel.startButton,
                keyguardRootViewModel.alpha,
                falsingManager,
@@ -340,7 +367,7 @@ constructor(

        shortcutsBindings.add(
            KeyguardQuickAffordanceViewBinder.bind(
                keyguardRootView.requireViewById(R.id.end_button),
                rootView.requireViewById(R.id.end_button),
                quickAffordancesCombinedViewModel.endButton,
                keyguardRootViewModel.alpha,
                falsingManager,
+68 −36
Original line number Diff line number Diff line
@@ -18,22 +18,20 @@
package com.android.systemui.keyguard.ui.viewmodel

import androidx.annotation.VisibleForTesting
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import javax.inject.Inject

@OptIn(ExperimentalCoroutinesApi::class)
class KeyguardQuickAffordancesCombinedViewModel
@@ -43,6 +41,18 @@ constructor(
    private val keyguardInteractor: KeyguardInteractor,
) {

    data class PreviewMode(
        val isInPreviewMode: Boolean = false,
        val shouldHighlightSelectedAffordance: Boolean = false,
    )

    /**
     * Whether this view-model instance is powering the preview experience that renders exclusively
     * in the wallpaper picker application. This should _always_ be `false` for the real lock screen
     * experience.
     */
    private val previewMode = MutableStateFlow(PreviewMode())

    /**
     * ID of the slot that's currently selected in the preview that renders exclusively in the
     * wallpaper picker application. This is ignored for the actual, real lock screen experience.
@@ -85,10 +95,34 @@ constructor(
        selectedPreviewSlotId.value = slotId
    }

    /**
     * Puts this view-model in "preview mode", which means it's being used for UI that is rendering
     * the lock screen preview in wallpaper picker / settings and not the real experience on the
     * lock screen.
     *
     * @param initiallySelectedSlotId The ID of the initial slot to render as the selected one.
     * @param shouldHighlightSelectedAffordance Whether the selected quick affordance should be
     *   highlighted (while all others are dimmed to make the selected one stand out).
     */
    fun enablePreviewMode(
        initiallySelectedSlotId: String?,
        shouldHighlightSelectedAffordance: Boolean,
    ) {
        val newPreviewMode =
            PreviewMode(
                isInPreviewMode = true,
                shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
            )
        onPreviewSlotSelected(
            initiallySelectedSlotId ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
        )
        previewMode.value = newPreviewMode
    }

    private fun button(
        position: KeyguardQuickAffordancePosition
    ): Flow<KeyguardQuickAffordanceViewModel> {
        return keyguardInteractor.previewMode.flatMapLatest { previewMode ->
        return previewMode.flatMapLatest { previewMode ->
            combine(
                    if (previewMode.isInPreviewMode) {
                        quickAffordanceInteractor.quickAffordanceAlwaysVisible(position = position)
@@ -167,8 +201,6 @@ constructor(
        // time, we don't want the number to be too close to 1.0 such that there is a chance that we
        // never treat the affordance UI as "fully opaque" as that would risk making it forever not
        // clickable.
        @VisibleForTesting
        const val AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD = 0.95f
        @VisibleForTesting const val AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD = 0.95f
    }

}
+18 −24
Original line number Diff line number Diff line
@@ -19,29 +19,37 @@ package com.android.systemui.keyguard.ui.viewmodel

import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import javax.inject.Inject

@OptIn(ExperimentalCoroutinesApi::class)
class KeyguardRootViewModel
@Inject
constructor(
    private val keyguardInteractor: KeyguardInteractor,
    private val keyguardQuickAffordancesCombinedViewModel: KeyguardQuickAffordancesCombinedViewModel
)
{
) {

    data class PreviewMode(val isInPreviewMode: Boolean = false)

    /**
     * Whether this view-model instance is powering the preview experience that renders exclusively
     * in the wallpaper picker application. This should _always_ be `false` for the real lock screen
     * experience.
     */
    private val previewMode = MutableStateFlow(PreviewMode())

    /** Represents the current state of the KeyguardRootView visibility */
    val keyguardRootViewVisibilityState: Flow<KeyguardRootViewVisibilityState> =
        keyguardInteractor.keyguardRootViewVisibilityState

    /** An observable for the alpha level for the entire keyguard root view. */
    val alpha: Flow<Float> =
        keyguardInteractor.previewMode.flatMapLatest {
        previewMode.flatMapLatest {
            if (it.isInPreviewMode) {
                flowOf(1f)
            } else {
@@ -53,23 +61,9 @@ constructor(
     * Puts this view-model in "preview mode", which means it's being used for UI that is rendering
     * the lock screen preview in wallpaper picker / settings and not the real experience on the
     * lock screen.
     *
     * @param initiallySelectedSlotId The ID of the initial slot to render as the selected one.
     * @param shouldHighlightSelectedAffordance Whether the selected quick affordance should be
     *   highlighted (while all others are dimmed to make the selected one stand out).
     */
    fun enablePreviewMode(
        initiallySelectedSlotId: String?,
        shouldHighlightSelectedAffordance: Boolean,
    ) {
        keyguardInteractor.previewMode.value =
            KeyguardInteractor.PreviewMode(
                isInPreviewMode = true,
                shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
            )
        keyguardQuickAffordancesCombinedViewModel.onPreviewSlotSelected(
            initiallySelectedSlotId ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
        )
    fun enablePreviewMode() {
        val newPreviewMode = PreviewMode(true)
        previewMode.value = newPreviewMode
    }

}
+2 −10
Original line number Diff line number Diff line
@@ -281,11 +281,7 @@ class KeyguardQuickAffordancesCombinedViewModelTest : SysuiTestCase() {
            underTest.onPreviewSlotSelected(
                KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
            )
            keyguardInteractor.previewMode.value =
                KeyguardInteractor.PreviewMode(
                    isInPreviewMode = true,
                    shouldHighlightSelectedAffordance = true,
                )
            underTest.enablePreviewMode(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, true)

            repository.setKeyguardShowing(false)
            val latest = collectLastValue(underTest.startButton)
@@ -330,11 +326,7 @@ class KeyguardQuickAffordancesCombinedViewModelTest : SysuiTestCase() {
            underTest.onPreviewSlotSelected(
                KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
            )
            keyguardInteractor.previewMode.value =
                KeyguardInteractor.PreviewMode(
                    isInPreviewMode = true,
                    shouldHighlightSelectedAffordance = true,
                )
            underTest.enablePreviewMode(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, true)

            repository.setKeyguardShowing(false)
            val endButton = collectLastValue(underTest.endButton)
Loading