Merge "Transitions - Add doze transition information" into tm-qpr-dev am: 2850e3301a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20495869

Change-Id: I1b366750a609f1db75ce75f5b87b0f86e14c3e97
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Matt Pietal
2022-11-18 12:34:00 +00:00
committed by Automerger Merge Worker
13 changed files with 527 additions and 231 deletions

View File

@@ -0,0 +1,48 @@
/*
* 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.doze
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.policy.CallbackController
import javax.inject.Inject
/** Receives doze transition events, and passes those events to registered callbacks. */
@SysUISingleton
class DozeTransitionListener @Inject constructor() :
DozeMachine.Part, CallbackController<DozeTransitionCallback> {
val callbacks = mutableSetOf<DozeTransitionCallback>()
var oldState = DozeMachine.State.UNINITIALIZED
var newState = DozeMachine.State.UNINITIALIZED
override fun transitionTo(oldState: DozeMachine.State, newState: DozeMachine.State) {
this.oldState = oldState
this.newState = newState
callbacks.forEach { it.onDozeTransition(oldState, newState) }
}
override fun addCallback(callback: DozeTransitionCallback) {
callbacks.add(callback)
}
override fun removeCallback(callback: DozeTransitionCallback) {
callbacks.remove(callback)
}
}
interface DozeTransitionCallback {
fun onDozeTransition(oldState: DozeMachine.State, newState: DozeMachine.State)
}

View File

@@ -35,6 +35,7 @@ import com.android.systemui.doze.DozeScreenStatePreventingAdapter;
import com.android.systemui.doze.DozeSensors; import com.android.systemui.doze.DozeSensors;
import com.android.systemui.doze.DozeSuppressor; import com.android.systemui.doze.DozeSuppressor;
import com.android.systemui.doze.DozeSuspendScreenStatePreventingAdapter; import com.android.systemui.doze.DozeSuspendScreenStatePreventingAdapter;
import com.android.systemui.doze.DozeTransitionListener;
import com.android.systemui.doze.DozeTriggers; import com.android.systemui.doze.DozeTriggers;
import com.android.systemui.doze.DozeUi; import com.android.systemui.doze.DozeUi;
import com.android.systemui.doze.DozeWallpaperState; import com.android.systemui.doze.DozeWallpaperState;
@@ -83,7 +84,7 @@ public abstract class DozeModule {
DozeUi dozeUi, DozeScreenState dozeScreenState, DozeUi dozeUi, DozeScreenState dozeScreenState,
DozeScreenBrightness dozeScreenBrightness, DozeWallpaperState dozeWallpaperState, DozeScreenBrightness dozeScreenBrightness, DozeWallpaperState dozeWallpaperState,
DozeDockHandler dozeDockHandler, DozeAuthRemover dozeAuthRemover, DozeDockHandler dozeDockHandler, DozeAuthRemover dozeAuthRemover,
DozeSuppressor dozeSuppressor) { DozeSuppressor dozeSuppressor, DozeTransitionListener dozeTransitionListener) {
return new DozeMachine.Part[]{ return new DozeMachine.Part[]{
dozePauser, dozePauser,
dozeFalsingManagerAdapter, dozeFalsingManagerAdapter,
@@ -94,7 +95,8 @@ public abstract class DozeModule {
dozeWallpaperState, dozeWallpaperState,
dozeDockHandler, dozeDockHandler,
dozeAuthRemover, dozeAuthRemover,
dozeSuppressor dozeSuppressor,
dozeTransitionListener
}; };
} }

View File

