Transitions - Add dozing information am: 2a314ee828 am: b3b2a258a8

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

Change-Id: I63dd08c1a4f24c080a9bbad712301978169c728b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Matt Pietal
2022-12-04 13:21:30 +00:00
committed by Automerger Merge Worker
16 changed files with 228 additions and 208 deletions

View File

@@ -116,6 +116,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
KeyguardState.LOCKSCREEN,
0f,
TransitionState.STARTED,
KeyguardTransitionRepositoryImpl::class.simpleName!!,
)
)
emitTransition(
@@ -124,6 +125,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
KeyguardState.LOCKSCREEN,
1f,
TransitionState.FINISHED,
KeyguardTransitionRepositoryImpl::class.simpleName!!,
)
)
}

View File

@@ -41,17 +41,14 @@ constructor(
override fun start() {
listenForTransitionToAodFromLockscreen()
listenForTransitionToLockscreenFromAod()
listenForTransitionToLockscreenFromDozeStates()
}
private fun listenForTransitionToAodFromLockscreen() {
scope.launch {
keyguardInteractor
.dozeTransitionTo(DozeStateModel.DOZE_AOD)
.sample(
keyguardTransitionInteractor.startedKeyguardTransitionStep,
{ a, b -> Pair(a, b) }
)
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (dozeToAod, lastStartedStep) = pair
if (lastStartedStep.to == KeyguardState.LOCKSCREEN) {
@@ -68,21 +65,19 @@ constructor(
}
}
private fun listenForTransitionToLockscreenFromAod() {
private fun listenForTransitionToLockscreenFromDozeStates() {
val canGoToLockscreen = setOf(KeyguardState.AOD, KeyguardState.DOZING)
scope.launch {
keyguardInteractor
.dozeTransitionTo(DozeStateModel.FINISH)
.sample(
keyguardTransitionInteractor.startedKeyguardTransitionStep,
{ a, b -> Pair(a, b) }
)
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (dozeToAod, lastStartedStep) = pair
if (lastStartedStep.to == KeyguardState.AOD) {
if (canGoToLockscreen.contains(lastStartedStep.to)) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
KeyguardState.AOD,
lastStartedStep.to,
KeyguardState.LOCKSCREEN,
getAnimator(),
)

View File

@@ -21,9 +21,7 @@ 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.BiometricUnlockModel.WAKE_AND_UNLOCK
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.sample
@@ -42,9 +40,6 @@ constructor(
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor(AodToGoneTransitionInteractor::class.simpleName!!) {
private val wakeAndUnlockModes =
setOf(WAKE_AND_UNLOCK, WAKE_AND_UNLOCK_FROM_DREAM, WAKE_AND_UNLOCK_PULSING)
override fun start() {
scope.launch {
keyguardInteractor.biometricUnlockState
@@ -52,8 +47,7 @@ constructor(
.collect { pair ->
val (biometricUnlockState, keyguardState) = pair
if (
keyguardState == KeyguardState.AOD &&
wakeAndUnlockModes.contains(biometricUnlockState)
keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)
) {
keyguardTransitionRepository.startTransition(
TransitionInfo(

View File

@@ -1,94 +0,0 @@
/*
* 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.DozeStateModel
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.flow.combine
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(DreamingLockscreenTransitionInteractor::class.simpleName!!) {
override fun start() {
scope.launch {
keyguardInteractor.isDreaming
.sample(
combine(
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) {
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
}
}

View File

@@ -1,76 +0,0 @@
/*
* 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.wakefulnessModel
.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
}
}

View File

@@ -0,0 +1,180 @@
/*
* 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.BiometricUnlockModel.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
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.flow.combine
import kotlinx.coroutines.launch
@SysUISingleton
class DreamingTransitionInteractor
@Inject
constructor(
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor(DreamingTransitionInteractor::class.simpleName!!) {
private val canDreamFrom =
setOf(KeyguardState.LOCKSCREEN, KeyguardState.GONE, KeyguardState.DOZING)
override fun start() {
listenForEntryToDreaming()
listenForDreamingToLockscreen()
listenForDreamingToGone()
listenForDreamingToDozing()
}
private fun listenForEntryToDreaming() {
scope.launch {
keyguardInteractor.isDreaming
.sample(
combine(
keyguardInteractor.dozeTransitionModel,
keyguardTransitionInteractor.finishedKeyguardState,
::Pair
),
::toTriple
)
.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 (
isDozeOff(dozeTransitionModel.to) &&
isDreaming &&
canDreamFrom.contains(keyguardState)
) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
keyguardState,
KeyguardState.DREAMING,
getAnimator(),
)
)
}
}
}
}
private fun listenForDreamingToLockscreen() {
scope.launch {
keyguardInteractor.isDreaming
.sample(
combine(
keyguardInteractor.dozeTransitionModel,
keyguardTransitionInteractor.startedKeyguardTransitionStep,
::Pair,
),
::toTriple
)
.collect { triple ->
val (isDreaming, dozeTransitionModel, lastStartedTransition) = triple
if (
isDozeOff(dozeTransitionModel.to) &&
!isDreaming &&
lastStartedTransition.to == KeyguardState.DREAMING
) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
KeyguardState.DREAMING,
KeyguardState.LOCKSCREEN,
getAnimator(),
)
)
}
}
}
}
private fun listenForDreamingToGone() {
scope.launch {
keyguardInteractor.biometricUnlockState
.sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
.collect { pair ->
val (biometricUnlockState, keyguardState) = pair
if (
keyguardState == KeyguardState.DREAMING &&
isWakeAndUnlock(biometricUnlockState)
) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
KeyguardState.DREAMING,
KeyguardState.GONE,
getAnimator(),
)
)
}
}
}
}
private fun listenForDreamingToDozing() {
scope.launch {
combine(
keyguardInteractor.dozeTransitionModel,
keyguardTransitionInteractor.finishedKeyguardState,
::Pair
)
.collect { pair ->
val (dozeTransitionModel, keyguardState) = pair
if (
dozeTransitionModel.to == DozeStateModel.DOZE &&
keyguardState == KeyguardState.DREAMING
) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
KeyguardState.DREAMING,
KeyguardState.DOZING,
getAnimator(),
)
)
}
}
}
}
private fun getAnimator(): ValueAnimator {
return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR)
setDuration(TRANSITION_DURATION_MS)
}
}
companion object {
private const val TRANSITION_DURATION_MS = 500L
}
}

View File

@@ -37,7 +37,7 @@ constructor(
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor("GONE->AOD") {
) : TransitionInteractor(GoneAodTransitionInteractor::class.simpleName!!) {
override fun start() {
scope.launch {

View File

@@ -46,6 +46,8 @@ constructor(
scope.launch { keyguardInteractor.isDozing.collect { logger.v("isDozing", it) } }
scope.launch { keyguardInteractor.isDreaming.collect { logger.v("isDreaming", it) } }
scope.launch {
interactor.finishedKeyguardTransitionStep.collect {
logger.i("Finished transition", it)
@@ -61,5 +63,9 @@ constructor(
scope.launch {
interactor.startedKeyguardTransitionStep.collect { logger.i("Started transition", it) }
}
scope.launch {
keyguardInteractor.dozeTransitionModel.collect { logger.i("Doze transition", it) }
}
}
}

View File

@@ -43,8 +43,7 @@ constructor(
is LockscreenGoneTransitionInteractor -> Log.d(TAG, "Started $it")
is AodToGoneTransitionInteractor -> Log.d(TAG, "Started $it")
is BouncerToGoneTransitionInteractor -> Log.d(TAG, "Started $it")
is DreamingLockscreenTransitionInteractor -> Log.d(TAG, "Started $it")
is DreamingToAodTransitionInteractor -> Log.d(TAG, "Started $it")
is DreamingTransitionInteractor -> Log.d(TAG, "Started $it")
}
it.start()
}

View File

@@ -37,15 +37,15 @@ constructor(
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
) : TransitionInteractor("LOCKSCREEN->GONE") {
) : TransitionInteractor(LockscreenGoneTransitionInteractor::class.simpleName!!) {
override fun start() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
.sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isKeyguardGoingAway, keyguardState) = pair
if (!isKeyguardGoingAway && keyguardState == KeyguardState.LOCKSCREEN) {
val (isKeyguardGoingAway, lastStartedStep) = pair
if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,

View File

@@ -52,13 +52,5 @@ abstract class StartKeyguardTransitionModule {
@IntoSet
abstract fun lockscreenGone(impl: LockscreenGoneTransitionInteractor): TransitionInteractor
@Binds
@IntoSet
abstract fun dreamingLockscreen(
impl: DreamingLockscreenTransitionInteractor
): TransitionInteractor
@Binds
@IntoSet
abstract fun dreamingToAod(impl: DreamingToAodTransitionInteractor): TransitionInteractor
@Binds @IntoSet abstract fun dreaming(impl: DreamingTransitionInteractor): TransitionInteractor
}

View File

@@ -29,4 +29,6 @@ package com.android.systemui.keyguard.domain.interactor
sealed class TransitionInteractor(val name: String) {
abstract fun start()
fun <A, B, C> toTriple(a: A, bc: Pair<B, C>) = Triple(a, bc.first, bc.second)
}

View File

@@ -46,5 +46,14 @@ enum class BiometricUnlockModel {
/** When bouncer is visible and will be dismissed. */
DISMISS_BOUNCER,
/** Mode in which fingerprint wakes and unlocks the device from a dream. */
WAKE_AND_UNLOCK_FROM_DREAM,
WAKE_AND_UNLOCK_FROM_DREAM;
companion object {
private val wakeAndUnlockModes =
setOf(WAKE_AND_UNLOCK, WAKE_AND_UNLOCK_FROM_DREAM, WAKE_AND_UNLOCK_PULSING)
fun isWakeAndUnlock(model: BiometricUnlockModel): Boolean {
return wakeAndUnlockModes.contains(model)
}
}
}

View File

@@ -42,5 +42,11 @@ enum class DozeStateModel {
/** 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
DOZE_AOD_DOCKED;
companion object {
fun isDozeOff(model: DozeStateModel): Boolean {
return model == UNINITIALIZED || model == FINISH
}
}
}

View File

@@ -22,6 +22,7 @@ import android.util.Log
import android.util.Log.TerribleFailure
import android.util.Log.TerribleFailureHandler
import android.view.Choreographer.FrameCallback
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators
@@ -97,6 +98,7 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
}
@Test
@FlakyTest(bugId = 260213291)
fun `starting second transition will cancel the first transition`() {
runBlocking(IMMEDIATE) {
val (animator, provider) = setupAnimator(this)

View File

@@ -200,6 +200,9 @@ public class KeyguardServiceDelegate {
if (!mKeyguardState.enabled) {
mKeyguardService.setKeyguardEnabled(mKeyguardState.enabled);
}
if (mKeyguardState.dreaming) {
mKeyguardService.onDreamingStarted();
}
}
@Override