Merge changes I645115ab,I73b51987,Id1b79253 into tm-qpr-dev
* changes: Scrims - Don't blend with bouncer when shade is collapsing Transitions - Add dreaming state Transitions - Make them cancelable
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package com.android.systemui.keyguard.data.repository
|
package com.android.systemui.keyguard.data.repository
|
||||||
|
|
||||||
import com.android.keyguard.KeyguardUpdateMonitor
|
import com.android.keyguard.KeyguardUpdateMonitor
|
||||||
|
import com.android.keyguard.KeyguardUpdateMonitorCallback
|
||||||
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
|
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
|
||||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||||
import com.android.systemui.common.shared.model.Position
|
import com.android.systemui.common.shared.model.Position
|
||||||
@@ -69,6 +70,9 @@ interface KeyguardRepository {
|
|||||||
*/
|
*/
|
||||||
val isKeyguardShowing: Flow<Boolean>
|
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. */
|
/** Observable for whether the bouncer is showing. */
|
||||||
val isBouncerShowing: Flow<Boolean>
|
val isBouncerShowing: Flow<Boolean>
|
||||||
|
|
||||||
@@ -84,6 +88,14 @@ interface KeyguardRepository {
|
|||||||
*/
|
*/
|
||||||
val isDozing: Flow<Boolean>
|
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.
|
* Observable for the amount of doze we are currently in.
|
||||||
*
|
*
|
||||||
@@ -176,6 +188,29 @@ constructor(
|
|||||||
awaitClose { keyguardStateController.removeCallback(callback) }
|
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 {
|
override val isBouncerShowing: Flow<Boolean> = conflatedCallbackFlow {
|
||||||
val callback =
|
val callback =
|
||||||
object : KeyguardStateController.Callback {
|
object : KeyguardStateController.Callback {
|
||||||
@@ -218,6 +253,25 @@ constructor(
|
|||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.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 {
|
override val dozeAmount: Flow<Float> = conflatedCallbackFlow {
|
||||||
val callback =
|
val callback =
|
||||||
object : StatusBarStateController.StateListener {
|
object : StatusBarStateController.StateListener {
|
||||||
|
|||||||
@@ -94,11 +94,13 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
|
|||||||
*/
|
*/
|
||||||
private val _transitions =
|
private val _transitions =
|
||||||
MutableSharedFlow<TransitionStep>(
|
MutableSharedFlow<TransitionStep>(
|
||||||
|
replay = 2,
|
||||||
extraBufferCapacity = 10,
|
extraBufferCapacity = 10,
|
||||||
onBufferOverflow = BufferOverflow.DROP_OLDEST
|
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||||
)
|
)
|
||||||
override val transitions = _transitions.asSharedFlow().distinctUntilChanged()
|
override val transitions = _transitions.asSharedFlow().distinctUntilChanged()
|
||||||
private var lastStep: TransitionStep = TransitionStep()
|
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
|
* When manual control of the transition is requested, a unique [UUID] is used as the handle
|
||||||
@@ -106,19 +108,39 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
|
|||||||
*/
|
*/
|
||||||
private var updateTransitionId: UUID? = null
|
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? {
|
override fun startTransition(info: TransitionInfo): UUID? {
|
||||||
if (lastStep.transitionState != TransitionState.FINISHED) {
|
if (lastStep.transitionState != TransitionState.FINISHED) {
|
||||||
// Open questions:
|
Log.i(TAG, "Transition still active: $lastStep, canceling")
|
||||||
// * 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val startingValue = 1f - lastStep.value
|
||||||
|
lastAnimator?.cancel()
|
||||||
|
lastAnimator = info.animator
|
||||||
|
|
||||||
info.animator?.let { animator ->
|
info.animator?.let { animator ->
|
||||||
// An animator was provided, so use it to run the transition
|
// 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 =
|
val updateListener =
|
||||||
object : AnimatorUpdateListener {
|
object : AnimatorUpdateListener {
|
||||||
override fun onAnimationUpdate(animation: ValueAnimator) {
|
override fun onAnimationUpdate(animation: ValueAnimator) {
|
||||||
@@ -134,15 +156,24 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
|
|||||||
val adapter =
|
val adapter =
|
||||||
object : AnimatorListenerAdapter() {
|
object : AnimatorListenerAdapter() {
|
||||||
override fun onAnimationStart(animation: Animator) {
|
override fun onAnimationStart(animation: Animator) {
|
||||||
emitTransition(TransitionStep(info, 0f, TransitionState.STARTED))
|
emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
|
||||||
}
|
}
|
||||||
override fun onAnimationCancel(animation: Animator) {
|
override fun onAnimationCancel(animation: Animator) {
|
||||||
Log.i(TAG, "Cancelling transition: $info")
|
endAnimation(animation, lastStep.value, TransitionState.CANCELED)
|
||||||
}
|
}
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
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.removeListener(this)
|
||||||
animator.removeUpdateListener(updateListener)
|
animator.removeUpdateListener(updateListener)
|
||||||
|
lastAnimator = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
animator.addListener(adapter)
|
animator.addListener(adapter)
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ import android.animation.ValueAnimator
|
|||||||
import com.android.systemui.animation.Interpolators
|
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.KeyguardRepository
|
|
||||||
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
||||||
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
|
||||||
@@ -35,18 +36,30 @@ class AodLockscreenTransitionInteractor
|
|||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
private val keyguardRepository: KeyguardRepository,
|
private val keyguardInteractor: KeyguardInteractor,
|
||||||
private val keyguardTransitionRepository: KeyguardTransitionRepository,
|
private val keyguardTransitionRepository: KeyguardTransitionRepository,
|
||||||
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
|
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
|
||||||
) : TransitionInteractor("AOD<->LOCKSCREEN") {
|
) : TransitionInteractor("AOD<->LOCKSCREEN") {
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
scope.launch {
|
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 ->
|
.collect { pair ->
|
||||||
val (isDozing, keyguardState) = pair
|
val (wakefulnessState, lastStartedStep) = pair
|
||||||
if (isDozing && keyguardState == KeyguardState.LOCKSCREEN) {
|
if (
|
||||||
|
isSleepingOrStartingToSleep(wakefulnessState) &&
|
||||||
|
lastStartedStep.to == KeyguardState.LOCKSCREEN
|
||||||
|
) {
|
||||||
keyguardTransitionRepository.startTransition(
|
keyguardTransitionRepository.startTransition(
|
||||||
TransitionInfo(
|
TransitionInfo(
|
||||||
name,
|
name,
|
||||||
@@ -55,7 +68,10 @@ constructor(
|
|||||||
getAnimator(),
|
getAnimator(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else if (!isDozing && keyguardState == KeyguardState.AOD) {
|
} else if (
|
||||||
|
isWakingOrStartingToWake(wakefulnessState) &&
|
||||||
|
lastStartedStep.to == KeyguardState.AOD
|
||||||
|
) {
|
||||||
keyguardTransitionRepository.startTransition(
|
keyguardTransitionRepository.startTransition(
|
||||||
TransitionInfo(
|
TransitionInfo(
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,8 +41,15 @@ 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
|
||||||
|
/**
|
||||||
|
* 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. */
|
/** Whether the keyguard is showing or not. */
|
||||||
val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
|
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. */
|
/** Whether the bouncer is showing or not. */
|
||||||
val isBouncerShowing: Flow<Boolean> = repository.isBouncerShowing
|
val isBouncerShowing: Flow<Boolean> = repository.isBouncerShowing
|
||||||
/** The device wake/sleep state */
|
/** The device wake/sleep state */
|
||||||
|
|||||||
@@ -40,12 +40,24 @@ constructor(
|
|||||||
keyguardInteractor.wakefulnessState.collect { logger.v("WakefulnessState", it) }
|
keyguardInteractor.wakefulnessState.collect { logger.v("WakefulnessState", it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
keyguardInteractor.isBouncerShowing.collect { logger.v("Bouncer showing", it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.launch { keyguardInteractor.isDozing.collect { logger.v("isDozing", it) } }
|
||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
interactor.finishedKeyguardTransitionStep.collect {
|
interactor.finishedKeyguardTransitionStep.collect {
|
||||||
logger.i("Finished transition", it)
|
logger.i("Finished transition", it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
interactor.canceledKeyguardTransitionStep.collect {
|
||||||
|
logger.i("Canceled transition", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
interactor.startedKeyguardTransitionStep.collect { logger.i("Started transition", it) }
|
interactor.startedKeyguardTransitionStep.collect { logger.i("Started transition", it) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ constructor(
|
|||||||
is GoneAodTransitionInteractor -> Log.d(TAG, "Started $it")
|
is GoneAodTransitionInteractor -> Log.d(TAG, "Started $it")
|
||||||
is LockscreenGoneTransitionInteractor -> Log.d(TAG, "Started $it")
|
is LockscreenGoneTransitionInteractor -> Log.d(TAG, "Started $it")
|
||||||
is AodToGoneTransitionInteractor -> 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()
|
it.start()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,14 @@ constructor(
|
|||||||
lockscreenToAodTransition,
|
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 */
|
/* The last [TransitionStep] with a [TransitionState] of FINISHED */
|
||||||
val finishedKeyguardTransitionStep: Flow<TransitionStep> =
|
val finishedKeyguardTransitionStep: Flow<TransitionStep> =
|
||||||
repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED }
|
repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED }
|
||||||
@@ -64,8 +72,4 @@ constructor(
|
|||||||
/* The last completed [KeyguardState] transition */
|
/* The last completed [KeyguardState] transition */
|
||||||
val finishedKeyguardState: Flow<KeyguardState> =
|
val finishedKeyguardState: Flow<KeyguardState> =
|
||||||
finishedKeyguardTransitionStep.map { step -> step.to }
|
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 }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,10 +56,20 @@ constructor(
|
|||||||
private fun listenForBouncerHiding() {
|
private fun listenForBouncerHiding() {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
keyguardInteractor.isBouncerShowing
|
keyguardInteractor.isBouncerShowing
|
||||||
.sample(keyguardInteractor.wakefulnessState, { a, b -> Pair(a, b) })
|
.sample(
|
||||||
.collect { pair ->
|
combine(
|
||||||
val (isBouncerShowing, wakefulnessState) = pair
|
keyguardInteractor.wakefulnessState,
|
||||||
if (!isBouncerShowing) {
|
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 =
|
val to =
|
||||||
if (
|
if (
|
||||||
wakefulnessState == WakefulnessModel.STARTING_TO_SLEEP ||
|
wakefulnessState == WakefulnessModel.STARTING_TO_SLEEP ||
|
||||||
@@ -90,10 +100,10 @@ constructor(
|
|||||||
combine(
|
combine(
|
||||||
keyguardTransitionInteractor.finishedKeyguardState,
|
keyguardTransitionInteractor.finishedKeyguardState,
|
||||||
keyguardInteractor.statusBarState,
|
keyguardInteractor.statusBarState,
|
||||||
) { keyguardState, statusBarState ->
|
) { a, b ->
|
||||||
Pair(keyguardState, statusBarState)
|
Pair(a, b)
|
||||||
},
|
},
|
||||||
{ shadeModel, pair -> Triple(shadeModel, pair.first, pair.second) }
|
{ a, bc -> Triple(a, bc.first, bc.second) }
|
||||||
)
|
)
|
||||||
.collect { triple ->
|
.collect { triple ->
|
||||||
val (shadeModel, keyguardState, statusBarState) = triple
|
val (shadeModel, keyguardState, statusBarState) = triple
|
||||||
@@ -116,8 +126,7 @@ constructor(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// TODO (b/251849525): Remove statusbarstate check when that state is
|
// TODO (b/251849525): Remove statusbarstate check when that state is
|
||||||
// integrated
|
// integrated into KeyguardTransitionRepository
|
||||||
// into KeyguardTransitionRepository
|
|
||||||
if (
|
if (
|
||||||
keyguardState == KeyguardState.LOCKSCREEN &&
|
keyguardState == KeyguardState.LOCKSCREEN &&
|
||||||
shadeModel.isUserDragging &&
|
shadeModel.isUserDragging &&
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ 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.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 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
|
||||||
@@ -34,13 +35,17 @@ class LockscreenGoneTransitionInteractor
|
|||||||
constructor(
|
constructor(
|
||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
private val keyguardInteractor: KeyguardInteractor,
|
private val keyguardInteractor: KeyguardInteractor,
|
||||||
|
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
|
||||||
private val keyguardTransitionRepository: KeyguardTransitionRepository,
|
private val keyguardTransitionRepository: KeyguardTransitionRepository,
|
||||||
) : TransitionInteractor("LOCKSCREEN->GONE") {
|
) : TransitionInteractor("LOCKSCREEN->GONE") {
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
keyguardInteractor.isKeyguardShowing.collect { isShowing ->
|
keyguardInteractor.isKeyguardGoingAway
|
||||||
if (!isShowing) {
|
.sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
|
||||||
|
.collect { pair ->
|
||||||
|
val (isKeyguardGoingAway, keyguardState) = pair
|
||||||
|
if (!isKeyguardGoingAway && keyguardState == KeyguardState.LOCKSCREEN) {
|
||||||
keyguardTransitionRepository.startTransition(
|
keyguardTransitionRepository.startTransition(
|
||||||
TransitionInfo(
|
TransitionInfo(
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -210,9 +210,12 @@ constructor(
|
|||||||
expansion == KeyguardBouncer.EXPANSION_HIDDEN &&
|
expansion == KeyguardBouncer.EXPANSION_HIDDEN &&
|
||||||
oldExpansion != KeyguardBouncer.EXPANSION_HIDDEN
|
oldExpansion != KeyguardBouncer.EXPANSION_HIDDEN
|
||||||
) {
|
) {
|
||||||
repository.setPrimaryVisible(false)
|
/*
|
||||||
repository.setPrimaryShow(null)
|
* There are cases where #hide() was not invoked, such as when
|
||||||
falsingCollector.onBouncerHidden()
|
* NotificationPanelViewController controls the hide animation. Make sure the state gets
|
||||||
|
* updated by calling #hide() directly.
|
||||||
|
*/
|
||||||
|
hide()
|
||||||
DejankUtils.postAfterTraversal { primaryBouncerCallbackInteractor.dispatchReset() }
|
DejankUtils.postAfterTraversal { primaryBouncerCallbackInteractor.dispatchReset() }
|
||||||
primaryBouncerCallbackInteractor.dispatchFullyHidden()
|
primaryBouncerCallbackInteractor.dispatchFullyHidden()
|
||||||
} else if (
|
} else if (
|
||||||
|
|||||||
@@ -44,7 +44,21 @@ abstract class StartKeyguardTransitionModule {
|
|||||||
|
|
||||||
@Binds @IntoSet abstract fun aodGone(impl: AodToGoneTransitionInteractor): TransitionInteractor
|
@Binds @IntoSet abstract fun aodGone(impl: AodToGoneTransitionInteractor): TransitionInteractor
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoSet
|
||||||
|
abstract fun bouncerGone(impl: BouncerToGoneTransitionInteractor): TransitionInteractor
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoSet
|
@IntoSet
|
||||||
abstract fun lockscreenGone(impl: LockscreenGoneTransitionInteractor): TransitionInteractor
|
abstract fun lockscreenGone(impl: LockscreenGoneTransitionInteractor): TransitionInteractor
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoSet
|
||||||
|
abstract fun dreamingLockscreen(
|
||||||
|
impl: DreamingLockscreenTransitionInteractor
|
||||||
|
): TransitionInteractor
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoSet
|
||||||
|
abstract fun dreamingToAod(impl: DreamingToAodTransitionInteractor): TransitionInteractor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,29 @@ package com.android.systemui.keyguard.shared.model
|
|||||||
|
|
||||||
/** List of all possible states to transition to/from */
|
/** List of all possible states to transition to/from */
|
||||||
enum class KeyguardState {
|
enum class KeyguardState {
|
||||||
/**
|
/*
|
||||||
* For initialization as well as when the security method is set to NONE, indicating that
|
* The display is completely off, as well as any sensors that would trigger the device to wake
|
||||||
* the keyguard should never be shown.
|
* up.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
*/
|
*/
|
||||||
NONE,
|
|
||||||
/* Always-on Display. The device is in a low-power mode with a minimal UI visible */
|
|
||||||
AOD,
|
AOD,
|
||||||
/*
|
/*
|
||||||
* The security screen prompt UI, containing PIN, Password, Pattern, and all FPS
|
* The security screen prompt UI, containing PIN, Password, Pattern, and all FPS
|
||||||
@@ -34,7 +51,6 @@ enum class KeyguardState {
|
|||||||
* unlocked if SWIPE security method is used, or if face lockscreen bypass is false.
|
* unlocked if SWIPE security method is used, or if face lockscreen bypass is false.
|
||||||
*/
|
*/
|
||||||
LOCKSCREEN,
|
LOCKSCREEN,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Keyguard is no longer visible. In most cases the user has just authenticated and keyguard
|
* 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
|
* is being removed, but there are other cases where the user is swiping away keyguard, such as
|
||||||
|
|||||||
@@ -17,7 +17,12 @@ package com.android.systemui.keyguard.shared.model
|
|||||||
|
|
||||||
/** Possible states for a running transition between [State] */
|
/** Possible states for a running transition between [State] */
|
||||||
enum class TransitionState {
|
enum class TransitionState {
|
||||||
|
/* Transition has begun. */
|
||||||
STARTED,
|
STARTED,
|
||||||
|
/* Transition is actively running. */
|
||||||
RUNNING,
|
RUNNING,
|
||||||
FINISHED
|
/* Transition has completed successfully. */
|
||||||
|
FINISHED,
|
||||||
|
/* Transition has been interrupted, and not completed successfully. */
|
||||||
|
CANCELED,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ package com.android.systemui.keyguard.shared.model
|
|||||||
|
|
||||||
/** This information will flow from the [KeyguardTransitionRepository] to control the UI layer */
|
/** This information will flow from the [KeyguardTransitionRepository] to control the UI layer */
|
||||||
data class TransitionStep(
|
data class TransitionStep(
|
||||||
val from: KeyguardState = KeyguardState.NONE,
|
val from: KeyguardState = KeyguardState.OFF,
|
||||||
val to: KeyguardState = KeyguardState.NONE,
|
val to: KeyguardState = KeyguardState.OFF,
|
||||||
val value: Float = 0f, // constrained [0.0, 1.0]
|
val value: Float = 0f, // constrained [0.0, 1.0]
|
||||||
val transitionState: TransitionState = TransitionState.FINISHED,
|
val transitionState: TransitionState = TransitionState.FINISHED,
|
||||||
val ownerName: String = "",
|
val ownerName: String = "",
|
||||||
|
|||||||
@@ -24,5 +24,15 @@ enum class WakefulnessModel {
|
|||||||
/** Device is now fully awake and interactive. */
|
/** Device is now fully awake and interactive. */
|
||||||
AWAKE,
|
AWAKE,
|
||||||
/** Signal that the device is now going to sleep. */
|
/** 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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,10 +279,7 @@ public class KeyguardBouncer {
|
|||||||
* @see #onFullyShown()
|
* @see #onFullyShown()
|
||||||
*/
|
*/
|
||||||
private void onFullyHidden() {
|
private void onFullyHidden() {
|
||||||
cancelShowRunnable();
|
|
||||||
setVisibility(View.INVISIBLE);
|
|
||||||
mFalsingCollector.onBouncerHidden();
|
|
||||||
DejankUtils.postAfterTraversal(mResetRunnable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setVisibility(@View.Visibility int visibility) {
|
private void setVisibility(@View.Visibility int visibility) {
|
||||||
@@ -459,7 +456,13 @@ public class KeyguardBouncer {
|
|||||||
onFullyShown();
|
onFullyShown();
|
||||||
dispatchFullyShown();
|
dispatchFullyShown();
|
||||||
} else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
|
} 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();
|
dispatchFullyHidden();
|
||||||
} else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
|
} else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
|
||||||
dispatchStartingToHide();
|
dispatchStartingToHide();
|
||||||
|
|||||||
@@ -895,7 +895,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
|||||||
|
|
||||||
float stateBehind = mClipsQsScrim ? state.getNotifAlpha() : state.getBehindAlpha();
|
float stateBehind = mClipsQsScrim ? state.getNotifAlpha() : state.getBehindAlpha();
|
||||||
float behindAlpha;
|
float behindAlpha;
|
||||||
int behindTint;
|
int behindTint = state.getBehindTint();
|
||||||
if (mDarkenWhileDragging) {
|
if (mDarkenWhileDragging) {
|
||||||
behindAlpha = MathUtils.lerp(mDefaultScrimAlpha, stateBehind,
|
behindAlpha = MathUtils.lerp(mDefaultScrimAlpha, stateBehind,
|
||||||
interpolatedFract);
|
interpolatedFract);
|
||||||
@@ -903,6 +903,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
|||||||
behindAlpha = MathUtils.lerp(0 /* start */, stateBehind,
|
behindAlpha = MathUtils.lerp(0 /* start */, stateBehind,
|
||||||
interpolatedFract);
|
interpolatedFract);
|
||||||
}
|
}
|
||||||
|
if (mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()) {
|
||||||
if (mClipsQsScrim) {
|
if (mClipsQsScrim) {
|
||||||
behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getNotifTint(),
|
behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getNotifTint(),
|
||||||
state.getNotifTint(), interpolatedFract);
|
state.getNotifTint(), interpolatedFract);
|
||||||
@@ -910,6 +911,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
|||||||
behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
|
behindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
|
||||||
state.getBehindTint(), interpolatedFract);
|
state.getBehindTint(), interpolatedFract);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (mQsExpansion > 0) {
|
if (mQsExpansion > 0) {
|
||||||
behindAlpha = MathUtils.lerp(behindAlpha, mDefaultScrimAlpha, mQsExpansion);
|
behindAlpha = MathUtils.lerp(behindAlpha, mDefaultScrimAlpha, mQsExpansion);
|
||||||
float tintProgress = mQsExpansion;
|
float tintProgress = mQsExpansion;
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
@Override
|
@Override
|
||||||
public void onFullyHidden() {
|
public void onFullyHidden() {
|
||||||
mPrimaryBouncerAnimating = false;
|
mPrimaryBouncerAnimating = false;
|
||||||
|
updateStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1184,12 +1185,16 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
updateNavigationBarVisibility(navBarVisible);
|
updateNavigationBarVisibility(navBarVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (primaryBouncerShowing != mLastPrimaryBouncerShowing || mFirstUpdate) {
|
boolean isPrimaryBouncerShowingChanged =
|
||||||
|
primaryBouncerShowing != mLastPrimaryBouncerShowing;
|
||||||
|
mLastPrimaryBouncerShowing = primaryBouncerShowing;
|
||||||
|
|
||||||
|
if (isPrimaryBouncerShowingChanged || mFirstUpdate) {
|
||||||
mNotificationShadeWindowController.setBouncerShowing(primaryBouncerShowing);
|
mNotificationShadeWindowController.setBouncerShowing(primaryBouncerShowing);
|
||||||
mCentralSurfaces.setBouncerShowing(primaryBouncerShowing);
|
mCentralSurfaces.setBouncerShowing(primaryBouncerShowing);
|
||||||
}
|
}
|
||||||
if (primaryBouncerIsOrWillBeShowing != mLastPrimaryBouncerIsOrWillBeShowing || mFirstUpdate
|
if (primaryBouncerIsOrWillBeShowing != mLastPrimaryBouncerIsOrWillBeShowing || mFirstUpdate
|
||||||
|| primaryBouncerShowing != mLastPrimaryBouncerShowing) {
|
|| isPrimaryBouncerShowingChanged) {
|
||||||
mKeyguardUpdateManager.sendPrimaryBouncerChanged(primaryBouncerIsOrWillBeShowing,
|
mKeyguardUpdateManager.sendPrimaryBouncerChanged(primaryBouncerIsOrWillBeShowing,
|
||||||
primaryBouncerShowing);
|
primaryBouncerShowing);
|
||||||
}
|
}
|
||||||
@@ -1198,7 +1203,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
|||||||
mLastShowing = showing;
|
mLastShowing = showing;
|
||||||
mLastGlobalActionsVisible = mGlobalActionsVisible;
|
mLastGlobalActionsVisible = mGlobalActionsVisible;
|
||||||
mLastOccluded = occluded;
|
mLastOccluded = occluded;
|
||||||
mLastPrimaryBouncerShowing = primaryBouncerShowing;
|
|
||||||
mLastPrimaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing;
|
mLastPrimaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing;
|
||||||
mLastBouncerDismissible = primaryBouncerDismissible;
|
mLastBouncerDismissible = primaryBouncerDismissible;
|
||||||
mLastRemoteInputActive = remoteInputActive;
|
mLastRemoteInputActive = remoteInputActive;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.repository
|
|||||||
|
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.keyguard.KeyguardUpdateMonitor
|
import com.android.keyguard.KeyguardUpdateMonitor
|
||||||
|
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
|
||||||
@@ -256,6 +257,48 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Test
|
||||||
fun biometricUnlockState() = runBlockingTest {
|
fun biometricUnlockState() = runBlockingTest {
|
||||||
val values = mutableListOf<BiometricUnlockModel>()
|
val values = mutableListOf<BiometricUnlockModel>()
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import android.view.Choreographer.FrameCallback
|
|||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.animation.Interpolators
|
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.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.KeyguardState.LOCKSCREEN
|
||||||
import com.android.systemui.keyguard.shared.model.TransitionInfo
|
import com.android.systemui.keyguard.shared.model.TransitionInfo
|
||||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||||
@@ -38,7 +38,6 @@ import java.util.UUID
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -91,18 +90,51 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertSteps(steps, listWithStep(BigDecimal(.1)))
|
assertSteps(steps, listWithStep(BigDecimal(.1)), AOD, LOCKSCREEN)
|
||||||
|
|
||||||
job.cancel()
|
job.cancel()
|
||||||
provider.stop()
|
provider.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `startTransition called during another transition fails`() {
|
fun `starting second transition will cancel the first transition`() {
|
||||||
underTest.startTransition(TransitionInfo(OWNER_NAME, AOD, LOCKSCREEN, null))
|
runBlocking(IMMEDIATE) {
|
||||||
underTest.startTransition(TransitionInfo(OWNER_NAME, LOCKSCREEN, BOUNCER, null))
|
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
|
@Test
|
||||||
@@ -165,11 +197,15 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
|
|||||||
assertThat(wtfHandler.failed).isTrue()
|
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>()
|
val steps = mutableListOf<BigDecimal>()
|
||||||
|
|
||||||
var i = BigDecimal.ZERO
|
var i = start
|
||||||
while (i.compareTo(BigDecimal.ONE) <= 0) {
|
while (i.compareTo(stop) <= 0) {
|
||||||
steps.add(i)
|
steps.add(i)
|
||||||
i = (i + step).setScale(2, RoundingMode.HALF_UP)
|
i = (i + step).setScale(2, RoundingMode.HALF_UP)
|
||||||
}
|
}
|
||||||
@@ -177,23 +213,43 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
|
|||||||
return steps
|
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])
|
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 ->
|
fractions.forEachIndexed { index, fraction ->
|
||||||
assertThat(steps[index + 1])
|
assertThat(steps[index + 1])
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
TransitionStep(
|
TransitionStep(
|
||||||
AOD,
|
from,
|
||||||
LOCKSCREEN,
|
to,
|
||||||
fraction.toFloat(),
|
fraction.toFloat(),
|
||||||
TransitionState.RUNNING,
|
TransitionState.RUNNING,
|
||||||
OWNER_NAME
|
OWNER_NAME
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
val lastValue = fractions[fractions.size - 1].toFloat()
|
||||||
|
val status =
|
||||||
|
if (lastValue < 1f) {
|
||||||
|
TransitionState.CANCELED
|
||||||
|
} else {
|
||||||
|
TransitionState.FINISHED
|
||||||
|
}
|
||||||
assertThat(steps[steps.size - 1])
|
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()
|
assertThat(wtfHandler.failed).isFalse()
|
||||||
}
|
}
|
||||||
@@ -230,7 +286,7 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
|
|||||||
scope.launch {
|
scope.launch {
|
||||||
frames.collect {
|
frames.collect {
|
||||||
// Delay is required for AnimationHandler to properly register a callback
|
// Delay is required for AnimationHandler to properly register a callback
|
||||||
delay(1)
|
yield()
|
||||||
val (frameNumber, callback) = it
|
val (frameNumber, callback) = it
|
||||||
callback?.doFrame(frameNumber)
|
callback?.doFrame(frameNumber)
|
||||||
}
|
}
|
||||||
@@ -243,7 +299,7 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun postFrameCallback(cb: FrameCallback) {
|
override fun postFrameCallback(cb: FrameCallback) {
|
||||||
frames.value = Pair(++frameCount, cb)
|
frames.value = Pair(frameCount++, cb)
|
||||||
}
|
}
|
||||||
override fun postCommitCallback(runnable: Runnable) {}
|
override fun postCommitCallback(runnable: Runnable) {}
|
||||||
override fun getFrameTime() = frameCount
|
override fun getFrameTime() = frameCount
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
|
|||||||
mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN)
|
mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN)
|
||||||
verify(repository).setPrimaryVisible(false)
|
verify(repository).setPrimaryVisible(false)
|
||||||
verify(repository).setPrimaryShow(null)
|
verify(repository).setPrimaryShow(null)
|
||||||
|
verify(repository).setPrimaryHide(true)
|
||||||
verify(falsingCollector).onBouncerHidden()
|
verify(falsingCollector).onBouncerHidden()
|
||||||
verify(mPrimaryBouncerCallbackInteractor).dispatchReset()
|
verify(mPrimaryBouncerCallbackInteractor).dispatchReset()
|
||||||
verify(mPrimaryBouncerCallbackInteractor).dispatchFullyHidden()
|
verify(mPrimaryBouncerCallbackInteractor).dispatchFullyHidden()
|
||||||
|
|||||||
@@ -1436,6 +1436,17 @@ public class ScrimControllerTest extends SysuiTestCase {
|
|||||||
assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
|
assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Test
|
||||||
public void testNotificationTransparency_followsTransitionToFullShade() {
|
public void testNotificationTransparency_followsTransitionToFullShade() {
|
||||||
mScrimController.transitionTo(SHADE_LOCKED);
|
mScrimController.transitionTo(SHADE_LOCKED);
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ class FakeKeyguardRepository : KeyguardRepository {
|
|||||||
private val _isDozing = MutableStateFlow(false)
|
private val _isDozing = MutableStateFlow(false)
|
||||||
override val isDozing: Flow<Boolean> = _isDozing
|
override val isDozing: Flow<Boolean> = _isDozing
|
||||||
|
|
||||||
|
private val _isDreaming = MutableStateFlow(false)
|
||||||
|
override val isDreaming: Flow<Boolean> = _isDreaming
|
||||||
|
|
||||||
private val _dozeAmount = MutableStateFlow(0f)
|
private val _dozeAmount = MutableStateFlow(0f)
|
||||||
override val dozeAmount: Flow<Float> = _dozeAmount
|
override val dozeAmount: Flow<Float> = _dozeAmount
|
||||||
|
|
||||||
@@ -58,6 +61,9 @@ class FakeKeyguardRepository : KeyguardRepository {
|
|||||||
private val _isBouncerShowing = MutableStateFlow(false)
|
private val _isBouncerShowing = MutableStateFlow(false)
|
||||||
override val isBouncerShowing: Flow<Boolean> = _isBouncerShowing
|
override val isBouncerShowing: Flow<Boolean> = _isBouncerShowing
|
||||||
|
|
||||||
|
private val _isKeyguardGoingAway = MutableStateFlow(false)
|
||||||
|
override val isKeyguardGoingAway: Flow<Boolean> = _isKeyguardGoingAway
|
||||||
|
|
||||||
private val _biometricUnlockState = MutableStateFlow(BiometricUnlockModel.NONE)
|
private val _biometricUnlockState = MutableStateFlow(BiometricUnlockModel.NONE)
|
||||||
override val biometricUnlockState: Flow<BiometricUnlockModel> = _biometricUnlockState
|
override val biometricUnlockState: Flow<BiometricUnlockModel> = _biometricUnlockState
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user