Merge "Transitions - Add GONE state" into tm-qpr-dev
This commit is contained in:
@@ -237,6 +237,9 @@ class DefaultClockController(
|
|||||||
) {
|
) {
|
||||||
var isActive: Boolean = fraction < 0.5f
|
var isActive: Boolean = fraction < 0.5f
|
||||||
fun update(newFraction: Float): Pair<Boolean, Boolean> {
|
fun update(newFraction: Float): Pair<Boolean, Boolean> {
|
||||||
|
if (newFraction == fraction) {
|
||||||
|
return Pair(isActive, false)
|
||||||
|
}
|
||||||
val wasActive = isActive
|
val wasActive = isActive
|
||||||
val hasJumped =
|
val hasJumped =
|
||||||
(fraction == 0f && newFraction == 1f) || (fraction == 1f && newFraction == 0f)
|
(fraction == 0f && newFraction == 1f) || (fraction == 1f && newFraction == 0f)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.android.systemui.flags.Flags.DOZING_MIGRATION_1
|
|||||||
import com.android.systemui.flags.Flags.REGION_SAMPLING
|
import com.android.systemui.flags.Flags.REGION_SAMPLING
|
||||||
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
|
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
|
||||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||||
import com.android.systemui.log.dagger.KeyguardClockLog
|
import com.android.systemui.log.dagger.KeyguardClockLog
|
||||||
import com.android.systemui.plugins.ClockController
|
import com.android.systemui.plugins.ClockController
|
||||||
@@ -47,6 +48,7 @@ import kotlinx.coroutines.DisposableHandle
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@@ -186,10 +188,12 @@ open class ClockEventController @Inject constructor(
|
|||||||
private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
|
private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
|
||||||
override fun onKeyguardVisibilityChanged(visible: Boolean) {
|
override fun onKeyguardVisibilityChanged(visible: Boolean) {
|
||||||
isKeyguardVisible = visible
|
isKeyguardVisible = visible
|
||||||
|
if (!featureFlags.isEnabled(DOZING_MIGRATION_1)) {
|
||||||
if (!isKeyguardVisible) {
|
if (!isKeyguardVisible) {
|
||||||
clock?.animations?.doze(if (isDozing) 1f else 0f)
|
clock?.animations?.doze(if (isDozing) 1f else 0f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onTimeFormatChanged(timeFormat: String) {
|
override fun onTimeFormatChanged(timeFormat: String) {
|
||||||
clock?.events?.onTimeFormatChanged(DateFormat.is24HourFormat(context))
|
clock?.events?.onTimeFormatChanged(DateFormat.is24HourFormat(context))
|
||||||
@@ -224,6 +228,7 @@ open class ClockEventController @Inject constructor(
|
|||||||
listenForDozing(this)
|
listenForDozing(this)
|
||||||
if (featureFlags.isEnabled(DOZING_MIGRATION_1)) {
|
if (featureFlags.isEnabled(DOZING_MIGRATION_1)) {
|
||||||
listenForDozeAmountTransition(this)
|
listenForDozeAmountTransition(this)
|
||||||
|
listenForGoneToAodTransition(this)
|
||||||
} else {
|
} else {
|
||||||
listenForDozeAmount(this)
|
listenForDozeAmount(this)
|
||||||
}
|
}
|
||||||
@@ -276,6 +281,22 @@ open class ClockEventController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When keyguard is displayed again after being gone, the clock must be reset to full
|
||||||
|
* dozing.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
internal fun listenForGoneToAodTransition(scope: CoroutineScope): Job {
|
||||||
|
return scope.launch {
|
||||||
|
keyguardTransitionInteractor.goneToAodTransition.filter {
|
||||||
|
it.transitionState == TransitionState.STARTED
|
||||||
|
}.collect {
|
||||||
|
dozeAmount = 1f
|
||||||
|
clock?.animations?.doze(dozeAmount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
internal fun listenForDozing(scope: CoroutineScope): Job {
|
internal fun listenForDozing(scope: CoroutineScope): Job {
|
||||||
return scope.launch {
|
return scope.launch {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.android.systemui.plugins.log.LogBuffer
|
|||||||
import com.android.systemui.plugins.log.LogLevel
|
import com.android.systemui.plugins.log.LogLevel
|
||||||
import com.android.systemui.plugins.log.LogLevel.DEBUG
|
import com.android.systemui.plugins.log.LogLevel.DEBUG
|
||||||
import com.android.systemui.plugins.log.LogLevel.ERROR
|
import com.android.systemui.plugins.log.LogLevel.ERROR
|
||||||
|
import com.android.systemui.plugins.log.LogLevel.INFO
|
||||||
import com.android.systemui.plugins.log.LogLevel.VERBOSE
|
import com.android.systemui.plugins.log.LogLevel.VERBOSE
|
||||||
import com.android.systemui.plugins.log.LogLevel.WARNING
|
import com.android.systemui.plugins.log.LogLevel.WARNING
|
||||||
import com.android.systemui.plugins.log.MessageInitializer
|
import com.android.systemui.plugins.log.MessageInitializer
|
||||||
@@ -50,6 +51,14 @@ class KeyguardLogger @Inject constructor(@KeyguardLog private val buffer: LogBuf
|
|||||||
buffer.log(TAG, DEBUG, messageInitializer, messagePrinter)
|
buffer.log(TAG, DEBUG, messageInitializer, messagePrinter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun v(msg: String, arg: Any) {
|
||||||
|
buffer.log(TAG, VERBOSE, { str1 = arg.toString() }, { "$msg: $str1" })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(msg: String, arg: Any) {
|
||||||
|
buffer.log(TAG, INFO, { str1 = arg.toString() }, { "$msg: $str1" })
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: remove after b/237743330 is fixed
|
// TODO: remove after b/237743330 is fixed
|
||||||
fun logStatusBarCalculatedAlpha(alpha: Float) {
|
fun logStatusBarCalculatedAlpha(alpha: Float) {
|
||||||
debugLog({ double1 = alpha.toDouble() }, { "Calculated new alpha: $double1" })
|
debugLog({ double1 = alpha.toDouble() }, { "Calculated new alpha: $double1" })
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ object Flags {
|
|||||||
* Migration from the legacy isDozing/dozeAmount paths to the new KeyguardTransitionRepository
|
* Migration from the legacy isDozing/dozeAmount paths to the new KeyguardTransitionRepository
|
||||||
* will occur in stages. This is one stage of many to come.
|
* will occur in stages. This is one stage of many to come.
|
||||||
*/
|
*/
|
||||||
@JvmField val DOZING_MIGRATION_1 = UnreleasedFlag(213, teamfood = true)
|
// TODO(b/255607168): Tracking Bug
|
||||||
|
@JvmField val DOZING_MIGRATION_1 = UnreleasedFlag(213)
|
||||||
|
|
||||||
// 300 - power menu
|
// 300 - power menu
|
||||||
// TODO(b/254512600): Tracking Bug
|
// TODO(b/254512600): Tracking Bug
|
||||||
|
|||||||
@@ -21,7 +21,10 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
|
|||||||
import com.android.systemui.common.shared.model.Position
|
import com.android.systemui.common.shared.model.Position
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.doze.DozeHost
|
import com.android.systemui.doze.DozeHost
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness
|
||||||
import com.android.systemui.keyguard.shared.model.StatusBarState
|
import com.android.systemui.keyguard.shared.model.StatusBarState
|
||||||
|
import com.android.systemui.keyguard.shared.model.WakefulnessModel
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -89,6 +92,9 @@ interface KeyguardRepository {
|
|||||||
/** Observable for the [StatusBarState] */
|
/** Observable for the [StatusBarState] */
|
||||||
val statusBarState: Flow<StatusBarState>
|
val statusBarState: Flow<StatusBarState>
|
||||||
|
|
||||||
|
/** Observable for device wake/sleep state */
|
||||||
|
val wakefulnessState: Flow<WakefulnessModel>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns `true` if the keyguard is showing; `false` otherwise.
|
* Returns `true` if the keyguard is showing; `false` otherwise.
|
||||||
*
|
*
|
||||||
@@ -118,6 +124,7 @@ constructor(
|
|||||||
statusBarStateController: StatusBarStateController,
|
statusBarStateController: StatusBarStateController,
|
||||||
private val keyguardStateController: KeyguardStateController,
|
private val keyguardStateController: KeyguardStateController,
|
||||||
dozeHost: DozeHost,
|
dozeHost: DozeHost,
|
||||||
|
wakefulnessLifecycle: WakefulnessLifecycle,
|
||||||
) : KeyguardRepository {
|
) : KeyguardRepository {
|
||||||
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
|
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
|
||||||
override val animateBottomAreaDozingTransitions =
|
override val animateBottomAreaDozingTransitions =
|
||||||
@@ -207,6 +214,40 @@ constructor(
|
|||||||
awaitClose { statusBarStateController.removeCallback(callback) }
|
awaitClose { statusBarStateController.removeCallback(callback) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val wakefulnessState: Flow<WakefulnessModel> = conflatedCallbackFlow {
|
||||||
|
val callback =
|
||||||
|
object : WakefulnessLifecycle.Observer {
|
||||||
|
override fun onStartedWakingUp() {
|
||||||
|
trySendWithFailureLogging(
|
||||||
|
WakefulnessModel.STARTING_TO_WAKE,
|
||||||
|
TAG,
|
||||||
|
"Wakefulness: starting to wake"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
override fun onFinishedWakingUp() {
|
||||||
|
trySendWithFailureLogging(WakefulnessModel.AWAKE, TAG, "Wakefulness: awake")
|
||||||
|
}
|
||||||
|
override fun onStartedGoingToSleep() {
|
||||||
|
trySendWithFailureLogging(
|
||||||
|
WakefulnessModel.STARTING_TO_SLEEP,
|
||||||
|
TAG,
|
||||||
|
"Wakefulness: starting to sleep"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
override fun onFinishedGoingToSleep() {
|
||||||
|
trySendWithFailureLogging(WakefulnessModel.ASLEEP, TAG, "Wakefulness: asleep")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wakefulnessLifecycle.addObserver(callback)
|
||||||
|
trySendWithFailureLogging(
|
||||||
|
wakefulnessIntToObject(wakefulnessLifecycle.getWakefulness()),
|
||||||
|
TAG,
|
||||||
|
"initial wakefulness state"
|
||||||
|
)
|
||||||
|
|
||||||
|
awaitClose { wakefulnessLifecycle.removeObserver(callback) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun setAnimateDozingTransitions(animate: Boolean) {
|
override fun setAnimateDozingTransitions(animate: Boolean) {
|
||||||
_animateBottomAreaDozingTransitions.value = animate
|
_animateBottomAreaDozingTransitions.value = animate
|
||||||
}
|
}
|
||||||
@@ -228,6 +269,16 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun wakefulnessIntToObject(@Wakefulness value: Int): WakefulnessModel {
|
||||||
|
return when (value) {
|
||||||
|
0 -> WakefulnessModel.ASLEEP
|
||||||
|
1 -> WakefulnessModel.STARTING_TO_WAKE
|
||||||
|
2 -> WakefulnessModel.AWAKE
|
||||||
|
3 -> WakefulnessModel.STARTING_TO_SLEEP
|
||||||
|
else -> throw IllegalArgumentException("Invalid Wakefulness value: $value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "KeyguardRepositoryImpl"
|
private const val TAG = "KeyguardRepositoryImpl"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,4 +22,9 @@ import dagger.Module
|
|||||||
@Module
|
@Module
|
||||||
interface KeyguardRepositoryModule {
|
interface KeyguardRepositoryModule {
|
||||||
@Binds fun keyguardRepository(impl: KeyguardRepositoryImpl): KeyguardRepository
|
@Binds fun keyguardRepository(impl: KeyguardRepositoryImpl): KeyguardRepository
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
fun keyguardTransitionRepository(
|
||||||
|
impl: KeyguardTransitionRepositoryImpl
|
||||||
|
): KeyguardTransitionRepository
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,27 +29,33 @@ import com.android.systemui.keyguard.shared.model.TransitionState
|
|||||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
|
|
||||||
@SysUISingleton
|
/**
|
||||||
class KeyguardTransitionRepository @Inject constructor() {
|
* The source of truth for all keyguard transitions.
|
||||||
/*
|
*
|
||||||
* Each transition between [KeyguardState]s will have an associated Flow.
|
* While the keyguard component is visible, it can undergo a number of transitions between different
|
||||||
* In order to collect these events, clients should call [transition].
|
* UI screens, such as AOD (Always-on Display), Bouncer, and others mentioned in [KeyguardState].
|
||||||
|
* These UI elements should listen to events emitted by [transitions], to ensure a centrally
|
||||||
|
* coordinated experience.
|
||||||
|
*
|
||||||
|
* To create or modify logic that controls when and how transitions get created, look at
|
||||||
|
* [TransitionInteractor]. These interactors will call [startTransition] and [updateTransition] on
|
||||||
|
* this repository.
|
||||||
*/
|
*/
|
||||||
private val _transitions = MutableStateFlow(TransitionStep())
|
interface KeyguardTransitionRepository {
|
||||||
val transitions = _transitions.asStateFlow()
|
/**
|
||||||
|
* All events regarding transitions, as they start, run, and complete. [TransitionStep#value] is
|
||||||
/* Information about the active transition. */
|
* a float between [0, 1] representing progress towards completion. If this is a user driven
|
||||||
private var currentTransitionInfo: TransitionInfo? = null
|
* transition, that value may not be a monotonic progression, as the user may swipe in any
|
||||||
/*
|
* direction.
|
||||||
* When manual control of the transition is requested, a unique [UUID] is used as the handle
|
|
||||||
* to permit calls to [updateTransition]
|
|
||||||
*/
|
*/
|
||||||
private var updateTransitionId: UUID? = null
|
val transitions: Flow<TransitionStep>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interactors that require information about changes between [KeyguardState]s will call this to
|
* Interactors that require information about changes between [KeyguardState]s will call this to
|
||||||
@@ -60,65 +66,10 @@ class KeyguardTransitionRepository @Inject constructor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begin a transition from one state to another. The [info.from] must match
|
* Begin a transition from one state to another. Will not start if another transition is in
|
||||||
* [currentTransitionInfo.to], or the request will be denied. This is enforced to avoid
|
* progress.
|
||||||
* unplanned transitions.
|
|
||||||
*/
|
*/
|
||||||
fun startTransition(info: TransitionInfo): UUID? {
|
fun startTransition(info: TransitionInfo): UUID?
|
||||||
if (currentTransitionInfo != null) {
|
|
||||||
// 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: $currentTransitionInfo")
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
currentTransitionInfo?.animator?.cancel()
|
|
||||||
|
|
||||||
currentTransitionInfo = info
|
|
||||||
info.animator?.let { animator ->
|
|
||||||
// An animator was provided, so use it to run the transition
|
|
||||||
animator.setFloatValues(0f, 1f)
|
|
||||||
val updateListener =
|
|
||||||
object : AnimatorUpdateListener {
|
|
||||||
override fun onAnimationUpdate(animation: ValueAnimator) {
|
|
||||||
emitTransition(
|
|
||||||
info,
|
|
||||||
(animation.getAnimatedValue() as Float),
|
|
||||||
TransitionState.RUNNING
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val adapter =
|
|
||||||
object : AnimatorListenerAdapter() {
|
|
||||||
override fun onAnimationStart(animation: Animator) {
|
|
||||||
Log.i(TAG, "Starting transition: $info")
|
|
||||||
emitTransition(info, 0f, TransitionState.STARTED)
|
|
||||||
}
|
|
||||||
override fun onAnimationCancel(animation: Animator) {
|
|
||||||
Log.i(TAG, "Cancelling transition: $info")
|
|
||||||
}
|
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
|
||||||
Log.i(TAG, "Ending transition: $info")
|
|
||||||
emitTransition(info, 1f, TransitionState.FINISHED)
|
|
||||||
animator.removeListener(this)
|
|
||||||
animator.removeUpdateListener(updateListener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
animator.addListener(adapter)
|
|
||||||
animator.addUpdateListener(updateListener)
|
|
||||||
animator.start()
|
|
||||||
return@startTransition null
|
|
||||||
}
|
|
||||||
?: run {
|
|
||||||
Log.i(TAG, "Starting transition (manual): $info")
|
|
||||||
emitTransition(info, 0f, TransitionState.STARTED)
|
|
||||||
|
|
||||||
// No animator, so it's manual. Provide a mechanism to callback
|
|
||||||
updateTransitionId = UUID.randomUUID()
|
|
||||||
return@startTransition updateTransitionId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows manual control of a transition. When calling [startTransition], the consumer must pass
|
* Allows manual control of a transition. When calling [startTransition], the consumer must pass
|
||||||
@@ -132,58 +83,127 @@ class KeyguardTransitionRepository @Inject constructor() {
|
|||||||
transitionId: UUID,
|
transitionId: UUID,
|
||||||
@FloatRange(from = 0.0, to = 1.0) value: Float,
|
@FloatRange(from = 0.0, to = 1.0) value: Float,
|
||||||
state: TransitionState
|
state: TransitionState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SysUISingleton
|
||||||
|
class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitionRepository {
|
||||||
|
/*
|
||||||
|
* Each transition between [KeyguardState]s will have an associated Flow.
|
||||||
|
* In order to collect these events, clients should call [transition].
|
||||||
|
*/
|
||||||
|
private val _transitions =
|
||||||
|
MutableSharedFlow<TransitionStep>(
|
||||||
|
extraBufferCapacity = 10,
|
||||||
|
onBufferOverflow = BufferOverflow.DROP_OLDEST
|
||||||
|
)
|
||||||
|
override val transitions = _transitions.asSharedFlow().distinctUntilChanged()
|
||||||
|
private var lastStep: TransitionStep = TransitionStep()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When manual control of the transition is requested, a unique [UUID] is used as the handle
|
||||||
|
* to permit calls to [updateTransition]
|
||||||
|
*/
|
||||||
|
private var updateTransitionId: UUID? = null
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
info.animator?.let { animator ->
|
||||||
|
// An animator was provided, so use it to run the transition
|
||||||
|
animator.setFloatValues(0f, 1f)
|
||||||
|
val updateListener =
|
||||||
|
object : AnimatorUpdateListener {
|
||||||
|
override fun onAnimationUpdate(animation: ValueAnimator) {
|
||||||
|
emitTransition(
|
||||||
|
TransitionStep(
|
||||||
|
info,
|
||||||
|
(animation.getAnimatedValue() as Float),
|
||||||
|
TransitionState.RUNNING
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val adapter =
|
||||||
|
object : AnimatorListenerAdapter() {
|
||||||
|
override fun onAnimationStart(animation: Animator) {
|
||||||
|
emitTransition(TransitionStep(info, 0f, TransitionState.STARTED))
|
||||||
|
}
|
||||||
|
override fun onAnimationCancel(animation: Animator) {
|
||||||
|
Log.i(TAG, "Cancelling transition: $info")
|
||||||
|
}
|
||||||
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
|
emitTransition(TransitionStep(info, 1f, TransitionState.FINISHED))
|
||||||
|
animator.removeListener(this)
|
||||||
|
animator.removeUpdateListener(updateListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
animator.addListener(adapter)
|
||||||
|
animator.addUpdateListener(updateListener)
|
||||||
|
animator.start()
|
||||||
|
return@startTransition null
|
||||||
|
}
|
||||||
|
?: run {
|
||||||
|
emitTransition(TransitionStep(info, 0f, TransitionState.STARTED))
|
||||||
|
|
||||||
|
// No animator, so it's manual. Provide a mechanism to callback
|
||||||
|
updateTransitionId = UUID.randomUUID()
|
||||||
|
return@startTransition updateTransitionId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateTransition(
|
||||||
|
transitionId: UUID,
|
||||||
|
@FloatRange(from = 0.0, to = 1.0) value: Float,
|
||||||
|
state: TransitionState
|
||||||
) {
|
) {
|
||||||
if (updateTransitionId != transitionId) {
|
if (updateTransitionId != transitionId) {
|
||||||
Log.wtf(TAG, "Attempting to update with old/invalid transitionId: $transitionId")
|
Log.wtf(TAG, "Attempting to update with old/invalid transitionId: $transitionId")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTransitionInfo == null) {
|
|
||||||
Log.wtf(TAG, "Attempting to update with null 'currentTransitionInfo'")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
currentTransitionInfo?.let { info ->
|
|
||||||
if (state == TransitionState.FINISHED) {
|
if (state == TransitionState.FINISHED) {
|
||||||
updateTransitionId = null
|
updateTransitionId = null
|
||||||
Log.i(TAG, "Ending transition: $info")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emitTransition(info, value, state)
|
val nextStep = lastStep.copy(value = value, transitionState = state)
|
||||||
}
|
emitTransition(nextStep, isManual = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun emitTransition(
|
private fun emitTransition(nextStep: TransitionStep, isManual: Boolean = false) {
|
||||||
info: TransitionInfo,
|
trace(nextStep, isManual)
|
||||||
value: Float,
|
val emitted = _transitions.tryEmit(nextStep)
|
||||||
transitionState: TransitionState
|
if (!emitted) {
|
||||||
) {
|
Log.w(TAG, "Failed to emit next value without suspending")
|
||||||
trace(info, transitionState)
|
|
||||||
|
|
||||||
if (transitionState == TransitionState.FINISHED) {
|
|
||||||
currentTransitionInfo = null
|
|
||||||
}
|
}
|
||||||
_transitions.value = TransitionStep(info.from, info.to, value, transitionState)
|
lastStep = nextStep
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun trace(info: TransitionInfo, transitionState: TransitionState) {
|
private fun trace(step: TransitionStep, isManual: Boolean) {
|
||||||
if (
|
if (
|
||||||
transitionState != TransitionState.STARTED &&
|
step.transitionState != TransitionState.STARTED &&
|
||||||
transitionState != TransitionState.FINISHED
|
step.transitionState != TransitionState.FINISHED
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val traceName =
|
val traceName =
|
||||||
"Transition: ${info.from} -> ${info.to} " +
|
"Transition: ${step.from} -> ${step.to} " +
|
||||||
if (info.animator == null) {
|
if (isManual) {
|
||||||
"(manual)"
|
"(manual)"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
val traceCookie = traceName.hashCode()
|
val traceCookie = traceName.hashCode()
|
||||||
if (transitionState == TransitionState.STARTED) {
|
if (step.transitionState == TransitionState.STARTED) {
|
||||||
Trace.beginAsyncSection(traceName, traceCookie)
|
Trace.beginAsyncSection(traceName, traceCookie)
|
||||||
} else if (transitionState == TransitionState.FINISHED) {
|
} else if (step.transitionState == TransitionState.FINISHED) {
|
||||||
Trace.endAsyncSection(traceName, traceCookie)
|
Trace.endAsyncSection(traceName, traceCookie)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ 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.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
|
||||||
@@ -36,12 +37,16 @@ constructor(
|
|||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
private val keyguardRepository: KeyguardRepository,
|
private val keyguardRepository: KeyguardRepository,
|
||||||
private val keyguardTransitionRepository: KeyguardTransitionRepository,
|
private val keyguardTransitionRepository: KeyguardTransitionRepository,
|
||||||
|
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
|
||||||
) : TransitionInteractor("AOD<->LOCKSCREEN") {
|
) : TransitionInteractor("AOD<->LOCKSCREEN") {
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
keyguardRepository.isDozing.collect { isDozing ->
|
keyguardRepository.isDozing
|
||||||
if (isDozing) {
|
.sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
|
||||||
|
.collect { pair ->
|
||||||
|
val (isDozing, keyguardState) = pair
|
||||||
|
if (isDozing && keyguardState == KeyguardState.LOCKSCREEN) {
|
||||||
keyguardTransitionRepository.startTransition(
|
keyguardTransitionRepository.startTransition(
|
||||||
TransitionInfo(
|
TransitionInfo(
|
||||||
name,
|
name,
|
||||||
@@ -50,7 +55,7 @@ constructor(
|
|||||||
getAnimator(),
|
getAnimator(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else if (!isDozing && keyguardState == KeyguardState.AOD) {
|
||||||
keyguardTransitionRepository.startTransition(
|
keyguardTransitionRepository.startTransition(
|
||||||
TransitionInfo(
|
TransitionInfo(
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -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
|
||||||
|
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 GoneAodTransitionInteractor
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
@Application private val scope: CoroutineScope,
|
||||||
|
private val keyguardInteractor: KeyguardInteractor,
|
||||||
|
private val keyguardTransitionRepository: KeyguardTransitionRepository,
|
||||||
|
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
|
||||||
|
) : TransitionInteractor("GONE->AOD") {
|
||||||
|
|
||||||
|
override fun start() {
|
||||||
|
scope.launch {
|
||||||
|
keyguardInteractor.wakefulnessState
|
||||||
|
.sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
|
||||||
|
.collect { pair ->
|
||||||
|
val (wakefulnessState, keyguardState) = pair
|
||||||
|
if (
|
||||||
|
keyguardState == KeyguardState.GONE &&
|
||||||
|
wakefulnessState == WakefulnessModel.STARTING_TO_SLEEP
|
||||||
|
) {
|
||||||
|
keyguardTransitionRepository.startTransition(
|
||||||
|
TransitionInfo(
|
||||||
|
name,
|
||||||
|
KeyguardState.GONE,
|
||||||
|
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 = 500L
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.domain.interactor
|
|||||||
|
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.keyguard.data.repository.KeyguardRepository
|
import com.android.systemui.keyguard.data.repository.KeyguardRepository
|
||||||
|
import com.android.systemui.keyguard.shared.model.WakefulnessModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@@ -40,6 +41,8 @@ constructor(
|
|||||||
val isDozing: Flow<Boolean> = repository.isDozing
|
val isDozing: Flow<Boolean> = repository.isDozing
|
||||||
/** Whether the keyguard is showing to not. */
|
/** Whether the keyguard is showing to not. */
|
||||||
val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
|
val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
|
||||||
|
/** The device wake/sleep state */
|
||||||
|
val wakefulnessState: Flow<WakefulnessModel> = repository.wakefulnessState
|
||||||
|
|
||||||
fun isKeyguardShowing(): Boolean {
|
fun isKeyguardShowing(): Boolean {
|
||||||
return repository.isKeyguardShowing()
|
return repository.isKeyguardShowing()
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.keyguard.logging.KeyguardLogger
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/** Collect flows of interest for auditing keyguard transitions. */
|
||||||
|
@SysUISingleton
|
||||||
|
class KeyguardTransitionAuditLogger
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
@Application private val scope: CoroutineScope,
|
||||||
|
private val interactor: KeyguardTransitionInteractor,
|
||||||
|
private val keyguardInteractor: KeyguardInteractor,
|
||||||
|
private val logger: KeyguardLogger,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun start() {
|
||||||
|
scope.launch {
|
||||||
|
keyguardInteractor.wakefulnessState.collect { logger.v("WakefulnessState", it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
interactor.finishedKeyguardState.collect { logger.i("Finished transition to", it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
interactor.startedKeyguardState.collect { logger.i("Started transition to", it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ class KeyguardTransitionCoreStartable
|
|||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val interactors: Set<TransitionInteractor>,
|
private val interactors: Set<TransitionInteractor>,
|
||||||
|
private val auditLogger: KeyguardTransitionAuditLogger,
|
||||||
) : CoreStartable {
|
) : CoreStartable {
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
@@ -38,9 +39,12 @@ constructor(
|
|||||||
when (it) {
|
when (it) {
|
||||||
is LockscreenBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
|
is LockscreenBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
|
||||||
is AodLockscreenTransitionInteractor -> Log.d(TAG, "Started $it")
|
is AodLockscreenTransitionInteractor -> Log.d(TAG, "Started $it")
|
||||||
|
is GoneAodTransitionInteractor -> Log.d(TAG, "Started $it")
|
||||||
|
is LockscreenGoneTransitionInteractor -> Log.d(TAG, "Started $it")
|
||||||
}
|
}
|
||||||
it.start()
|
it.start()
|
||||||
}
|
}
|
||||||
|
auditLogger.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -19,11 +19,15 @@ package com.android.systemui.keyguard.domain.interactor
|
|||||||
|
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.keyguard.data.repository.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.AOD
|
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
|
||||||
|
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
|
||||||
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.TransitionState
|
||||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
|
|
||||||
@@ -40,6 +44,9 @@ constructor(
|
|||||||
/** LOCKSCREEN->AOD transition information. */
|
/** LOCKSCREEN->AOD transition information. */
|
||||||
val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
|
val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
|
||||||
|
|
||||||
|
/** GONE->AOD information. */
|
||||||
|
val goneToAodTransition: Flow<TransitionStep> = repository.transition(GONE, AOD)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
|
* AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
|
||||||
* Lockscreen (0f).
|
* Lockscreen (0f).
|
||||||
@@ -49,4 +56,16 @@ constructor(
|
|||||||
aodToLockscreenTransition.map { step -> step.copy(value = 1f - step.value) },
|
aodToLockscreenTransition.map { step -> step.copy(value = 1f - step.value) },
|
||||||
lockscreenToAodTransition,
|
lockscreenToAodTransition,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/* The last completed [KeyguardState] transition */
|
||||||
|
val finishedKeyguardState: Flow<KeyguardState> =
|
||||||
|
repository.transitions
|
||||||
|
.filter { step -> step.transitionState == TransitionState.FINISHED }
|
||||||
|
.map { step -> step.to }
|
||||||
|
|
||||||
|
/* The last started [KeyguardState] transition */
|
||||||
|
val startedKeyguardState: Flow<KeyguardState> =
|
||||||
|
repository.transitions
|
||||||
|
.filter { step -> step.transitionState == TransitionState.STARTED }
|
||||||
|
.map { step -> step.to }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.android.systemui.util.kotlin.sample
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
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.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -40,21 +41,25 @@ constructor(
|
|||||||
private val keyguardRepository: KeyguardRepository,
|
private val keyguardRepository: KeyguardRepository,
|
||||||
private val shadeRepository: ShadeRepository,
|
private val shadeRepository: ShadeRepository,
|
||||||
private val keyguardTransitionRepository: KeyguardTransitionRepository,
|
private val keyguardTransitionRepository: KeyguardTransitionRepository,
|
||||||
|
private val keyguardTransitionInteractor: KeyguardTransitionInteractor
|
||||||
) : TransitionInteractor("LOCKSCREEN<->BOUNCER") {
|
) : TransitionInteractor("LOCKSCREEN<->BOUNCER") {
|
||||||
|
|
||||||
private var transitionId: UUID? = null
|
private var transitionId: UUID? = null
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
shadeRepository.shadeModel.sample(
|
shadeRepository.shadeModel
|
||||||
|
.sample(
|
||||||
combine(
|
combine(
|
||||||
keyguardTransitionRepository.transitions,
|
keyguardTransitionInteractor.finishedKeyguardState,
|
||||||
keyguardRepository.statusBarState,
|
keyguardRepository.statusBarState,
|
||||||
) { transitions, statusBarState ->
|
) { keyguardState, statusBarState ->
|
||||||
Pair(transitions, statusBarState)
|
Pair(keyguardState, statusBarState)
|
||||||
}
|
},
|
||||||
) { shadeModel, pair ->
|
{ shadeModel, pair -> Triple(shadeModel, pair.first, pair.second) }
|
||||||
val (transitions, statusBarState) = pair
|
)
|
||||||
|
.collect { triple ->
|
||||||
|
val (shadeModel, keyguardState, statusBarState) = triple
|
||||||
|
|
||||||
val id = transitionId
|
val id = transitionId
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
@@ -63,7 +68,9 @@ constructor(
|
|||||||
keyguardTransitionRepository.updateTransition(
|
keyguardTransitionRepository.updateTransition(
|
||||||
id,
|
id,
|
||||||
shadeModel.expansionAmount,
|
shadeModel.expansionAmount,
|
||||||
if (shadeModel.expansionAmount == 0f || shadeModel.expansionAmount == 1f) {
|
if (
|
||||||
|
shadeModel.expansionAmount == 0f || shadeModel.expansionAmount == 1f
|
||||||
|
) {
|
||||||
transitionId = null
|
transitionId = null
|
||||||
TransitionState.FINISHED
|
TransitionState.FINISHED
|
||||||
} else {
|
} else {
|
||||||
@@ -71,13 +78,11 @@ constructor(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// TODO (b/251849525): Remove statusbarstate check when that state is integrated
|
// TODO (b/251849525): Remove statusbarstate check when that state is
|
||||||
|
// integrated
|
||||||
// into KeyguardTransitionRepository
|
// into KeyguardTransitionRepository
|
||||||
val isOnLockscreen =
|
|
||||||
transitions.transitionState == TransitionState.FINISHED &&
|
|
||||||
transitions.to == KeyguardState.LOCKSCREEN
|
|
||||||
if (
|
if (
|
||||||
isOnLockscreen &&
|
keyguardState == KeyguardState.LOCKSCREEN &&
|
||||||
shadeModel.isUserDragging &&
|
shadeModel.isUserDragging &&
|
||||||
statusBarState != SHADE_LOCKED
|
statusBarState != SHADE_LOCKED
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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 javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@SysUISingleton
|
||||||
|
class LockscreenGoneTransitionInteractor
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
@Application private val scope: CoroutineScope,
|
||||||
|
private val keyguardInteractor: KeyguardInteractor,
|
||||||
|
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(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAnimator(): ValueAnimator {
|
||||||
|
return ValueAnimator().apply {
|
||||||
|
setInterpolator(Interpolators.LINEAR)
|
||||||
|
setDuration(TRANSITION_DURATION_MS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TRANSITION_DURATION_MS = 10L
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,4 +39,10 @@ abstract class StartKeyguardTransitionModule {
|
|||||||
@Binds
|
@Binds
|
||||||
@IntoSet
|
@IntoSet
|
||||||
abstract fun aodLockscreen(impl: AodLockscreenTransitionInteractor): TransitionInteractor
|
abstract fun aodLockscreen(impl: AodLockscreenTransitionInteractor): TransitionInteractor
|
||||||
|
|
||||||
|
@Binds @IntoSet abstract fun goneAod(impl: GoneAodTransitionInteractor): TransitionInteractor
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoSet
|
||||||
|
abstract fun lockscreenGone(impl: LockscreenGoneTransitionInteractor): TransitionInteractor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,10 @@ 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 only */
|
/**
|
||||||
|
* For initialization as well as when the security method is set to NONE, indicating that
|
||||||
|
* the keyguard should never be shown.
|
||||||
|
*/
|
||||||
NONE,
|
NONE,
|
||||||
/* Always-on Display. The device is in a low-power mode with a minimal UI visible */
|
/* Always-on Display. The device is in a low-power mode with a minimal UI visible */
|
||||||
AOD,
|
AOD,
|
||||||
@@ -31,4 +34,11 @@ 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
|
||||||
|
* is being removed, but there are other cases where the user is swiping away keyguard, such as
|
||||||
|
* with SWIPE security method or face unlock without bypass.
|
||||||
|
*/
|
||||||
|
GONE,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ 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 {
|
||||||
NONE,
|
|
||||||
STARTED,
|
STARTED,
|
||||||
RUNNING,
|
RUNNING,
|
||||||
FINISHED
|
FINISHED
|
||||||
|
|||||||
@@ -20,5 +20,11 @@ data class TransitionStep(
|
|||||||
val from: KeyguardState = KeyguardState.NONE,
|
val from: KeyguardState = KeyguardState.NONE,
|
||||||
val to: KeyguardState = KeyguardState.NONE,
|
val to: KeyguardState = KeyguardState.NONE,
|
||||||
val value: Float = 0f, // constrained [0.0, 1.0]
|
val value: Float = 0f, // constrained [0.0, 1.0]
|
||||||
val transitionState: TransitionState = TransitionState.NONE,
|
val transitionState: TransitionState = TransitionState.FINISHED,
|
||||||
)
|
) {
|
||||||
|
constructor(
|
||||||
|
info: TransitionInfo,
|
||||||
|
value: Float,
|
||||||
|
transitionState: TransitionState,
|
||||||
|
) : this(info.from, info.to, value, transitionState)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License
|
||||||
|
*/
|
||||||
|
package com.android.systemui.keyguard.shared.model
|
||||||
|
|
||||||
|
/** Model device wakefulness states. */
|
||||||
|
enum class WakefulnessModel {
|
||||||
|
/** The device is asleep and not interactive. */
|
||||||
|
ASLEEP,
|
||||||
|
/** Received a signal that the device is beginning to wake up. */
|
||||||
|
STARTING_TO_WAKE,
|
||||||
|
/** Device is now fully awake and interactive. */
|
||||||
|
AWAKE,
|
||||||
|
/** Signal that the device is now going to sleep. */
|
||||||
|
STARTING_TO_SLEEP,
|
||||||
|
}
|
||||||
@@ -20,6 +20,8 @@ import androidx.test.filters.SmallTest
|
|||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.common.shared.model.Position
|
import com.android.systemui.common.shared.model.Position
|
||||||
import com.android.systemui.doze.DozeHost
|
import com.android.systemui.doze.DozeHost
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle
|
||||||
|
import com.android.systemui.keyguard.shared.model.WakefulnessModel
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||||
import com.android.systemui.util.mockito.argumentCaptor
|
import com.android.systemui.util.mockito.argumentCaptor
|
||||||
@@ -43,6 +45,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var statusBarStateController: StatusBarStateController
|
@Mock private lateinit var statusBarStateController: StatusBarStateController
|
||||||
@Mock private lateinit var dozeHost: DozeHost
|
@Mock private lateinit var dozeHost: DozeHost
|
||||||
@Mock private lateinit var keyguardStateController: KeyguardStateController
|
@Mock private lateinit var keyguardStateController: KeyguardStateController
|
||||||
|
@Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
|
||||||
|
|
||||||
private lateinit var underTest: KeyguardRepositoryImpl
|
private lateinit var underTest: KeyguardRepositoryImpl
|
||||||
|
|
||||||
@@ -55,6 +58,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
|||||||
statusBarStateController,
|
statusBarStateController,
|
||||||
keyguardStateController,
|
keyguardStateController,
|
||||||
dozeHost,
|
dozeHost,
|
||||||
|
wakefulnessLifecycle,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,4 +188,33 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
verify(statusBarStateController).removeCallback(captor.value)
|
verify(statusBarStateController).removeCallback(captor.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wakefullness() = runBlockingTest {
|
||||||
|
val values = mutableListOf<WakefulnessModel>()
|
||||||
|
val job = underTest.wakefulnessState.onEach(values::add).launchIn(this)
|
||||||
|
|
||||||
|
val captor = argumentCaptor<WakefulnessLifecycle.Observer>()
|
||||||
|
verify(wakefulnessLifecycle).addObserver(captor.capture())
|
||||||
|
|
||||||
|
captor.value.onStartedWakingUp()
|
||||||
|
captor.value.onFinishedWakingUp()
|
||||||
|
captor.value.onStartedGoingToSleep()
|
||||||
|
captor.value.onFinishedGoingToSleep()
|
||||||
|
|
||||||
|
assertThat(values)
|
||||||
|
.isEqualTo(
|
||||||
|
listOf(
|
||||||
|
// Initial value will be ASLEEP
|
||||||
|
WakefulnessModel.ASLEEP,
|
||||||
|
WakefulnessModel.STARTING_TO_WAKE,
|
||||||
|
WakefulnessModel.AWAKE,
|
||||||
|
WakefulnessModel.STARTING_TO_SLEEP,
|
||||||
|
WakefulnessModel.ASLEEP,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
verify(wakefulnessLifecycle).removeObserver(captor.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
underTest = KeyguardTransitionRepository()
|
underTest = KeyguardTransitionRepositoryImpl()
|
||||||
wtfHandler = WtfHandler()
|
wtfHandler = WtfHandler()
|
||||||
oldWtfHandler = Log.setWtfHandler(wtfHandler)
|
oldWtfHandler = Log.setWtfHandler(wtfHandler)
|
||||||
}
|
}
|
||||||
@@ -174,9 +174,6 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun assertSteps(steps: List<TransitionStep>, fractions: List<BigDecimal>) {
|
private fun assertSteps(steps: List<TransitionStep>, fractions: List<BigDecimal>) {
|
||||||
// + 2 accounts for start and finish of automated transition
|
|
||||||
assertThat(steps.size).isEqualTo(fractions.size + 2)
|
|
||||||
|
|
||||||
assertThat(steps[0]).isEqualTo(TransitionStep(AOD, LOCKSCREEN, 0f, TransitionState.STARTED))
|
assertThat(steps[0]).isEqualTo(TransitionStep(AOD, LOCKSCREEN, 0f, TransitionState.STARTED))
|
||||||
fractions.forEachIndexed { index, fraction ->
|
fractions.forEachIndexed { index, fraction ->
|
||||||
assertThat(steps[index + 1])
|
assertThat(steps[index + 1])
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* 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 androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||||
|
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.GONE
|
||||||
|
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
class KeyguardTransitionInteractorTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
private lateinit var underTest: KeyguardTransitionInteractor
|
||||||
|
private lateinit var repository: FakeKeyguardTransitionRepository
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
repository = FakeKeyguardTransitionRepository()
|
||||||
|
underTest = KeyguardTransitionInteractor(repository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `transition collectors receives only appropriate events`() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
var goneToAodSteps = mutableListOf<TransitionStep>()
|
||||||
|
val job1 =
|
||||||
|
underTest.goneToAodTransition.onEach { goneToAodSteps.add(it) }.launchIn(this)
|
||||||
|
|
||||||
|
var aodToLockscreenSteps = mutableListOf<TransitionStep>()
|
||||||
|
val job2 =
|
||||||
|
underTest.aodToLockscreenTransition
|
||||||
|
.onEach { aodToLockscreenSteps.add(it) }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val steps = mutableListOf<TransitionStep>()
|
||||||
|
steps.add(TransitionStep(AOD, GONE, 0f, STARTED))
|
||||||
|
steps.add(TransitionStep(AOD, GONE, 1f, FINISHED))
|
||||||
|
steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
|
||||||
|
steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
|
||||||
|
steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
|
||||||
|
steps.add(TransitionStep(GONE, AOD, 0f, STARTED))
|
||||||
|
steps.add(TransitionStep(GONE, AOD, 0.1f, RUNNING))
|
||||||
|
steps.add(TransitionStep(GONE, AOD, 0.2f, RUNNING))
|
||||||
|
|
||||||
|
steps.forEach { repository.sendTransitionStep(it) }
|
||||||
|
|
||||||
|
assertThat(aodToLockscreenSteps).isEqualTo(steps.subList(2, 5))
|
||||||
|
assertThat(goneToAodSteps).isEqualTo(steps.subList(5, 8))
|
||||||
|
|
||||||
|
job1.cancel()
|
||||||
|
job2.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dozeAmountTransitionTest() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
var dozeAmountSteps = mutableListOf<TransitionStep>()
|
||||||
|
val job =
|
||||||
|
underTest.dozeAmountTransition.onEach { dozeAmountSteps.add(it) }.launchIn(this)
|
||||||
|
|
||||||
|
val steps = mutableListOf<TransitionStep>()
|
||||||
|
|
||||||
|
steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
|
||||||
|
steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
|
||||||
|
steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
|
||||||
|
steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
|
||||||
|
steps.add(TransitionStep(LOCKSCREEN, AOD, 0.8f, RUNNING))
|
||||||
|
steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING))
|
||||||
|
steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
|
||||||
|
|
||||||
|
steps.forEach { repository.sendTransitionStep(it) }
|
||||||
|
|
||||||
|
assertThat(dozeAmountSteps.subList(0, 3))
|
||||||
|
.isEqualTo(
|
||||||
|
listOf(
|
||||||
|
steps[0].copy(value = 1f - steps[0].value),
|
||||||
|
steps[1].copy(value = 1f - steps[1].value),
|
||||||
|
steps[2].copy(value = 1f - steps[2].value),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7))
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun keyguardStateTests() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
var finishedSteps = mutableListOf<KeyguardState>()
|
||||||
|
val job1 =
|
||||||
|
underTest.finishedKeyguardState.onEach { finishedSteps.add(it) }.launchIn(this)
|
||||||
|
var startedSteps = mutableListOf<KeyguardState>()
|
||||||
|
val job2 = underTest.startedKeyguardState.onEach { startedSteps.add(it) }.launchIn(this)
|
||||||
|
|
||||||
|
val steps = mutableListOf<TransitionStep>()
|
||||||
|
|
||||||
|
steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
|
||||||
|
steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
|
||||||
|
steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
|
||||||
|
steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
|
||||||
|
steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING))
|
||||||
|
steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
|
||||||
|
steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
|
||||||
|
|
||||||
|
steps.forEach { repository.sendTransitionStep(it) }
|
||||||
|
|
||||||
|
assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, AOD))
|
||||||
|
assertThat(startedSteps).isEqualTo(listOf(LOCKSCREEN, AOD, GONE))
|
||||||
|
|
||||||
|
job1.cancel()
|
||||||
|
job2.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ package com.android.systemui.keyguard.data.repository
|
|||||||
|
|
||||||
import com.android.systemui.common.shared.model.Position
|
import com.android.systemui.common.shared.model.Position
|
||||||
import com.android.systemui.keyguard.shared.model.StatusBarState
|
import com.android.systemui.keyguard.shared.model.StatusBarState
|
||||||
|
import com.android.systemui.keyguard.shared.model.WakefulnessModel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@@ -48,6 +49,9 @@ class FakeKeyguardRepository : KeyguardRepository {
|
|||||||
private val _statusBarState = MutableStateFlow(StatusBarState.SHADE)
|
private val _statusBarState = MutableStateFlow(StatusBarState.SHADE)
|
||||||
override val statusBarState: Flow<StatusBarState> = _statusBarState
|
override val statusBarState: Flow<StatusBarState> = _statusBarState
|
||||||
|
|
||||||
|
private val _wakefulnessState = MutableStateFlow(WakefulnessModel.ASLEEP)
|
||||||
|
override val wakefulnessState: Flow<WakefulnessModel> = _wakefulnessState
|
||||||
|
|
||||||
override fun isKeyguardShowing(): Boolean {
|
override fun isKeyguardShowing(): Boolean {
|
||||||
return _isKeyguardShowing.value
|
return _isKeyguardShowing.value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.data.repository
|
||||||
|
|
||||||
|
import android.annotation.FloatRange
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionInfo
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
|
||||||
|
/** Fake implementation of [KeyguardTransitionRepository] */
|
||||||
|
class FakeKeyguardTransitionRepository : KeyguardTransitionRepository {
|
||||||
|
|
||||||
|
private val _transitions = MutableSharedFlow<TransitionStep>()
|
||||||
|
override val transitions: SharedFlow<TransitionStep> = _transitions
|
||||||
|
|
||||||
|
suspend fun sendTransitionStep(step: TransitionStep) {
|
||||||
|
_transitions.emit(step)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startTransition(info: TransitionInfo): UUID? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateTransition(
|
||||||
|
transitionId: UUID,
|
||||||
|
@FloatRange(from = 0.0, to = 1.0) value: Float,
|
||||||
|
state: TransitionState
|
||||||
|
) = Unit
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user