@@ -23,9 +23,14 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.common.shared.model.Position import com.android.systemui.common.shared.model.Position
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.doze.DozeHost import com.android.systemui.doze.DozeHost
import com.android.systemui.doze.DozeMachine
import com.android.systemui.doze.DozeTransitionCallback
import com.android.systemui.doze.DozeTransitionListener
import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -108,6 +113,9 @@ interface KeyguardRepository {
*/ */
val dozeAmount: Flow<Float> val dozeAmount: Flow<Float>
/** Doze state information, as it transitions */
val dozeTransitionModel: Flow<DozeTransitionModel>
/** Observable for the [StatusBarState] */ /** Observable for the [StatusBarState] */
val statusBarState: Flow<StatusBarState> val statusBarState: Flow<StatusBarState>
@@ -154,6 +162,7 @@ constructor(
biometricUnlockController: BiometricUnlockController, biometricUnlockController: BiometricUnlockController,
private val keyguardStateController: KeyguardStateController, private val keyguardStateController: KeyguardStateController,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val dozeTransitionListener: DozeTransitionListener,
) : KeyguardRepository { ) : KeyguardRepository {
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false) private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions = override val animateBottomAreaDozingTransitions =
@@ -286,6 +295,37 @@ constructor(
awaitClose { statusBarStateController.removeCallback(callback) } awaitClose { statusBarStateController.removeCallback(callback) }
} }
override val dozeTransitionModel: Flow<DozeTransitionModel> = conflatedCallbackFlow {
val callback =
object : DozeTransitionCallback {
override fun onDozeTransition(
oldState: DozeMachine.State,
newState: DozeMachine.State
) {
trySendWithFailureLogging(
DozeTransitionModel(
from = dozeMachineStateToModel(oldState),
to = dozeMachineStateToModel(newState),
),
TAG,
"doze transition model"
)
}
}
dozeTransitionListener.addCallback(callback)
trySendWithFailureLogging(
DozeTransitionModel(
from = dozeMachineStateToModel(dozeTransitionListener.oldState),
to = dozeMachineStateToModel(dozeTransitionListener.newState),
),
TAG,
"initial doze transition model"
)
awaitClose { dozeTransitionListener.removeCallback(callback) }
}
override fun isKeyguardShowing(): Boolean { override fun isKeyguardShowing(): Boolean {
return keyguardStateController.isShowing return keyguardStateController.isShowing
} }
@@ -407,6 +447,25 @@ constructor(
} }
} }
private fun dozeMachineStateToModel(state: DozeMachine.State): DozeStateModel {
return when (state) {
DozeMachine.State.UNINITIALIZED -> DozeStateModel.UNINITIALIZED
DozeMachine.State.INITIALIZED -> DozeStateModel.INITIALIZED
DozeMachine.State.DOZE -> DozeStateModel.DOZE
DozeMachine.State.DOZE_SUSPEND_TRIGGERS -> DozeStateModel.DOZE_SUSPEND_TRIGGERS
DozeMachine.State.DOZE_AOD -> DozeStateModel.DOZE_AOD
DozeMachine.State.DOZE_REQUEST_PULSE -> DozeStateModel.DOZE_REQUEST_PULSE
DozeMachine.State.DOZE_PULSING -> DozeStateModel.DOZE_PULSING
DozeMachine.State.DOZE_PULSING_BRIGHT -> DozeStateModel.DOZE_PULSING_BRIGHT
DozeMachine.State.DOZE_PULSE_DONE -> DozeStateModel.DOZE_PULSE_DONE
DozeMachine.State.FINISH -> DozeStateModel.FINISH
DozeMachine.State.DOZE_AOD_PAUSED -> DozeStateModel.DOZE_AOD_PAUSED
DozeMachine.State.DOZE_AOD_PAUSING -> DozeStateModel.DOZE_AOD_PAUSING
DozeMachine.State.DOZE_AOD_DOCKED -> DozeStateModel.DOZE_AOD_DOCKED
else -> throw IllegalArgumentException("Invalid DozeMachine.State: state")
}
}
companion object { companion object {
private const val TAG = "KeyguardRepositoryImpl" private const val TAG = "KeyguardRepositoryImpl"
} }

View File

