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

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

Transitions - Add dreaming state

Add support for states in and out of dreaming. At the moment, AOD is
equivalent to DOZING but these will be separated out in the future.

Test: atest KeyguardTransitionRepositoryTest
KeyguardRepositoryImplTest
Bug: 195430376

Change-Id: I73b51987f01540cc3d321f23286a3344d0847f9c
parent d3783f7b
Loading
Loading
Loading
Loading
+34 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.repository

import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.Position
@@ -87,6 +88,14 @@ interface KeyguardRepository {
     */
    val isDozing: Flow<Boolean>

    /**
     * Observable for whether the device is dreaming.
     *
     * Dozing/AOD is a specific type of dream, but it is also possible for other non-systemui dreams
     * to be active, such as screensavers.
     */
    val isDreaming: Flow<Boolean>

    /**
     * Observable for the amount of doze we are currently in.
     *
@@ -244,6 +253,25 @@ constructor(
            }
            .distinctUntilChanged()

    override val isDreaming: Flow<Boolean> =
        conflatedCallbackFlow {
                val callback =
                    object : KeyguardUpdateMonitorCallback() {
                        override fun onDreamingStateChanged(isDreaming: Boolean) {
                            trySendWithFailureLogging(isDreaming, TAG, "updated isDreaming")
                        }
                    }
                keyguardUpdateMonitor.registerCallback(callback)
                trySendWithFailureLogging(
                    keyguardUpdateMonitor.isDreaming,
                    TAG,
                    "initial isDreaming",
                )

                awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
            }
            .distinctUntilChanged()

    override val dozeAmount: Flow<Float> = conflatedCallbackFlow {
        val callback =
            object : StatusBarStateController.StateListener {
+2 −2
Original line number Diff line number Diff line
@@ -112,7 +112,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
        // Seed with transitions signaling a boot into lockscreen state
        emitTransition(
            TransitionStep(
                KeyguardState.NONE,
                KeyguardState.OFF,
                KeyguardState.LOCKSCREEN,
                0f,
                TransitionState.STARTED,
@@ -120,7 +120,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
        )
        emitTransition(
            TransitionStep(
                KeyguardState.NONE,
                KeyguardState.OFF,
                KeyguardState.LOCKSCREEN,
                1f,
                TransitionState.FINISHED,
+81 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.domain.interactor

import android.animation.ValueAnimator
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

@SysUISingleton
class DreamingLockscreenTransitionInteractor
@Inject
constructor(
    @Application private val scope: CoroutineScope,
    private val keyguardInteractor: KeyguardInteractor,
    private val keyguardTransitionRepository: KeyguardTransitionRepository,
    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor("DREAMING<->LOCKSCREEN") {

    override fun start() {
        scope.launch {
            keyguardInteractor.isDreaming
                .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
                .collect { pair ->
                    val (isDreaming, keyguardState) = pair
                    if (isDreaming && keyguardState == KeyguardState.LOCKSCREEN) {
                        keyguardTransitionRepository.startTransition(
                            TransitionInfo(
                                name,
                                KeyguardState.LOCKSCREEN,
                                KeyguardState.DREAMING,
                                getAnimator(),
                            )
                        )
                    } else if (!isDreaming && keyguardState == KeyguardState.DREAMING) {
                        keyguardTransitionRepository.startTransition(
                            TransitionInfo(
                                name,
                                KeyguardState.DREAMING,
                                KeyguardState.LOCKSCREEN,
                                getAnimator(),
                            )
                        )
                    }
                }
        }
    }

    private fun getAnimator(): ValueAnimator {
        return ValueAnimator().apply {
            setInterpolator(Interpolators.LINEAR)
            setDuration(TRANSITION_DURATION_MS)
        }
    }

    companion object {
        private const val TRANSITION_DURATION_MS = 500L
    }
}
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.domain.interactor

import android.animation.ValueAnimator
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isSleepingOrStartingToSleep
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

@SysUISingleton
class DreamingToAodTransitionInteractor
@Inject
constructor(
    @Application private val scope: CoroutineScope,
    private val keyguardInteractor: KeyguardInteractor,
    private val keyguardTransitionRepository: KeyguardTransitionRepository,
    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor("DREAMING->AOD") {

    override fun start() {
        scope.launch {
            keyguardInteractor.wakefulnessState
                .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
                .collect { pair ->
                    val (wakefulnessState, keyguardState) = pair
                    if (
                        isSleepingOrStartingToSleep(wakefulnessState) &&
                            keyguardState == KeyguardState.DREAMING
                    ) {
                        keyguardTransitionRepository.startTransition(
                            TransitionInfo(
                                name,
                                KeyguardState.DREAMING,
                                KeyguardState.AOD,
                                getAnimator(),
                            )
                        )
                    }
                }
        }
    }

    private fun getAnimator(): ValueAnimator {
        return ValueAnimator().apply {
            setInterpolator(Interpolators.LINEAR)
            setDuration(TRANSITION_DURATION_MS)
        }
    }

    companion object {
        private const val TRANSITION_DURATION_MS = 300L
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -41,6 +41,11 @@ constructor(
    val dozeAmount: Flow<Float> = repository.dozeAmount
    /** Whether the system is in doze mode. */
    val isDozing: Flow<Boolean> = repository.isDozing
    /**
     * Whether the system is dreaming. [isDreaming] will be always be true when [isDozing] is true,
     * but not vice-versa.
     */
    val isDreaming: Flow<Boolean> = repository.isDreaming
    /** Whether the keyguard is showing or not. */
    val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
    /** Whether the keyguard is going away. */
Loading