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

Commit 61d14d94 authored by Andreas Miko's avatar Andreas Miko
Browse files

Add UNDEFINED KTF state and tie it to STL transitions

UNDEFINED is a special state that is always tied to STL transitions. It
is important that STL and KTF stay in-sync at all times. To guarantee
this UNDEFINED state is only controlled by
LockscreenSceneTransitionInteractor.

Test: LockscreenSceneTransitionInteractorTest
Test: Manual testing. Navigated around scenes and observed in logcat
 that KTF is following around correctly.
Bug: b/330311871
Bug: b/336581871
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Change-Id: I2f9795415eef0ecd64a6181d2599b170af95866c
parent 92b7ff77
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -247,7 +247,7 @@ constructor(
        state: TransitionState
    ) {
        if (updateTransitionId != transitionId) {
            Log.wtf(TAG, "Attempting to update with old/invalid transitionId: $transitionId")
            Log.w(TAG, "Attempting to update with old/invalid transitionId: $transitionId")
            return
        }

+37 −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.keyguard.data.repository

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.KeyguardState
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow

@SysUISingleton
class LockscreenSceneTransitionRepository @Inject constructor() {

    /**
     * This [KeyguardState] will indicate which sub state within KTF should be navigated to when the
     * next transition into the Lockscreen scene is started. It will be consumed exactly once and
     * after that the state will be set back to [DEFAULT_STATE].
     */
    val nextLockscreenTargetState: MutableStateFlow<KeyguardState> = MutableStateFlow(DEFAULT_STATE)

    companion object {
        val DEFAULT_STATE = KeyguardState.LOCKSCREEN
    }
}
+34 −1
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@

package com.android.systemui.keyguard.domain.interactor

import android.annotation.FloatRange
import android.annotation.SuppressLint
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -34,6 +36,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.pairwise
import java.util.UUID
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -76,6 +79,8 @@ constructor(
     * single state. This prevent the redundant filters from running.
     */
    private val transitionValueCache = mutableMapOf<KeyguardState, MutableSharedFlow<Float>>()

    @SuppressLint("SharedFlowCreation")
    private fun getTransitionValueFlow(state: KeyguardState): MutableSharedFlow<Float> {
        return transitionValueCache.getOrPut(state) {
            MutableSharedFlow<Float>(
@@ -90,6 +95,9 @@ constructor(
    @Deprecated("Not performant - Use something else in this class")
    val transitions = repository.transitions

    val transitionState: StateFlow<TransitionStep> =
        transitions.stateIn(scope, SharingStarted.Eagerly, TransitionStep())

    /**
     * A pair of the most recent STARTED step, and the transition step immediately preceding it. The
     * transition framework enforces that the previous step is either a CANCELED or FINISHED step,
@@ -99,6 +107,7 @@ constructor(
     * FINISHED. In the case of a CANCELED step, we can also figure out which state we were coming
     * from when we were canceled.
     */
    @SuppressLint("SharedFlowCreation")
    val startedStepWithPrecedingStep =
        repository.transitions
            .pairwise()
@@ -144,9 +153,10 @@ constructor(
    }

    /** Given an [edge], return a SharedFlow to collect only relevant [TransitionStep]. */
    @SuppressLint("SharedFlowCreation")
    fun getOrCreateFlow(edge: Edge): MutableSharedFlow<TransitionStep> {
        return transitionMap.getOrPut(edge) {
            MutableSharedFlow<TransitionStep>(
            MutableSharedFlow(
                extraBufferCapacity = 10,
                onBufferOverflow = BufferOverflow.DROP_OLDEST
            )
@@ -180,6 +190,7 @@ constructor(
     * AOD<->* transition information, mapped to dozeAmount range of AOD (1f) <->
     * * (0f).
     */
    @SuppressLint("SharedFlowCreation")
    val dozeAmountTransition: Flow<TransitionStep> =
        repository.transitions
            .filter { step -> step.from == AOD || step.to == AOD }
@@ -201,11 +212,20 @@ constructor(
        repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED }

    /** The destination state of the last [TransitionState.STARTED] transition. */
    @SuppressLint("SharedFlowCreation")
    val startedKeyguardState: SharedFlow<KeyguardState> =
        startedKeyguardTransitionStep
            .map { step -> step.to }
            .shareIn(scope, SharingStarted.Eagerly, replay = 1)

    /** The from state of the last [TransitionState.STARTED] transition. */
    // TODO: is it performant to have several SharedFlows side by side instead of one?
    @SuppressLint("SharedFlowCreation")
    val startedKeyguardFromState: SharedFlow<KeyguardState> =
        startedKeyguardTransitionStep
            .map { step -> step.from }
            .shareIn(scope, SharingStarted.Eagerly, replay = 1)

    /** Which keyguard state to use when the device goes to sleep. */
    val asleepKeyguardState: StateFlow<KeyguardState> =
        keyguardRepository.isAodAvailable
@@ -243,6 +263,7 @@ constructor(
     * sufficient. However, if you're having issues with state *during* transitions started after
     * one or more canceled transitions, you probably need to use [currentKeyguardState].
     */
    @SuppressLint("SharedFlowCreation")
    val finishedKeyguardState: SharedFlow<KeyguardState> =
        finishedKeyguardTransitionStep
            .map { step -> step.to }
@@ -491,7 +512,19 @@ constructor(
        return startedKeyguardState.replayCache.last()
    }

    fun getStartedFromState(): KeyguardState {
        return startedKeyguardFromState.replayCache.last()
    }

    fun getFinishedState(): KeyguardState {
        return finishedKeyguardState.replayCache.last()
    }

    suspend fun startTransition(info: TransitionInfo) = repository.startTransition(info)

    fun updateTransition(
        transitionId: UUID,
        @FloatRange(from = 0.0, to = 1.0) value: Float,
        state: TransitionState
    ) = repository.updateTransition(transitionId, value, state)
}
+1 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ constructor(
            KeyguardState.LOCKSCREEN -> true
            KeyguardState.GONE -> true
            KeyguardState.OCCLUDED -> true
            KeyguardState.UNDEFINED -> true
        }
    }

+8 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.domain.interactor

import com.android.systemui.CoreStartable
import com.android.systemui.keyguard.domain.interactor.scenetransition.LockscreenSceneTransitionInteractor
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -30,6 +31,13 @@ abstract class StartKeyguardTransitionModule {
    @ClassKey(KeyguardTransitionCoreStartable::class)
    abstract fun bind(impl: KeyguardTransitionCoreStartable): CoreStartable

    @Binds
    @IntoMap
    @ClassKey(LockscreenSceneTransitionInteractor::class)
    abstract fun bindLockscreenSceneTransitionInteractor(
        impl: LockscreenSceneTransitionInteractor
    ): CoreStartable

    @Binds
    @IntoSet
    abstract fun fromPrimaryBouncer(
Loading