@@ -21,10 +21,9 @@ import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isSleepingOrStartingToSleep
import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isWakingOrStartingToWake
import com.android.systemui.util.kotlin.sample import com.android.systemui.util.kotlin.sample
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@@ -39,27 +38,24 @@ constructor(
private val keyguardInteractor: KeyguardInteractor, private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository, private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor("AOD<->LOCKSCREEN") { ) : TransitionInteractor(AodLockscreenTransitionInteractor::class.simpleName!!) {
override fun start() { override fun start() {
listenForTransitionToAodFromLockscreen()
listenForTransitionToLockscreenFromAod()
}
private fun listenForTransitionToAodFromLockscreen() {
scope.launch { scope.launch {
/* keyguardInteractor
* Listening to the startedKeyguardTransitionStep (last started step) allows this code .dozeTransitionTo(DozeStateModel.DOZE_AOD)
* to interrupt an active transition, as long as they were either going to LOCKSCREEN or
* AOD state. One example is when the user presses the power button in the middle of an
* active transition.
*/
keyguardInteractor.wakefulnessState
.sample( .sample(
keyguardTransitionInteractor.startedKeyguardTransitionStep, keyguardTransitionInteractor.startedKeyguardTransitionStep,
{ a, b -> Pair(a, b) } { a, b -> Pair(a, b) }
) )
.collect { pair -> .collect { pair ->
val (wakefulnessState, lastStartedStep) = pair val (dozeToAod, lastStartedStep) = pair
if ( if (lastStartedStep.to == KeyguardState.LOCKSCREEN) {
isSleepingOrStartingToSleep(wakefulnessState) &&
lastStartedStep.to == KeyguardState.LOCKSCREEN
) {
keyguardTransitionRepository.startTransition( keyguardTransitionRepository.startTransition(
TransitionInfo( TransitionInfo(
name, name,
@@ -68,10 +64,22 @@ constructor(
getAnimator(), getAnimator(),
) )
) )
} else if ( }
isWakingOrStartingToWake(wakefulnessState) && }
lastStartedStep.to == KeyguardState.AOD }
) { }
private fun listenForTransitionToLockscreenFromAod() {
scope.launch {
keyguardInteractor
.dozeTransitionTo(DozeStateModel.FINISH)
.sample(
keyguardTransitionInteractor.startedKeyguardTransitionStep,
{ a, b -> Pair(a, b) }
)
.collect { pair ->
val (dozeToAod, lastStartedStep) = pair
if (lastStartedStep.to == KeyguardState.AOD) {
keyguardTransitionRepository.startTransition( keyguardTransitionRepository.startTransition(
TransitionInfo( TransitionInfo(
name, name,

View File

@@ -40,7 +40,7 @@ constructor(
private val keyguardInteractor: KeyguardInteractor, private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository, private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor("AOD->GONE") { ) : TransitionInteractor(AodToGoneTransitionInteractor::class.simpleName!!) {
private val wakeAndUnlockModes = private val wakeAndUnlockModes =
setOf(WAKE_AND_UNLOCK, WAKE_AND_UNLOCK_FROM_DREAM, WAKE_AND_UNLOCK_PULSING) setOf(WAKE_AND_UNLOCK, WAKE_AND_UNLOCK_FROM_DREAM, WAKE_AND_UNLOCK_PULSING)

View File

@@ -40,7 +40,7 @@ constructor(
private val shadeRepository: ShadeRepository, private val shadeRepository: ShadeRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository, private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor private val keyguardTransitionInteractor: KeyguardTransitionInteractor
) : TransitionInteractor("BOUNCER->GONE") { ) : TransitionInteractor(BouncerToGoneTransitionInteractor::class.simpleName!!) {
private var transitionId: UUID? = null private var transitionId: UUID? = null

View File

@@ -21,12 +21,14 @@ import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.sample import com.android.systemui.util.kotlin.sample
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@SysUISingleton @SysUISingleton
@@ -37,14 +39,24 @@ constructor(
private val keyguardInteractor: KeyguardInteractor, private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository, private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor("DREAMING<->LOCKSCREEN") { ) : TransitionInteractor(DreamingLockscreenTransitionInteractor::class.simpleName!!) {
override fun start() { override fun start() {
scope.launch { scope.launch {
keyguardInteractor.isDreaming keyguardInteractor.isDreaming
.sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) }) .sample(
.collect { pair -> combine(
val (isDreaming, keyguardState) = pair keyguardInteractor.dozeTransitionModel,
keyguardTransitionInteractor.finishedKeyguardState
) { a, b -> Pair(a, b) },
{ a, bc -> Triple(a, bc.first, bc.second) }
)
.collect { triple ->
val (isDreaming, dozeTransitionModel, keyguardState) = triple
// Dozing/AOD and dreaming have overlapping events. If the state remains in
// FINISH, it means that doze mode is not running and DREAMING is ok to
// commence.
if (dozeTransitionModel.to == DozeStateModel.FINISH) {
if (isDreaming && keyguardState == KeyguardState.LOCKSCREEN) { if (isDreaming && keyguardState == KeyguardState.LOCKSCREEN) {
keyguardTransitionRepository.startTransition( keyguardTransitionRepository.startTransition(
TransitionInfo( TransitionInfo(
@@ -67,6 +79,7 @@ constructor(
} }
} }
} }
}
private fun getAnimator(): ValueAnimator { private fun getAnimator(): ValueAnimator {
return ValueAnimator().apply { return ValueAnimator().apply {

View File

@@ -20,10 +20,13 @@ package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessModel
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
/** /**
* Encapsulates business-logic related to the keyguard but not to a more specific part within it. * Encapsulates business-logic related to the keyguard but not to a more specific part within it.
@@ -41,6 +44,8 @@ constructor(
val dozeAmount: Flow<Float> = repository.dozeAmount val dozeAmount: Flow<Float> = repository.dozeAmount
/** Whether the system is in doze mode. */ /** Whether the system is in doze mode. */
val isDozing: Flow<Boolean> = repository.isDozing val isDozing: Flow<Boolean> = repository.isDozing
/** Doze transition information. */
val dozeTransitionModel: Flow<DozeTransitionModel> = repository.dozeTransitionModel
/** /**
* Whether the system is dreaming. [isDreaming] will be always be true when [isDozing] is true, * Whether the system is dreaming. [isDreaming] will be always be true when [isDozing] is true,
* but not vice-versa. * but not vice-versa.
@@ -62,6 +67,10 @@ constructor(
*/ */
val biometricUnlockState: Flow<BiometricUnlockModel> = repository.biometricUnlockState val biometricUnlockState: Flow<BiometricUnlockModel> = repository.biometricUnlockState
fun dozeTransitionTo(state: DozeStateModel): Flow<DozeTransitionModel> {
return dozeTransitionModel.filter { it.to == state }
}
fun isKeyguardShowing(): Boolean { fun isKeyguardShowing(): Boolean {
return repository.isKeyguardShowing() return repository.isKeyguardShowing()
} }

View File

@@ -44,7 +44,7 @@ constructor(
private val shadeRepository: ShadeRepository, private val shadeRepository: ShadeRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository, private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor private val keyguardTransitionInteractor: KeyguardTransitionInteractor
) : TransitionInteractor("LOCKSCREEN<->BOUNCER") { ) : TransitionInteractor(LockscreenBouncerTransitionInteractor::class.simpleName!!) {
private var transitionId: UUID? = null private var transitionId: UUID? = null

View File

@@ -0,0 +1,46 @@
/*
* 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.shared.model
/** Model device doze states. */
enum class DozeStateModel {
/** Default state. Transition to INITIALIZED to get Doze going. */
UNINITIALIZED,
/** Doze components are set up. Followed by transition to DOZE or DOZE_AOD. */
INITIALIZED,
/** Regular doze. Device is asleep and listening for pulse triggers. */
DOZE,
/** Deep doze. Device is asleep and is not listening for pulse triggers. */
DOZE_SUSPEND_TRIGGERS,
/** Always-on doze. Device is asleep, showing UI and listening for pulse triggers. */
DOZE_AOD,
/** Pulse has been requested. Device is awake and preparing UI */
DOZE_REQUEST_PULSE,
/** Pulse is showing. Device is awake and showing UI. */
DOZE_PULSING,
/** Pulse is showing with bright wallpaper. Device is awake and showing UI. */
DOZE_PULSING_BRIGHT,
/** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
DOZE_PULSE_DONE,
/** Doze is done. DozeService is finished. */
FINISH,
/** AOD, but the display is temporarily off. */
DOZE_AOD_PAUSED,
/** AOD, prox is near, transitions to DOZE_AOD_PAUSED after a timeout. */
DOZE_AOD_PAUSING,
/** Always-on doze. Device is awake, showing docking UI and listening for pulse triggers. */
DOZE_AOD_DOCKED
}

View File

@@ -0,0 +1,22 @@
/*
* 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.shared.model
/** Doze transition information. */
data class DozeTransitionModel(
val from: DozeStateModel = DozeStateModel.UNINITIALIZED,
val to: DozeStateModel = DozeStateModel.UNINITIALIZED,
)

View File

@@ -22,18 +22,25 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Position import com.android.systemui.common.shared.model.Position
import com.android.systemui.doze.DozeHost import com.android.systemui.doze.DozeHost
import com.android.systemui.doze.DozeMachine
import com.android.systemui.doze.DozeTransitionCallback
import com.android.systemui.doze.DozeTransitionListener
import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@@ -52,6 +59,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var biometricUnlockController: BiometricUnlockController @Mock private lateinit var biometricUnlockController: BiometricUnlockController
@Mock private lateinit var dozeTransitionListener: DozeTransitionListener
private lateinit var underTest: KeyguardRepositoryImpl private lateinit var underTest: KeyguardRepositoryImpl
@@ -67,11 +75,13 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
biometricUnlockController, biometricUnlockController,
keyguardStateController, keyguardStateController,
keyguardUpdateMonitor, keyguardUpdateMonitor,
dozeTransitionListener,
) )
} }
@Test @Test
fun animateBottomAreaDozingTransitions() = runBlockingTest { fun animateBottomAreaDozingTransitions() =
runTest(UnconfinedTestDispatcher()) {
assertThat(underTest.animateBottomAreaDozingTransitions.value).isEqualTo(false) assertThat(underTest.animateBottomAreaDozingTransitions.value).isEqualTo(false)
underTest.setAnimateDozingTransitions(true) underTest.setAnimateDozingTransitions(true)
@@ -85,7 +95,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun bottomAreaAlpha() = runBlockingTest { fun bottomAreaAlpha() =
runTest(UnconfinedTestDispatcher()) {
assertThat(underTest.bottomAreaAlpha.value).isEqualTo(1f) assertThat(underTest.bottomAreaAlpha.value).isEqualTo(1f)
underTest.setBottomAreaAlpha(0.1f) underTest.setBottomAreaAlpha(0.1f)
@@ -105,7 +116,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun clockPosition() = runBlockingTest { fun clockPosition() =
runTest(UnconfinedTestDispatcher()) {
assertThat(underTest.clockPosition.value).isEqualTo(Position(0, 0)) assertThat(underTest.clockPosition.value).isEqualTo(Position(0, 0))
underTest.setClockPosition(0, 1) underTest.setClockPosition(0, 1)
@@ -122,7 +134,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun isKeyguardShowing() = runBlockingTest { fun isKeyguardShowing() =
runTest(UnconfinedTestDispatcher()) {
whenever(keyguardStateController.isShowing).thenReturn(false) whenever(keyguardStateController.isShowing).thenReturn(false)
var latest: Boolean? = null var latest: Boolean? = null
val job = underTest.isKeyguardShowing.onEach { latest = it }.launchIn(this) val job = underTest.isKeyguardShowing.onEach { latest = it }.launchIn(this)
@@ -147,7 +160,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun isDozing() = runBlockingTest { fun isDozing() =
runTest(UnconfinedTestDispatcher()) {
var latest: Boolean? = null var latest: Boolean? = null
val job = underTest.isDozing.onEach { latest = it }.launchIn(this) val job = underTest.isDozing.onEach { latest = it }.launchIn(this)
@@ -165,7 +179,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun `isDozing - starts with correct initial value for isDozing`() = runBlockingTest { fun `isDozing - starts with correct initial value for isDozing`() =
runTest(UnconfinedTestDispatcher()) {
var latest: Boolean? = null var latest: Boolean? = null
whenever(statusBarStateController.isDozing).thenReturn(true) whenever(statusBarStateController.isDozing).thenReturn(true)
@@ -180,7 +195,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun dozeAmount() = runBlockingTest { fun dozeAmount() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>() val values = mutableListOf<Float>()
val job = underTest.dozeAmount.onEach(values::add).launchIn(this) val job = underTest.dozeAmount.onEach(values::add).launchIn(this)
@@ -198,7 +214,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun wakefulness() = runBlockingTest { fun wakefulness() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<WakefulnessModel>() val values = mutableListOf<WakefulnessModel>()
val job = underTest.wakefulnessState.onEach(values::add).launchIn(this) val job = underTest.wakefulnessState.onEach(values::add).launchIn(this)
@@ -227,7 +244,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun isUdfpsSupported() = runBlockingTest { fun isUdfpsSupported() =
runTest(UnconfinedTestDispatcher()) {
whenever(keyguardUpdateMonitor.isUdfpsSupported).thenReturn(true) whenever(keyguardUpdateMonitor.isUdfpsSupported).thenReturn(true)
assertThat(underTest.isUdfpsSupported()).isTrue() assertThat(underTest.isUdfpsSupported()).isTrue()
@@ -236,7 +254,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun isBouncerShowing() = runBlockingTest { fun isBouncerShowing() =
runTest(UnconfinedTestDispatcher()) {
whenever(keyguardStateController.isBouncerShowing).thenReturn(false) whenever(keyguardStateController.isBouncerShowing).thenReturn(false)
var latest: Boolean? = null var latest: Boolean? = null
val job = underTest.isBouncerShowing.onEach { latest = it }.launchIn(this) val job = underTest.isBouncerShowing.onEach { latest = it }.launchIn(this)
@@ -258,7 +277,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun isKeyguardGoingAway() = runBlockingTest { fun isKeyguardGoingAway() =
runTest(UnconfinedTestDispatcher()) {
whenever(keyguardStateController.isKeyguardGoingAway).thenReturn(false) whenever(keyguardStateController.isKeyguardGoingAway).thenReturn(false)
var latest: Boolean? = null var latest: Boolean? = null
val job = underTest.isKeyguardGoingAway.onEach { latest = it }.launchIn(this) val job = underTest.isKeyguardGoingAway.onEach { latest = it }.launchIn(this)
@@ -280,7 +300,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun isDreaming() = runBlockingTest { fun isDreaming() =
runTest(UnconfinedTestDispatcher()) {
whenever(keyguardUpdateMonitor.isDreaming()).thenReturn(false) whenever(keyguardUpdateMonitor.isDreaming()).thenReturn(false)
var latest: Boolean? = null var latest: Boolean? = null
val job = underTest.isDreaming.onEach { latest = it }.launchIn(this) val job = underTest.isDreaming.onEach { latest = it }.launchIn(this)
@@ -300,7 +321,8 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
} }
@Test @Test
fun biometricUnlockState() = runBlockingTest { fun biometricUnlockState() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<BiometricUnlockModel>() val values = mutableListOf<BiometricUnlockModel>()
val job = underTest.biometricUnlockState.onEach(values::add).launchIn(this) val job = underTest.biometricUnlockState.onEach(values::add).launchIn(this)
@@ -335,4 +357,67 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
job.cancel() job.cancel()
verify(biometricUnlockController).removeBiometricModeListener(captor.value) verify(biometricUnlockController).removeBiometricModeListener(captor.value)
} }
@Test
fun dozeTransitionModel() =
runTest(UnconfinedTestDispatcher()) {
// For the initial state
whenever(dozeTransitionListener.oldState).thenReturn(DozeMachine.State.UNINITIALIZED)
whenever(dozeTransitionListener.newState).thenReturn(DozeMachine.State.UNINITIALIZED)
val values = mutableListOf<DozeTransitionModel>()
val job = underTest.dozeTransitionModel.onEach(values::add).launchIn(this)
val listener =
withArgCaptor<DozeTransitionCallback> {
verify(dozeTransitionListener).addCallback(capture())
}
// These don't have to reflect real transitions from the DozeMachine. Only that the
// transitions are properly emitted
listener.onDozeTransition(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE)
listener.onDozeTransition(DozeMachine.State.DOZE, DozeMachine.State.DOZE_AOD)
listener.onDozeTransition(DozeMachine.State.DOZE_AOD_DOCKED, DozeMachine.State.FINISH)
listener.onDozeTransition(
DozeMachine.State.DOZE_REQUEST_PULSE,
DozeMachine.State.DOZE_PULSING
)
listener.onDozeTransition(
DozeMachine.State.DOZE_SUSPEND_TRIGGERS,
DozeMachine.State.DOZE_PULSE_DONE
)
listener.onDozeTransition(
DozeMachine.State.DOZE_AOD_PAUSING,
DozeMachine.State.DOZE_AOD_PAUSED
)
assertThat(values)
.isEqualTo(
listOf(
// Initial value will be UNINITIALIZED
DozeTransitionModel(
DozeStateModel.UNINITIALIZED,
DozeStateModel.UNINITIALIZED
),
DozeTransitionModel(DozeStateModel.INITIALIZED, DozeStateModel.DOZE),
DozeTransitionModel(DozeStateModel.DOZE, DozeStateModel.DOZE_AOD),
DozeTransitionModel(DozeStateModel.DOZE_AOD_DOCKED, DozeStateModel.FINISH),
DozeTransitionModel(
DozeStateModel.DOZE_REQUEST_PULSE,
DozeStateModel.DOZE_PULSING
),
DozeTransitionModel(
DozeStateModel.DOZE_SUSPEND_TRIGGERS,
DozeStateModel.DOZE_PULSE_DONE
),
DozeTransitionModel(
DozeStateModel.DOZE_AOD_PAUSING,
DozeStateModel.DOZE_AOD_PAUSED
),
)
)
job.cancel()
verify(dozeTransitionListener).removeCallback(listener)
}
} }

View File

@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.data.repository
import com.android.systemui.common.shared.model.Position import com.android.systemui.common.shared.model.Position
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessModel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@@ -53,6 +54,9 @@ class FakeKeyguardRepository : KeyguardRepository {
private val _statusBarState = MutableStateFlow(StatusBarState.SHADE) private val _statusBarState = MutableStateFlow(StatusBarState.SHADE)
override val statusBarState: Flow<StatusBarState> = _statusBarState override val statusBarState: Flow<StatusBarState> = _statusBarState
private val _dozeTransitionModel = MutableStateFlow(DozeTransitionModel())
override val dozeTransitionModel: Flow<DozeTransitionModel> = _dozeTransitionModel
private val _wakefulnessState = MutableStateFlow(WakefulnessModel.ASLEEP) private val _wakefulnessState = MutableStateFlow(WakefulnessModel.ASLEEP)
override val wakefulnessState: Flow<WakefulnessModel> = _wakefulnessState override val wakefulnessState: Flow<WakefulnessModel> = _wakefulnessState