Merge changes I645115ab,I73b51987,Id1b79253 into tm-qpr-dev am: 2c34290e87 am: c52dcfa7d5
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20427727
Change-Id: I0b6eb3cad7f3de3614f303969f937c29c3044671
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index ca25282..9d5d8bb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -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
@@ -69,6 +70,9 @@
*/
val isKeyguardShowing: Flow<Boolean>
+ /** Observable for the signal that keyguard is about to go away. */
+ val isKeyguardGoingAway: Flow<Boolean>
+
/** Observable for whether the bouncer is showing. */
val isBouncerShowing: Flow<Boolean>
@@ -85,6 +89,14 @@
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.
*
* While in doze state, this amount can change - driving a cycle of animations designed to avoid
@@ -136,12 +148,12 @@
class KeyguardRepositoryImpl
@Inject
constructor(
- statusBarStateController: StatusBarStateController,
- dozeHost: DozeHost,
- wakefulnessLifecycle: WakefulnessLifecycle,
- biometricUnlockController: BiometricUnlockController,
- private val keyguardStateController: KeyguardStateController,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ statusBarStateController: StatusBarStateController,
+ dozeHost: DozeHost,
+ wakefulnessLifecycle: WakefulnessLifecycle,
+ biometricUnlockController: BiometricUnlockController,
+ private val keyguardStateController: KeyguardStateController,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
) : KeyguardRepository {
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
@@ -176,6 +188,29 @@
awaitClose { keyguardStateController.removeCallback(callback) }
}
+ override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
+ val callback =
+ object : KeyguardStateController.Callback {
+ override fun onKeyguardGoingAwayChanged() {
+ trySendWithFailureLogging(
+ keyguardStateController.isKeyguardGoingAway,
+ TAG,
+ "updated isKeyguardGoingAway"
+ )
+ }
+ }
+
+ keyguardStateController.addCallback(callback)
+ // Adding the callback does not send an initial update.
+ trySendWithFailureLogging(
+ keyguardStateController.isKeyguardGoingAway,
+ TAG,
+ "initial isKeyguardGoingAway"
+ )
+
+ awaitClose { keyguardStateController.removeCallback(callback) }
+ }
+
override val isBouncerShowing: Flow<Boolean> = conflatedCallbackFlow {
val callback =
object : KeyguardStateController.Callback {
@@ -218,6 +253,25 @@
}
.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 {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index e3d1a27..bce7d92 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -94,11 +94,13 @@
*/
private val _transitions =
MutableSharedFlow<TransitionStep>(
+ replay = 2,
extraBufferCapacity = 10,
- onBufferOverflow = BufferOverflow.DROP_OLDEST
+ onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
override val transitions = _transitions.asSharedFlow().distinctUntilChanged()
private var lastStep: TransitionStep = TransitionStep()
+ private var lastAnimator: ValueAnimator? = null
/*
* When manual control of the transition is requested, a unique [UUID] is used as the handle
@@ -106,19 +108,39 @@
*/
private var updateTransitionId: UUID? = null
+ init {
+ // Seed with transitions signaling a boot into lockscreen state
+ emitTransition(
+ TransitionStep(
+ KeyguardState.OFF,
+ KeyguardState.LOCKSCREEN,
+ 0f,
+ TransitionState.STARTED,
+ )
+ )
+ emitTransition(
+ TransitionStep(
+ KeyguardState.OFF,
+ KeyguardState.LOCKSCREEN,
+ 1f,
+ TransitionState.FINISHED,
+ )
+ )
+ }
+
override fun startTransition(info: TransitionInfo): UUID? {
if (lastStep.transitionState != TransitionState.FINISHED) {
- // Open questions:
- // * Queue of transitions? buffer of 1?
- // * Are transitions cancellable if a new one is triggered?
- // * What validation does this need to do?
- Log.wtf(TAG, "Transition still active: $lastStep")
- return null
+ Log.i(TAG, "Transition still active: $lastStep, canceling")
}
+ val startingValue = 1f - lastStep.value
+ lastAnimator?.cancel()
+ lastAnimator = info.animator
+
info.animator?.let { animator ->
// An animator was provided, so use it to run the transition
- animator.setFloatValues(0f, 1f)
+ animator.setFloatValues(startingValue, 1f)
+ animator.duration = ((1f - startingValue) * animator.duration).toLong()
val updateListener =
object : AnimatorUpdateListener {
override fun onAnimationUpdate(animation: ValueAnimator) {
@@ -134,15 +156,24 @@
val adapter =
object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator) {
- emitTransition(TransitionStep(info, 0f, TransitionState.STARTED))
+ emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
}
override fun onAnimationCancel(animation: Animator) {
- Log.i(TAG, "Cancelling transition: $info")
+ endAnimation(animation, lastStep.value, TransitionState.CANCELED)
}
override fun onAnimationEnd(animation: Animator) {
- emitTransition(TransitionStep(info, 1f, TransitionState.FINISHED))
+ endAnimation(animation, 1f, TransitionState.FINISHED)
+ }
+
+ private fun endAnimation(
+ animation: Animator,
+ value: Float,
+ state: TransitionState
+ ) {
+ emitTransition(TransitionStep(info, value, state))
animator.removeListener(this)
animator.removeUpdateListener(updateListener)
+ lastAnimator = null
}
}
animator.addListener(adapter)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
index 0aeff7f..e5521c7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
@@ -20,10 +20,11 @@
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.KeyguardRepository
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.keyguard.shared.model.WakefulnessModel.Companion.isWakingOrStartingToWake
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -35,18 +36,30 @@
@Inject
constructor(
@Application private val scope: CoroutineScope,
- private val keyguardRepository: KeyguardRepository,
+ private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor("AOD<->LOCKSCREEN") {
override fun start() {
scope.launch {
- keyguardRepository.isDozing
- .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
+ /*
+ * Listening to the startedKeyguardTransitionStep (last started step) allows this code
+ * 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(
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ { a, b -> Pair(a, b) }
+ )
.collect { pair ->
- val (isDozing, keyguardState) = pair
- if (isDozing && keyguardState == KeyguardState.LOCKSCREEN) {
+ val (wakefulnessState, lastStartedStep) = pair
+ if (
+ isSleepingOrStartingToSleep(wakefulnessState) &&
+ lastStartedStep.to == KeyguardState.LOCKSCREEN
+ ) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
@@ -55,7 +68,10 @@
getAnimator(),
)
)
- } else if (!isDozing && keyguardState == KeyguardState.AOD) {
+ } else if (
+ isWakingOrStartingToWake(wakefulnessState) &&
+ lastStartedStep.to == KeyguardState.AOD
+ ) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerToGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerToGoneTransitionInteractor.kt
new file mode 100644
index 0000000..dd29673
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerToGoneTransitionInteractor.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.shade.data.repository.ShadeRepository
+import com.android.systemui.util.kotlin.sample
+import java.util.UUID
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class BouncerToGoneTransitionInteractor
+@Inject
+constructor(
+ @Application private val scope: CoroutineScope,
+ private val keyguardInteractor: KeyguardInteractor,
+ private val shadeRepository: ShadeRepository,
+ private val keyguardTransitionRepository: KeyguardTransitionRepository,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor
+) : TransitionInteractor("BOUNCER->GONE") {
+
+ private var transitionId: UUID? = null
+
+ override fun start() {
+ listenForKeyguardGoingAway()
+ }
+
+ private fun listenForKeyguardGoingAway() {
+ scope.launch {
+ keyguardInteractor.isKeyguardGoingAway
+ .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
+ .collect { pair ->
+ val (isKeyguardGoingAway, keyguardState) = pair
+ if (isKeyguardGoingAway && keyguardState == KeyguardState.BOUNCER) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.BOUNCER,
+ to = KeyguardState.GONE,
+ animator = getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun getAnimator(): ValueAnimator {
+ return ValueAnimator().apply {
+ setInterpolator(Interpolators.LINEAR)
+ setDuration(TRANSITION_DURATION_MS)
+ }
+ }
+
+ companion object {
+ private const val TRANSITION_DURATION_MS = 300L
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingLockscreenTransitionInteractor.kt
new file mode 100644
index 0000000..c44cda4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingLockscreenTransitionInteractor.kt
@@ -0,0 +1,81 @@
+/*
+ * 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
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt
new file mode 100644
index 0000000..9e2b724
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt
@@ -0,0 +1,76 @@
+/*
+ * 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
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 614ff8d..5a1c702 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -41,8 +41,15 @@
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. */
+ val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
/** Whether the bouncer is showing or not. */
val isBouncerShowing: Flow<Boolean> = repository.isBouncerShowing
/** The device wake/sleep state */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 57fb4a1..58a8093 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -41,12 +41,24 @@
}
scope.launch {
+ keyguardInteractor.isBouncerShowing.collect { logger.v("Bouncer showing", it) }
+ }
+
+ scope.launch { keyguardInteractor.isDozing.collect { logger.v("isDozing", it) } }
+
+ scope.launch {
interactor.finishedKeyguardTransitionStep.collect {
logger.i("Finished transition", it)
}
}
scope.launch {
+ interactor.canceledKeyguardTransitionStep.collect {
+ logger.i("Canceled transition", it)
+ }
+ }
+
+ scope.launch {
interactor.startedKeyguardTransitionStep.collect { logger.i("Started transition", it) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
index a7c6d44..43dd358e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
@@ -42,6 +42,9 @@
is GoneAodTransitionInteractor -> Log.d(TAG, "Started $it")
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")
}
it.start()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 749183e..54a4f49 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -57,6 +57,14 @@
lockscreenToAodTransition,
)
+ /* The last [TransitionStep] with a [TransitionState] of STARTED */
+ val startedKeyguardTransitionStep: Flow<TransitionStep> =
+ repository.transitions.filter { step -> step.transitionState == TransitionState.STARTED }
+
+ /* The last [TransitionStep] with a [TransitionState] of CANCELED */
+ val canceledKeyguardTransitionStep: Flow<TransitionStep> =
+ repository.transitions.filter { step -> step.transitionState == TransitionState.CANCELED }
+
/* The last [TransitionStep] with a [TransitionState] of FINISHED */
val finishedKeyguardTransitionStep: Flow<TransitionStep> =
repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED }
@@ -64,8 +72,4 @@
/* The last completed [KeyguardState] transition */
val finishedKeyguardState: Flow<KeyguardState> =
finishedKeyguardTransitionStep.map { step -> step.to }
-
- /* The last [TransitionStep] with a [TransitionState] of STARTED */
- val startedKeyguardTransitionStep: Flow<TransitionStep> =
- repository.transitions.filter { step -> step.transitionState == TransitionState.STARTED }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
index fd4814d..cca2d56 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
@@ -56,10 +56,20 @@
private fun listenForBouncerHiding() {
scope.launch {
keyguardInteractor.isBouncerShowing
- .sample(keyguardInteractor.wakefulnessState, { a, b -> Pair(a, b) })
- .collect { pair ->
- val (isBouncerShowing, wakefulnessState) = pair
- if (!isBouncerShowing) {
+ .sample(
+ combine(
+ keyguardInteractor.wakefulnessState,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ ) { a, b ->
+ Pair(a, b)
+ },
+ { a, bc -> Triple(a, bc.first, bc.second) }
+ )
+ .collect { triple ->
+ val (isBouncerShowing, wakefulnessState, lastStartedTransitionStep) = triple
+ if (
+ !isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.BOUNCER
+ ) {
val to =
if (
wakefulnessState == WakefulnessModel.STARTING_TO_SLEEP ||
@@ -90,10 +100,10 @@
combine(
keyguardTransitionInteractor.finishedKeyguardState,
keyguardInteractor.statusBarState,
- ) { keyguardState, statusBarState ->
- Pair(keyguardState, statusBarState)
+ ) { a, b ->
+ Pair(a, b)
},
- { shadeModel, pair -> Triple(shadeModel, pair.first, pair.second) }
+ { a, bc -> Triple(a, bc.first, bc.second) }
)
.collect { triple ->
val (shadeModel, keyguardState, statusBarState) = triple
@@ -116,8 +126,7 @@
)
} else {
// TODO (b/251849525): Remove statusbarstate check when that state is
- // integrated
- // into KeyguardTransitionRepository
+ // integrated into KeyguardTransitionRepository
if (
keyguardState == KeyguardState.LOCKSCREEN &&
shadeModel.isUserDragging &&
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt
index 6c1adbd..4100f7a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt
@@ -23,6 +23,7 @@
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
@@ -34,23 +35,27 @@
constructor(
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
) : TransitionInteractor("LOCKSCREEN->GONE") {
override fun start() {
scope.launch {
- keyguardInteractor.isKeyguardShowing.collect { isShowing ->
- if (!isShowing) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- KeyguardState.GONE,
- getAnimator(),
+ keyguardInteractor.isKeyguardGoingAway
+ .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
+ .collect { pair ->
+ val (isKeyguardGoingAway, keyguardState) = pair
+ if (!isKeyguardGoingAway && keyguardState == KeyguardState.LOCKSCREEN) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GONE,
+ getAnimator(),
+ )
)
- )
+ }
}
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index c22f4e7a..fcd653b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -210,9 +210,12 @@
expansion == KeyguardBouncer.EXPANSION_HIDDEN &&
oldExpansion != KeyguardBouncer.EXPANSION_HIDDEN
) {
- repository.setPrimaryVisible(false)
- repository.setPrimaryShow(null)
- falsingCollector.onBouncerHidden()
+ /*
+ * There are cases where #hide() was not invoked, such as when
+ * NotificationPanelViewController controls the hide animation. Make sure the state gets
+ * updated by calling #hide() directly.
+ */
+ hide()
DejankUtils.postAfterTraversal { primaryBouncerCallbackInteractor.dispatchReset() }
primaryBouncerCallbackInteractor.dispatchFullyHidden()
} else if (
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
index 37f33af..dbffeab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
@@ -46,5 +46,19 @@
@Binds
@IntoSet
+ abstract fun bouncerGone(impl: BouncerToGoneTransitionInteractor): TransitionInteractor
+
+ @Binds
+ @IntoSet
abstract fun lockscreenGone(impl: LockscreenGoneTransitionInteractor): TransitionInteractor
+
+ @Binds
+ @IntoSet
+ abstract fun dreamingLockscreen(
+ impl: DreamingLockscreenTransitionInteractor
+ ): TransitionInteractor
+
+ @Binds
+ @IntoSet
+ abstract fun dreamingToAod(impl: DreamingToAodTransitionInteractor): TransitionInteractor
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
index 7958033..dd908c4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
@@ -17,12 +17,29 @@
/** List of all possible states to transition to/from */
enum class KeyguardState {
- /**
- * For initialization as well as when the security method is set to NONE, indicating that
- * the keyguard should never be shown.
+ /*
+ * The display is completely off, as well as any sensors that would trigger the device to wake
+ * up.
*/
- NONE,
- /* Always-on Display. The device is in a low-power mode with a minimal UI visible */
+ OFF,
+ /**
+ * The device has entered a special low-power mode within SystemUI. Doze is technically a
+ * special dream service implementation. No UI is visible. In this state, a least some
+ * low-powered sensors such as lift to wake or tap to wake are enabled, or wake screen for
+ * notifications is enabled, allowing the device to quickly wake up.
+ */
+ DOZING,
+ /*
+ * A device state after the device times out, which can be from both LOCKSCREEN or GONE states.
+ * DOZING is an example of special version of this state. Dreams may be implemented by third
+ * parties to present their own UI over keyguard, like a screensaver.
+ */
+ DREAMING,
+ /**
+ * The device has entered a special low-power mode within SystemUI, also called the Always-on
+ * Display (AOD). A minimal UI is presented to show critical information. If the device is in
+ * low-power mode without a UI, then it is DOZING.
+ */
AOD,
/*
* The security screen prompt UI, containing PIN, Password, Pattern, and all FPS
@@ -34,7 +51,6 @@
* unlocked if SWIPE security method is used, or if face lockscreen bypass is false.
*/
LOCKSCREEN,
-
/*
* Keyguard is no longer visible. In most cases the user has just authenticated and keyguard
* is being removed, but there are other cases where the user is swiping away keyguard, such as
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt
index 0e0465b..38a93b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt
@@ -17,7 +17,12 @@
/** Possible states for a running transition between [State] */
enum class TransitionState {
+ /* Transition has begun. */
STARTED,
+ /* Transition is actively running. */
RUNNING,
- FINISHED
+ /* Transition has completed successfully. */
+ FINISHED,
+ /* Transition has been interrupted, and not completed successfully. */
+ CANCELED,
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt
index 732a6f7..767fd58 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt
@@ -17,8 +17,8 @@
/** This information will flow from the [KeyguardTransitionRepository] to control the UI layer */
data class TransitionStep(
- val from: KeyguardState = KeyguardState.NONE,
- val to: KeyguardState = KeyguardState.NONE,
+ val from: KeyguardState = KeyguardState.OFF,
+ val to: KeyguardState = KeyguardState.OFF,
val value: Float = 0f, // constrained [0.0, 1.0]
val transitionState: TransitionState = TransitionState.FINISHED,
val ownerName: String = "",
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
index 64f834d..92040f4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
@@ -24,5 +24,15 @@
/** Device is now fully awake and interactive. */
AWAKE,
/** Signal that the device is now going to sleep. */
- STARTING_TO_SLEEP,
+ STARTING_TO_SLEEP;
+
+ companion object {
+ fun isSleepingOrStartingToSleep(model: WakefulnessModel): Boolean {
+ return model == ASLEEP || model == STARTING_TO_SLEEP
+ }
+
+ fun isWakingOrStartingToWake(model: WakefulnessModel): Boolean {
+ return model == AWAKE || model == STARTING_TO_WAKE
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index d328472..aa0757e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -279,10 +279,7 @@
* @see #onFullyShown()
*/
private void onFullyHidden() {
- cancelShowRunnable();
- setVisibility(View.INVISIBLE);
- mFalsingCollector.onBouncerHidden();
- DejankUtils.postAfterTraversal(mResetRunnable);
+
}
private void setVisibility(@View.Visibility int visibility) {
@@ -459,7 +456,13 @@
onFullyShown();
dispatchFullyShown();
} else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
- onFullyHidden();
+ DejankUtils.postAfterTraversal(mResetRunnable);
+ /*
+ * There are cases where #hide() was not invoked, such as when
+ * NotificationPanelViewController controls the hide animation. Make sure the state gets
+ * updated by calling #hide() directly.
+ */
+ hide(false /* destroyView */);
dispatchFullyHidden();
} else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
dispatchStartingToHide();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 86e27ab..d54a863 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -895,7 +895,7 @@
float stateBehind = mClipsQsScrim ? state.getNotifAlpha() : state.getBehindAlpha();
float behindAlpha;
- int behindTint;
+ int behindTint = state.getBehindTint();
if (mDarkenWhileDragging) {
behindAlpha = MathUtils.lerp(mDefaultScrimAlpha, stateBehind,
interpolatedFract);
@@ -903,12 +903,14 @@
behindAlpha = MathUtils.lerp(0 /* start */, stateBehind,
interpolatedFract);
}
- if (mClipsQsScrim) {
- behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getNotifTint(),
+ if (mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()) {
+ if (mClipsQsScrim) {
+ behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getNotifTint(),
state.getNotifTint(), interpolatedFract);
- } else {
- behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
+ } else {
+ behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
state.getBehindTint(), interpolatedFract);
+ }
}
if (mQsExpansion > 0) {
behindAlpha = MathUtils.lerp(behindAlpha, mDefaultScrimAlpha, mQsExpansion);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index e9d4e55..681d21b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -165,6 +165,7 @@
@Override
public void onFullyHidden() {
mPrimaryBouncerAnimating = false;
+ updateStates();
}
@Override
@@ -1183,12 +1184,16 @@
updateNavigationBarVisibility(navBarVisible);
}
- if (primaryBouncerShowing != mLastPrimaryBouncerShowing || mFirstUpdate) {
+ boolean isPrimaryBouncerShowingChanged =
+ primaryBouncerShowing != mLastPrimaryBouncerShowing;
+ mLastPrimaryBouncerShowing = primaryBouncerShowing;
+
+ if (isPrimaryBouncerShowingChanged || mFirstUpdate) {
mNotificationShadeWindowController.setBouncerShowing(primaryBouncerShowing);
mCentralSurfaces.setBouncerShowing(primaryBouncerShowing);
}
if (primaryBouncerIsOrWillBeShowing != mLastPrimaryBouncerIsOrWillBeShowing || mFirstUpdate
- || primaryBouncerShowing != mLastPrimaryBouncerShowing) {
+ || isPrimaryBouncerShowingChanged) {
mKeyguardUpdateManager.sendPrimaryBouncerChanged(primaryBouncerIsOrWillBeShowing,
primaryBouncerShowing);
}
@@ -1197,7 +1202,6 @@
mLastShowing = showing;
mLastGlobalActionsVisible = mGlobalActionsVisible;
mLastOccluded = occluded;
- mLastPrimaryBouncerShowing = primaryBouncerShowing;
mLastPrimaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing;
mLastBouncerDismissible = primaryBouncerDismissible;
mLastRemoteInputActive = remoteInputActive;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index ade83cf..6ba0634 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -18,6 +18,7 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Position
import com.android.systemui.doze.DozeHost
@@ -60,12 +61,12 @@
underTest =
KeyguardRepositoryImpl(
- statusBarStateController,
- dozeHost,
- wakefulnessLifecycle,
- biometricUnlockController,
- keyguardStateController,
- keyguardUpdateMonitor,
+ statusBarStateController,
+ dozeHost,
+ wakefulnessLifecycle,
+ biometricUnlockController,
+ keyguardStateController,
+ keyguardUpdateMonitor,
)
}
@@ -257,6 +258,48 @@
}
@Test
+ fun isKeyguardGoingAway() = runBlockingTest {
+ whenever(keyguardStateController.isKeyguardGoingAway).thenReturn(false)
+ var latest: Boolean? = null
+ val job = underTest.isKeyguardGoingAway.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ val captor = argumentCaptor<KeyguardStateController.Callback>()
+ verify(keyguardStateController).addCallback(captor.capture())
+
+ whenever(keyguardStateController.isKeyguardGoingAway).thenReturn(true)
+ captor.value.onKeyguardGoingAwayChanged()
+ assertThat(latest).isTrue()
+
+ whenever(keyguardStateController.isKeyguardGoingAway).thenReturn(false)
+ captor.value.onKeyguardGoingAwayChanged()
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isDreaming() = runBlockingTest {
+ whenever(keyguardUpdateMonitor.isDreaming()).thenReturn(false)
+ var latest: Boolean? = null
+ val job = underTest.isDreaming.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+ verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+
+ captor.value.onDreamingStateChanged(true)
+ assertThat(latest).isTrue()
+
+ captor.value.onDreamingStateChanged(false)
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
fun biometricUnlockState() = runBlockingTest {
val values = mutableListOf<BiometricUnlockModel>()
val job = underTest.biometricUnlockState.onEach(values::add).launchIn(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index 27d5d0a..2b03722 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -25,8 +25,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
-import com.android.systemui.keyguard.shared.model.KeyguardState.BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -38,7 +38,6 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
-import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.launchIn
@@ -91,18 +90,51 @@
}
}
- assertSteps(steps, listWithStep(BigDecimal(.1)))
+ assertSteps(steps, listWithStep(BigDecimal(.1)), AOD, LOCKSCREEN)
job.cancel()
provider.stop()
}
@Test
- fun `startTransition called during another transition fails`() {
- underTest.startTransition(TransitionInfo(OWNER_NAME, AOD, LOCKSCREEN, null))
- underTest.startTransition(TransitionInfo(OWNER_NAME, LOCKSCREEN, BOUNCER, null))
+ fun `starting second transition will cancel the first transition`() {
+ runBlocking(IMMEDIATE) {
+ val (animator, provider) = setupAnimator(this)
- assertThat(wtfHandler.failed).isTrue()
+ val steps = mutableListOf<TransitionStep>()
+ val job = underTest.transition(AOD, LOCKSCREEN).onEach { steps.add(it) }.launchIn(this)
+
+ underTest.startTransition(TransitionInfo(OWNER_NAME, AOD, LOCKSCREEN, animator))
+ // 3 yields(), alternating with the animator, results in a value 0.1, which can be
+ // canceled and tested against
+ yield()
+ yield()
+ yield()
+
+ // Now start 2nd transition, which will interrupt the first
+ val job2 = underTest.transition(LOCKSCREEN, AOD).onEach { steps.add(it) }.launchIn(this)
+ val (animator2, provider2) = setupAnimator(this)
+ underTest.startTransition(TransitionInfo(OWNER_NAME, LOCKSCREEN, AOD, animator2))
+
+ val startTime = System.currentTimeMillis()
+ while (animator2.isRunning()) {
+ yield()
+ if (System.currentTimeMillis() - startTime > MAX_TEST_DURATION) {
+ fail("Failed test due to excessive runtime of: $MAX_TEST_DURATION")
+ }
+ }
+
+ val firstTransitionSteps = listWithStep(step = BigDecimal(.1), stop = BigDecimal(.1))
+ assertSteps(steps.subList(0, 4), firstTransitionSteps, AOD, LOCKSCREEN)
+
+ val secondTransitionSteps = listWithStep(step = BigDecimal(.1), start = BigDecimal(.9))
+ assertSteps(steps.subList(4, steps.size), secondTransitionSteps, LOCKSCREEN, AOD)
+
+ job.cancel()
+ job2.cancel()
+ provider.stop()
+ provider2.stop()
+ }
}
@Test
@@ -165,11 +197,15 @@
assertThat(wtfHandler.failed).isTrue()
}
- private fun listWithStep(step: BigDecimal): List<BigDecimal> {
+ private fun listWithStep(
+ step: BigDecimal,
+ start: BigDecimal = BigDecimal.ZERO,
+ stop: BigDecimal = BigDecimal.ONE,
+ ): List<BigDecimal> {
val steps = mutableListOf<BigDecimal>()
- var i = BigDecimal.ZERO
- while (i.compareTo(BigDecimal.ONE) <= 0) {
+ var i = start
+ while (i.compareTo(stop) <= 0) {
steps.add(i)
i = (i + step).setScale(2, RoundingMode.HALF_UP)
}
@@ -177,23 +213,43 @@
return steps
}
- private fun assertSteps(steps: List<TransitionStep>, fractions: List<BigDecimal>) {
+ private fun assertSteps(
+ steps: List<TransitionStep>,
+ fractions: List<BigDecimal>,
+ from: KeyguardState,
+ to: KeyguardState,
+ ) {
assertThat(steps[0])
- .isEqualTo(TransitionStep(AOD, LOCKSCREEN, 0f, TransitionState.STARTED, OWNER_NAME))
+ .isEqualTo(
+ TransitionStep(
+ from,
+ to,
+ fractions[0].toFloat(),
+ TransitionState.STARTED,
+ OWNER_NAME
+ )
+ )
fractions.forEachIndexed { index, fraction ->
assertThat(steps[index + 1])
.isEqualTo(
TransitionStep(
- AOD,
- LOCKSCREEN,
+ from,
+ to,
fraction.toFloat(),
TransitionState.RUNNING,
OWNER_NAME
)
)
}
+ val lastValue = fractions[fractions.size - 1].toFloat()
+ val status =
+ if (lastValue < 1f) {
+ TransitionState.CANCELED
+ } else {
+ TransitionState.FINISHED
+ }
assertThat(steps[steps.size - 1])
- .isEqualTo(TransitionStep(AOD, LOCKSCREEN, 1f, TransitionState.FINISHED, OWNER_NAME))
+ .isEqualTo(TransitionStep(from, to, lastValue, status, OWNER_NAME))
assertThat(wtfHandler.failed).isFalse()
}
@@ -230,7 +286,7 @@
scope.launch {
frames.collect {
// Delay is required for AnimationHandler to properly register a callback
- delay(1)
+ yield()
val (frameNumber, callback) = it
callback?.doFrame(frameNumber)
}
@@ -243,7 +299,7 @@
}
override fun postFrameCallback(cb: FrameCallback) {
- frames.value = Pair(++frameCount, cb)
+ frames.value = Pair(frameCount++, cb)
}
override fun postCommitCallback(runnable: Runnable) {}
override fun getFrameTime() = frameCount
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
index c85f7b9..21e5068 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -155,6 +155,7 @@
mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN)
verify(repository).setPrimaryVisible(false)
verify(repository).setPrimaryShow(null)
+ verify(repository).setPrimaryHide(true)
verify(falsingCollector).onBouncerHidden()
verify(mPrimaryBouncerCallbackInteractor).dispatchReset()
verify(mPrimaryBouncerCallbackInteractor).dispatchFullyHidden()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index df48e1d..808abc8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -1437,6 +1437,17 @@
}
@Test
+ public void behindTint_inKeyguardState_bouncerNotActive_usesKeyguardBehindTint() {
+ when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false);
+ mScrimController.setClipsQsScrim(false);
+
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ finishAnimationsImmediately();
+ assertThat(mScrimBehind.getTint())
+ .isEqualTo(ScrimState.KEYGUARD.getBehindTint());
+ }
+
+ @Test
public void testNotificationTransparency_followsTransitionToFullShade() {
mScrimController.transitionTo(SHADE_LOCKED);
mScrimController.setRawPanelExpansionFraction(1.0f);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 6f70f0e..a798f40 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -44,6 +44,9 @@
private val _isDozing = MutableStateFlow(false)
override val isDozing: Flow<Boolean> = _isDozing
+ private val _isDreaming = MutableStateFlow(false)
+ override val isDreaming: Flow<Boolean> = _isDreaming
+
private val _dozeAmount = MutableStateFlow(0f)
override val dozeAmount: Flow<Float> = _dozeAmount
@@ -54,10 +57,13 @@
override val wakefulnessState: Flow<WakefulnessModel> = _wakefulnessState
private val _isUdfpsSupported = MutableStateFlow(false)
-
+
private val _isBouncerShowing = MutableStateFlow(false)
override val isBouncerShowing: Flow<Boolean> = _isBouncerShowing
+ private val _isKeyguardGoingAway = MutableStateFlow(false)
+ override val isKeyguardGoingAway: Flow<Boolean> = _isKeyguardGoingAway
+
private val _biometricUnlockState = MutableStateFlow(BiometricUnlockModel.NONE)
override val biometricUnlockState: Flow<BiometricUnlockModel> = _biometricUnlockState