Merge changes I72c43c93,I254d2130 into tm-qpr-dev am: 5f3bb10877 am: 04e01a73f0
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21142718 Change-Id: I98c06ffbaa763e86b1338fadede46b1f619676f9 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
|
||||
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.isWakingOrStartingToWake
|
||||
@@ -44,6 +45,7 @@ constructor(
|
||||
|
||||
override fun start() {
|
||||
listenForDozingToLockscreen()
|
||||
listenForDozingToGone()
|
||||
}
|
||||
|
||||
private fun listenForDozingToLockscreen() {
|
||||
@@ -68,6 +70,28 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun listenForDozingToGone() {
|
||||
scope.launch {
|
||||
keyguardInteractor.biometricUnlockState
|
||||
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
|
||||
.collect { (biometricUnlockState, lastStartedTransition) ->
|
||||
if (
|
||||
lastStartedTransition.to == KeyguardState.DOZING &&
|
||||
isWakeAndUnlock(biometricUnlockState)
|
||||
) {
|
||||
keyguardTransitionRepository.startTransition(
|
||||
TransitionInfo(
|
||||
name,
|
||||
KeyguardState.DOZING,
|
||||
KeyguardState.GONE,
|
||||
getAnimator(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
|
||||
return ValueAnimator().apply {
|
||||
setInterpolator(Interpolators.LINEAR)
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState.BOUNCER
|
||||
@@ -31,9 +30,6 @@ import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.time.Duration
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -104,38 +100,4 @@ constructor(
|
||||
/* The last completed [KeyguardState] transition */
|
||||
val finishedKeyguardState: Flow<KeyguardState> =
|
||||
finishedKeyguardTransitionStep.map { step -> step.to }
|
||||
|
||||
/**
|
||||
* Transitions will occur over a [totalDuration] with [TransitionStep]s being emitted in the
|
||||
* range of [0, 1]. View animations should begin and end within a subset of this range. This
|
||||
* function maps the [startTime] and [duration] into [0, 1], when this subset is valid.
|
||||
*/
|
||||
fun transitionStepAnimation(
|
||||
flow: Flow<TransitionStep>,
|
||||
params: AnimationParams,
|
||||
totalDuration: Duration,
|
||||
): Flow<Float> {
|
||||
val start = (params.startTime / totalDuration).toFloat()
|
||||
val chunks = (totalDuration / params.duration).toFloat()
|
||||
var isRunning = false
|
||||
return flow
|
||||
.map { step ->
|
||||
val value = (step.value - start) * chunks
|
||||
if (step.transitionState == STARTED) {
|
||||
// When starting, make sure to always emit. If a transition is started from the
|
||||
// middle, it is possible this animation is being skipped but we need to inform
|
||||
// the ViewModels of the last update
|
||||
isRunning = true
|
||||
max(0f, min(1f, value))
|
||||
} else if (isRunning && value >= 1f) {
|
||||
// Always send a final value of 1. Because of rounding, [value] may never be
|
||||
// exactly 1.
|
||||
isRunning = false
|
||||
1f
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
.filter { value -> value >= 0f && value <= 1f }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
package com.android.systemui.keyguard.shared.model
|
||||
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
/** Animation parameters */
|
||||
data class AnimationParams(
|
||||
val startTime: Duration = 0.milliseconds,
|
||||
val duration: Duration,
|
||||
)
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.ui
|
||||
|
||||
import android.view.animation.Interpolator
|
||||
import com.android.systemui.animation.Interpolators.LINEAR
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
|
||||
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 kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
* For the given transition params, construct a flow using [createFlow] for the specified portion of
|
||||
* the overall transition.
|
||||
*/
|
||||
class KeyguardTransitionAnimationFlow(
|
||||
private val transitionDuration: Duration,
|
||||
private val transitionFlow: Flow<TransitionStep>,
|
||||
) {
|
||||
/**
|
||||
* Transitions will occur over a [transitionDuration] with [TransitionStep]s being emitted in
|
||||
* the range of [0, 1]. View animations should begin and end within a subset of this range. This
|
||||
* function maps the [startTime] and [duration] into [0, 1], when this subset is valid.
|
||||
*/
|
||||
fun createFlow(
|
||||
duration: Duration,
|
||||
onStep: (Float) -> Float,
|
||||
startTime: Duration = 0.milliseconds,
|
||||
onCancel: (() -> Float)? = null,
|
||||
onFinish: (() -> Float)? = null,
|
||||
interpolator: Interpolator = LINEAR,
|
||||
): Flow<Float> {
|
||||
if (!duration.isPositive()) {
|
||||
throw IllegalArgumentException("duration must be a positive number: $duration")
|
||||
}
|
||||
if ((startTime + duration).compareTo(transitionDuration) > 0) {
|
||||
throw IllegalArgumentException(
|
||||
"startTime($startTime) + duration($duration) must be" +
|
||||
" <= transitionDuration($transitionDuration)"
|
||||
)
|
||||
}
|
||||
|
||||
val start = (startTime / transitionDuration).toFloat()
|
||||
val chunks = (transitionDuration / duration).toFloat()
|
||||
var isComplete = true
|
||||
|
||||
fun stepToValue(step: TransitionStep): Float? {
|
||||
val value = (step.value - start) * chunks
|
||||
return when (step.transitionState) {
|
||||
// When starting, make sure to always emit. If a transition is started from the
|
||||
// middle, it is possible this animation is being skipped but we need to inform
|
||||
// the ViewModels of the last update
|
||||
STARTED -> {
|
||||
isComplete = false
|
||||
max(0f, min(1f, value))
|
||||
}
|
||||
// Always send a final value of 1. Because of rounding, [value] may never be
|
||||
// exactly 1.
|
||||
RUNNING ->
|
||||
if (isComplete) {
|
||||
null
|
||||
} else if (value >= 1f) {
|
||||
isComplete = true
|
||||
1f
|
||||
} else if (value >= 0f) {
|
||||
value
|
||||
} else {
|
||||
null
|
||||
}
|
||||
else -> null
|
||||
}?.let { onStep(interpolator.getInterpolation(it)) }
|
||||
}
|
||||
|
||||
return transitionFlow
|
||||
.map { step ->
|
||||
when (step.transitionState) {
|
||||
STARTED -> stepToValue(step)
|
||||
RUNNING -> stepToValue(step)
|
||||
CANCELED -> onCancel?.invoke()
|
||||
FINISHED -> onFinish?.invoke()
|
||||
}
|
||||
}
|
||||
.filterNotNull()
|
||||
}
|
||||
}
|
||||
@@ -21,15 +21,10 @@ import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
|
||||
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
|
||||
/**
|
||||
* Breaks down DREAMING->LOCKSCREEN transition into discrete steps for corresponding views to
|
||||
@@ -41,39 +36,46 @@ class DreamingToLockscreenTransitionViewModel
|
||||
constructor(
|
||||
private val interactor: KeyguardTransitionInteractor,
|
||||
) {
|
||||
private val transitionAnimation =
|
||||
KeyguardTransitionAnimationFlow(
|
||||
transitionDuration = TO_LOCKSCREEN_DURATION,
|
||||
transitionFlow = interactor.dreamingToLockscreenTransition,
|
||||
)
|
||||
|
||||
/** Dream overlay y-translation on exit */
|
||||
fun dreamOverlayTranslationY(translatePx: Int): Flow<Float> {
|
||||
return flowForAnimation(DREAM_OVERLAY_TRANSLATION_Y).map { value ->
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(value) * translatePx
|
||||
}
|
||||
return transitionAnimation.createFlow(
|
||||
duration = 600.milliseconds,
|
||||
onStep = { it * translatePx },
|
||||
interpolator = EMPHASIZED_ACCELERATE,
|
||||
)
|
||||
}
|
||||
/** Dream overlay views alpha - fade out */
|
||||
val dreamOverlayAlpha: Flow<Float> = flowForAnimation(DREAM_OVERLAY_ALPHA).map { 1f - it }
|
||||
val dreamOverlayAlpha: Flow<Float> =
|
||||
transitionAnimation.createFlow(
|
||||
duration = 250.milliseconds,
|
||||
onStep = { 1f - it },
|
||||
)
|
||||
|
||||
/** Lockscreen views y-translation */
|
||||
fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
|
||||
return merge(
|
||||
flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
|
||||
-translatePx + (EMPHASIZED_DECELERATE.getInterpolation(value) * translatePx)
|
||||
},
|
||||
// On end, reset the translation to 0
|
||||
interactor.dreamingToLockscreenTransition
|
||||
.filter { it.transitionState == FINISHED || it.transitionState == CANCELED }
|
||||
.map { 0f }
|
||||
return transitionAnimation.createFlow(
|
||||
duration = TO_LOCKSCREEN_DURATION,
|
||||
onStep = { value -> -translatePx + value * translatePx },
|
||||
// Reset on cancel or finish
|
||||
onFinish = { 0f },
|
||||
onCancel = { 0f },
|
||||
interpolator = EMPHASIZED_DECELERATE,
|
||||
)
|
||||
}
|
||||
|
||||
/** Lockscreen views alpha */
|
||||
val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA)
|
||||
|
||||
private fun flowForAnimation(params: AnimationParams): Flow<Float> {
|
||||
return interactor.transitionStepAnimation(
|
||||
interactor.dreamingToLockscreenTransition,
|
||||
params,
|
||||
totalDuration = TO_LOCKSCREEN_DURATION
|
||||
val lockscreenAlpha: Flow<Float> =
|
||||
transitionAnimation.createFlow(
|
||||
startTime = 233.milliseconds,
|
||||
duration = 250.milliseconds,
|
||||
onStep = { it },
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/* Length of time before ending the dream activity, in order to start unoccluding */
|
||||
@@ -81,11 +83,5 @@ constructor(
|
||||
@JvmField
|
||||
val LOCKSCREEN_ANIMATION_DURATION_MS =
|
||||
(TO_LOCKSCREEN_DURATION - DREAM_ANIMATION_DURATION).inWholeMilliseconds
|
||||
|
||||
val DREAM_OVERLAY_TRANSLATION_Y = AnimationParams(duration = 600.milliseconds)
|
||||
val DREAM_OVERLAY_ALPHA = AnimationParams(duration = 250.milliseconds)
|
||||
val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = TO_LOCKSCREEN_DURATION)
|
||||
val LOCKSCREEN_ALPHA =
|
||||
AnimationParams(startTime = 233.milliseconds, duration = 250.milliseconds)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,10 @@ import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
|
||||
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
|
||||
/** Breaks down GONE->DREAMING transition into discrete steps for corresponding views to consume. */
|
||||
@SysUISingleton
|
||||
@@ -38,32 +33,28 @@ constructor(
|
||||
private val interactor: KeyguardTransitionInteractor,
|
||||
) {
|
||||
|
||||
private val transitionAnimation =
|
||||
KeyguardTransitionAnimationFlow(
|
||||
transitionDuration = TO_DREAMING_DURATION,
|
||||
transitionFlow = interactor.goneToDreamingTransition,
|
||||
)
|
||||
|
||||
/** Lockscreen views y-translation */
|
||||
fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
|
||||
return merge(
|
||||
flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
|
||||
(EMPHASIZED_ACCELERATE.getInterpolation(value) * translatePx)
|
||||
},
|
||||
// On end, reset the translation to 0
|
||||
interactor.goneToDreamingTransition
|
||||
.filter { it.transitionState == FINISHED || it.transitionState == CANCELED }
|
||||
.map { 0f }
|
||||
return transitionAnimation.createFlow(
|
||||
duration = 500.milliseconds,
|
||||
onStep = { it * translatePx },
|
||||
// Reset on cancel or finish
|
||||
onFinish = { 0f },
|
||||
onCancel = { 0f },
|
||||
interpolator = EMPHASIZED_ACCELERATE,
|
||||
)
|
||||
}
|
||||
|
||||
/** Lockscreen views alpha */
|
||||
val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA).map { 1f - it }
|
||||
|
||||
private fun flowForAnimation(params: AnimationParams): Flow<Float> {
|
||||
return interactor.transitionStepAnimation(
|
||||
interactor.goneToDreamingTransition,
|
||||
params,
|
||||
totalDuration = TO_DREAMING_DURATION
|
||||
val lockscreenAlpha: Flow<Float> =
|
||||
transitionAnimation.createFlow(
|
||||
duration = 250.milliseconds,
|
||||
onStep = { 1f - it },
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = 500.milliseconds)
|
||||
val LOCKSCREEN_ALPHA = AnimationParams(duration = 250.milliseconds)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,10 @@ import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
|
||||
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
|
||||
/**
|
||||
* Breaks down LOCKSCREEN->DREAMING transition into discrete steps for corresponding views to
|
||||
@@ -40,35 +35,32 @@ class LockscreenToDreamingTransitionViewModel
|
||||
constructor(
|
||||
private val interactor: KeyguardTransitionInteractor,
|
||||
) {
|
||||
private val transitionAnimation =
|
||||
KeyguardTransitionAnimationFlow(
|
||||
transitionDuration = TO_DREAMING_DURATION,
|
||||
transitionFlow = interactor.lockscreenToDreamingTransition,
|
||||
)
|
||||
|
||||
/** Lockscreen views y-translation */
|
||||
fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
|
||||
return merge(
|
||||
flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
|
||||
(EMPHASIZED_ACCELERATE.getInterpolation(value) * translatePx)
|
||||
},
|
||||
// On end, reset the translation to 0
|
||||
interactor.lockscreenToDreamingTransition
|
||||
.filter { it.transitionState == FINISHED || it.transitionState == CANCELED }
|
||||
.map { 0f }
|
||||
return transitionAnimation.createFlow(
|
||||
duration = 500.milliseconds,
|
||||
onStep = { it * translatePx },
|
||||
// Reset on cancel or finish
|
||||
onFinish = { 0f },
|
||||
onCancel = { 0f },
|
||||
interpolator = EMPHASIZED_ACCELERATE,
|
||||
)
|
||||
}
|
||||
|
||||
/** Lockscreen views alpha */
|
||||
val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA).map { 1f - it }
|
||||
|
||||
private fun flowForAnimation(params: AnimationParams): Flow<Float> {
|
||||
return interactor.transitionStepAnimation(
|
||||
interactor.lockscreenToDreamingTransition,
|
||||
params,
|
||||
totalDuration = TO_DREAMING_DURATION
|
||||
val lockscreenAlpha: Flow<Float> =
|
||||
transitionAnimation.createFlow(
|
||||
duration = 250.milliseconds,
|
||||
onStep = { 1f - it },
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField val DREAMING_ANIMATION_DURATION_MS = TO_DREAMING_DURATION.inWholeMilliseconds
|
||||
|
||||
val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = 500.milliseconds)
|
||||
val LOCKSCREEN_ALPHA = AnimationParams(duration = 250.milliseconds)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,10 @@ import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
|
||||
/**
|
||||
* Breaks down LOCKSCREEN->OCCLUDED transition into discrete steps for corresponding views to
|
||||
@@ -39,33 +35,28 @@ class LockscreenToOccludedTransitionViewModel
|
||||
constructor(
|
||||
private val interactor: KeyguardTransitionInteractor,
|
||||
) {
|
||||
private val transitionAnimation =
|
||||
KeyguardTransitionAnimationFlow(
|
||||
transitionDuration = TO_OCCLUDED_DURATION,
|
||||
transitionFlow = interactor.lockscreenToOccludedTransition,
|
||||
)
|
||||
|
||||
/** Lockscreen views alpha */
|
||||
val lockscreenAlpha: Flow<Float> =
|
||||
transitionAnimation.createFlow(
|
||||
duration = 250.milliseconds,
|
||||
onStep = { 1f - it },
|
||||
)
|
||||
|
||||
/** Lockscreen views y-translation */
|
||||
fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
|
||||
return merge(
|
||||
flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
|
||||
(EMPHASIZED_ACCELERATE.getInterpolation(value) * translatePx)
|
||||
},
|
||||
// On end, reset the translation to 0
|
||||
interactor.lockscreenToOccludedTransition
|
||||
.filter { step -> step.transitionState == TransitionState.FINISHED }
|
||||
.map { 0f }
|
||||
return transitionAnimation.createFlow(
|
||||
duration = TO_OCCLUDED_DURATION,
|
||||
onStep = { value -> value * translatePx },
|
||||
// Reset on cancel or finish
|
||||
onFinish = { 0f },
|
||||
onCancel = { 0f },
|
||||
interpolator = EMPHASIZED_ACCELERATE,
|
||||
)
|
||||
}
|
||||
|
||||
/** Lockscreen views alpha */
|
||||
val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA).map { 1f - it }
|
||||
|
||||
private fun flowForAnimation(params: AnimationParams): Flow<Float> {
|
||||
return interactor.transitionStepAnimation(
|
||||
interactor.lockscreenToOccludedTransition,
|
||||
params,
|
||||
totalDuration = TO_OCCLUDED_DURATION
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = TO_OCCLUDED_DURATION)
|
||||
val LOCKSCREEN_ALPHA = AnimationParams(duration = 250.milliseconds)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,10 @@ import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
* Breaks down OCCLUDED->LOCKSCREEN transition into discrete steps for corresponding views to
|
||||
@@ -36,28 +35,26 @@ class OccludedToLockscreenTransitionViewModel
|
||||
constructor(
|
||||
private val interactor: KeyguardTransitionInteractor,
|
||||
) {
|
||||
private val transitionAnimation =
|
||||
KeyguardTransitionAnimationFlow(
|
||||
transitionDuration = TO_LOCKSCREEN_DURATION,
|
||||
transitionFlow = interactor.occludedToLockscreenTransition,
|
||||
)
|
||||
|
||||
/** Lockscreen views y-translation */
|
||||
fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
|
||||
return flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
|
||||
-translatePx + (EMPHASIZED_DECELERATE.getInterpolation(value) * translatePx)
|
||||
}
|
||||
}
|
||||
|
||||
/** Lockscreen views alpha */
|
||||
val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA)
|
||||
|
||||
private fun flowForAnimation(params: AnimationParams): Flow<Float> {
|
||||
return interactor.transitionStepAnimation(
|
||||
interactor.occludedToLockscreenTransition,
|
||||
params,
|
||||
totalDuration = TO_LOCKSCREEN_DURATION
|
||||
return transitionAnimation.createFlow(
|
||||
duration = TO_LOCKSCREEN_DURATION,
|
||||
onStep = { value -> -translatePx + value * translatePx },
|
||||
interpolator = EMPHASIZED_DECELERATE,
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField val LOCKSCREEN_ANIMATION_DURATION_MS = TO_LOCKSCREEN_DURATION.inWholeMilliseconds
|
||||
val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = TO_LOCKSCREEN_DURATION)
|
||||
val LOCKSCREEN_ALPHA =
|
||||
AnimationParams(startTime = 233.milliseconds, duration = 250.milliseconds)
|
||||
}
|
||||
/** Lockscreen views alpha */
|
||||
val lockscreenAlpha: Flow<Float> =
|
||||
transitionAnimation.createFlow(
|
||||
startTime = 233.milliseconds,
|
||||
duration = 250.milliseconds,
|
||||
onStep = { it },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositoryImpl
|
||||
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
|
||||
import com.android.systemui.keyguard.shared.model.DozeStateModel
|
||||
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
@@ -436,6 +437,43 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `DOZING to GONE`() =
|
||||
testScope.runTest {
|
||||
// GIVEN a prior transition has run to DOZING
|
||||
runner.startTransition(
|
||||
testScope,
|
||||
TransitionInfo(
|
||||
ownerName = "",
|
||||
from = KeyguardState.LOCKSCREEN,
|
||||
to = KeyguardState.DOZING,
|
||||
animator =
|
||||
ValueAnimator().apply {
|
||||
duration = 10
|
||||
interpolator = Interpolators.LINEAR
|
||||
},
|
||||
)
|
||||
)
|
||||
runCurrent()
|
||||
reset(mockTransitionRepository)
|
||||
|
||||
// WHEN biometrics succeeds with wake and unlock mode
|
||||
keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
|
||||
runCurrent()
|
||||
|
||||
val info =
|
||||
withArgCaptor<TransitionInfo> {
|
||||
verify(mockTransitionRepository).startTransition(capture())
|
||||
}
|
||||
// THEN a transition to DOZING should occur
|
||||
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
|
||||
assertThat(info.from).isEqualTo(KeyguardState.DOZING)
|
||||
assertThat(info.to).isEqualTo(KeyguardState.GONE)
|
||||
assertThat(info.animator).isNotNull()
|
||||
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GONE to DOZING`() =
|
||||
testScope.runTest {
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.ui
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
|
||||
@SmallTest
|
||||
@RunWith(JUnit4::class)
|
||||
class KeyguardTransitionAnimationFlowTest : SysuiTestCase() {
|
||||
private lateinit var underTest: KeyguardTransitionAnimationFlow
|
||||
private lateinit var repository: FakeKeyguardTransitionRepository
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
repository = FakeKeyguardTransitionRepository()
|
||||
underTest =
|
||||
KeyguardTransitionAnimationFlow(
|
||||
1000.milliseconds,
|
||||
repository.transitions,
|
||||
)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun zeroDurationThrowsException() = runTest {
|
||||
val flow = underTest.createFlow(duration = 0.milliseconds, onStep = { it })
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun startTimePlusDurationGreaterThanTransitionDurationThrowsException() = runTest {
|
||||
val flow =
|
||||
underTest.createFlow(
|
||||
startTime = 300.milliseconds,
|
||||
duration = 800.milliseconds,
|
||||
onStep = { it }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFinishRunsWhenSpecified() = runTest {
|
||||
val flow =
|
||||
underTest.createFlow(
|
||||
duration = 100.milliseconds,
|
||||
onStep = { it },
|
||||
onFinish = { 10f },
|
||||
)
|
||||
var animationValues = collectLastValue(flow)
|
||||
repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
|
||||
assertThat(animationValues()).isEqualTo(10f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onCancelRunsWhenSpecified() = runTest {
|
||||
val flow =
|
||||
underTest.createFlow(
|
||||
duration = 100.milliseconds,
|
||||
onStep = { it },
|
||||
onCancel = { 100f },
|
||||
)
|
||||
var animationValues = collectLastValue(flow)
|
||||
repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED))
|
||||
assertThat(animationValues()).isEqualTo(100f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun usesStartTime() = runTest {
|
||||
val flow =
|
||||
underTest.createFlow(
|
||||
startTime = 500.milliseconds,
|
||||
duration = 500.milliseconds,
|
||||
onStep = { it },
|
||||
)
|
||||
var animationValues = collectLastValue(flow)
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
assertThat(animationValues()).isEqualTo(0f)
|
||||
|
||||
// Should not emit a value
|
||||
repository.sendTransitionStep(step(0.1f, TransitionState.RUNNING))
|
||||
|
||||
repository.sendTransitionStep(step(0.5f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), 0f)
|
||||
repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), 0.2f)
|
||||
repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), 0.6f)
|
||||
repository.sendTransitionStep(step(1f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), 1f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun usesInterpolator() = runTest {
|
||||
val flow =
|
||||
underTest.createFlow(
|
||||
duration = 1000.milliseconds,
|
||||
interpolator = EMPHASIZED_ACCELERATE,
|
||||
onStep = { it },
|
||||
)
|
||||
var animationValues = collectLastValue(flow)
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0f))
|
||||
repository.sendTransitionStep(step(0.5f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0.5f))
|
||||
repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0.6f))
|
||||
repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0.8f))
|
||||
repository.sendTransitionStep(step(1f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(1f))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun usesOnStepToDoubleValue() = runTest {
|
||||
val flow =
|
||||
underTest.createFlow(
|
||||
duration = 1000.milliseconds,
|
||||
onStep = { it * 2 },
|
||||
)
|
||||
var animationValues = collectLastValue(flow)
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
assertFloat(animationValues(), 0f)
|
||||
repository.sendTransitionStep(step(0.3f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), 0.6f)
|
||||
repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), 1.2f)
|
||||
repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), 1.6f)
|
||||
repository.sendTransitionStep(step(1f, TransitionState.RUNNING))
|
||||
assertFloat(animationValues(), 2f)
|
||||
}
|
||||
|
||||
private fun assertFloat(actual: Float?, expected: Float) {
|
||||
assertThat(actual!!).isWithin(0.01f).of(expected)
|
||||
}
|
||||
|
||||
private fun step(
|
||||
value: Float,
|
||||
state: TransitionState = TransitionState.RUNNING
|
||||
): TransitionStep {
|
||||
return TransitionStep(
|
||||
from = KeyguardState.GONE,
|
||||
to = KeyguardState.DREAMING,
|
||||
value = value,
|
||||
transitionState = state,
|
||||
ownerName = "GoneToDreamingTransitionViewModelTest"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -18,19 +18,13 @@ package com.android.systemui.keyguard.ui.viewmodel
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
|
||||
import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.Companion.DREAM_OVERLAY_ALPHA
|
||||
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.Companion.DREAM_OVERLAY_TRANSLATION_Y
|
||||
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.Companion.LOCKSCREEN_ALPHA
|
||||
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
|
||||
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
|
||||
import com.google.common.collect.Range
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -46,6 +40,7 @@ import org.junit.runners.JUnit4
|
||||
class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
|
||||
private lateinit var underTest: DreamingToLockscreenTransitionViewModel
|
||||
private lateinit var repository: FakeKeyguardTransitionRepository
|
||||
private lateinit var transitionAnimation: KeyguardTransitionAnimationFlow
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
@@ -63,32 +58,18 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
|
||||
val job =
|
||||
underTest.dreamOverlayTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
repository.sendTransitionStep(step(0.5f))
|
||||
repository.sendTransitionStep(step(0.6f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(0.8f))
|
||||
repository.sendTransitionStep(step(1f))
|
||||
|
||||
// Only 3 values should be present, since the dream overlay runs for a small fraction
|
||||
// of the overall animation time
|
||||
assertThat(values.size).isEqualTo(3)
|
||||
assertThat(values[0])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0f, DREAM_OVERLAY_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[1])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0.3f, DREAM_OVERLAY_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[2])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0.5f, DREAM_OVERLAY_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values.size).isEqualTo(5)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -100,16 +81,18 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
|
||||
|
||||
val job = underTest.dreamOverlayAlpha.onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.1f))
|
||||
repository.sendTransitionStep(step(0.5f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(1f))
|
||||
|
||||
// Only two values should be present, since the dream overlay runs for a small fraction
|
||||
// of the overall animation time
|
||||
assertThat(values.size).isEqualTo(2)
|
||||
assertThat(values[0]).isEqualTo(1f - animValue(0f, DREAM_OVERLAY_ALPHA))
|
||||
assertThat(values[1]).isEqualTo(1f - animValue(0.1f, DREAM_OVERLAY_ALPHA))
|
||||
assertThat(values.size).isEqualTo(4)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -121,19 +104,15 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
|
||||
|
||||
val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.1f))
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0.2f))
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(1f))
|
||||
|
||||
// Only two values should be present, since the dream overlay runs for a small fraction
|
||||
// of the overall animation time
|
||||
assertThat(values.size).isEqualTo(2)
|
||||
assertThat(values[0]).isEqualTo(animValue(0.2f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values[1]).isEqualTo(animValue(0.3f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values.size).isEqualTo(4)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -147,58 +126,27 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
|
||||
val job =
|
||||
underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
repository.sendTransitionStep(step(0.5f))
|
||||
repository.sendTransitionStep(step(1f))
|
||||
|
||||
assertThat(values.size).isEqualTo(4)
|
||||
assertThat(values[0])
|
||||
.isEqualTo(
|
||||
-pixels +
|
||||
EMPHASIZED_DECELERATE.getInterpolation(
|
||||
animValue(0f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[1])
|
||||
.isEqualTo(
|
||||
-pixels +
|
||||
EMPHASIZED_DECELERATE.getInterpolation(
|
||||
animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[2])
|
||||
.isEqualTo(
|
||||
-pixels +
|
||||
EMPHASIZED_DECELERATE.getInterpolation(
|
||||
animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[3])
|
||||
.isEqualTo(
|
||||
-pixels +
|
||||
EMPHASIZED_DECELERATE.getInterpolation(
|
||||
animValue(1f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values.size).isEqualTo(5)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun animValue(stepValue: Float, params: AnimationParams): Float {
|
||||
val totalDuration = TO_LOCKSCREEN_DURATION
|
||||
val startValue = (params.startTime / totalDuration).toFloat()
|
||||
|
||||
val multiplier = (totalDuration / params.duration).toFloat()
|
||||
return (stepValue - startValue) * multiplier
|
||||
}
|
||||
|
||||
private fun step(value: Float): TransitionStep {
|
||||
private fun step(
|
||||
value: Float,
|
||||
state: TransitionState = TransitionState.RUNNING
|
||||
): TransitionStep {
|
||||
return TransitionStep(
|
||||
from = KeyguardState.DREAMING,
|
||||
to = KeyguardState.LOCKSCREEN,
|
||||
value = value,
|
||||
transitionState = TransitionState.RUNNING,
|
||||
transitionState = state,
|
||||
ownerName = "DreamingToLockscreenTransitionViewModelTest"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,16 +18,12 @@ package com.android.systemui.keyguard.ui.viewmodel
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||
import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel.Companion.LOCKSCREEN_ALPHA
|
||||
import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
|
||||
import com.google.common.collect.Range
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -59,20 +55,18 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() {
|
||||
val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.1f))
|
||||
repository.sendTransitionStep(step(0.2f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(1f))
|
||||
|
||||
// Only three values should be present, since the dream overlay runs for a small
|
||||
// fraction
|
||||
// of the overall animation time
|
||||
assertThat(values.size).isEqualTo(3)
|
||||
assertThat(values[0]).isEqualTo(1f - animValue(0f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values[1]).isEqualTo(1f - animValue(0.1f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values[2]).isEqualTo(1f - animValue(0.2f, LOCKSCREEN_ALPHA))
|
||||
// fraction of the overall animation time
|
||||
assertThat(values.size).isEqualTo(5)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -87,45 +81,19 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() {
|
||||
underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
repository.sendTransitionStep(step(0.5f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(1f))
|
||||
// And a final reset event on CANCEL
|
||||
repository.sendTransitionStep(step(0.8f, TransitionState.CANCELED))
|
||||
|
||||
assertThat(values.size).isEqualTo(4)
|
||||
assertThat(values[0])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[1])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[2])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[3]).isEqualTo(0f)
|
||||
assertThat(values.size).isEqualTo(5)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun animValue(stepValue: Float, params: AnimationParams): Float {
|
||||
val totalDuration = TO_DREAMING_DURATION
|
||||
val startValue = (params.startTime / totalDuration).toFloat()
|
||||
|
||||
val multiplier = (totalDuration / params.duration).toFloat()
|
||||
return (stepValue - startValue) * multiplier
|
||||
}
|
||||
|
||||
private fun step(
|
||||
value: Float,
|
||||
state: TransitionState = TransitionState.RUNNING
|
||||
|
||||
@@ -18,16 +18,12 @@ package com.android.systemui.keyguard.ui.viewmodel
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.Companion.LOCKSCREEN_ALPHA
|
||||
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
|
||||
import com.google.common.collect.Range
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -59,19 +55,18 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
|
||||
val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.1f))
|
||||
repository.sendTransitionStep(step(0.2f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(1f))
|
||||
|
||||
// Only three values should be present, since the dream overlay runs for a small
|
||||
// fraction of the overall animation time
|
||||
assertThat(values.size).isEqualTo(3)
|
||||
assertThat(values[0]).isEqualTo(1f - animValue(0f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values[1]).isEqualTo(1f - animValue(0.1f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values[2]).isEqualTo(1f - animValue(0.2f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values.size).isEqualTo(5)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -85,47 +80,22 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
|
||||
val job =
|
||||
underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
repository.sendTransitionStep(step(0.5f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(1f))
|
||||
// And a final reset event on FINISHED
|
||||
repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
|
||||
|
||||
assertThat(values.size).isEqualTo(4)
|
||||
assertThat(values[0])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[1])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[2])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[3]).isEqualTo(0f)
|
||||
assertThat(values.size).isEqualTo(6)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
|
||||
// Validate finished value
|
||||
assertThat(values[5]).isEqualTo(0f)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun animValue(stepValue: Float, params: AnimationParams): Float {
|
||||
val totalDuration = TO_DREAMING_DURATION
|
||||
val startValue = (params.startTime / totalDuration).toFloat()
|
||||
|
||||
val multiplier = (totalDuration / params.duration).toFloat()
|
||||
return (stepValue - startValue) * multiplier
|
||||
}
|
||||
|
||||
private fun step(
|
||||
value: Float,
|
||||
state: TransitionState = TransitionState.RUNNING
|
||||
|
||||
@@ -18,16 +18,12 @@ package com.android.systemui.keyguard.ui.viewmodel
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel.Companion.LOCKSCREEN_ALPHA
|
||||
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
|
||||
import com.google.common.collect.Range
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -59,19 +55,18 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
|
||||
val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.1f))
|
||||
repository.sendTransitionStep(step(0.4f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(0.7f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(1f))
|
||||
|
||||
// Only 3 values should be present, since the dream overlay runs for a small fraction
|
||||
// of the overall animation time
|
||||
assertThat(values.size).isEqualTo(3)
|
||||
assertThat(values[0]).isEqualTo(1f - animValue(0f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values[1]).isEqualTo(1f - animValue(0.1f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values[2]).isEqualTo(1f - animValue(0.4f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values.size).isEqualTo(5)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -86,54 +81,51 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
|
||||
underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
repository.sendTransitionStep(step(0.5f))
|
||||
repository.sendTransitionStep(step(1f))
|
||||
// ...up to here
|
||||
|
||||
assertThat(values.size).isEqualTo(4)
|
||||
assertThat(values[0])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[1])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[2])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[3])
|
||||
.isEqualTo(
|
||||
EMPHASIZED_ACCELERATE.getInterpolation(
|
||||
animValue(1f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values.size).isEqualTo(5)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun animValue(stepValue: Float, params: AnimationParams): Float {
|
||||
val totalDuration = TO_OCCLUDED_DURATION
|
||||
val startValue = (params.startTime / totalDuration).toFloat()
|
||||
@Test
|
||||
fun lockscreenTranslationYIsCanceled() =
|
||||
runTest(UnconfinedTestDispatcher()) {
|
||||
val values = mutableListOf<Float>()
|
||||
|
||||
val multiplier = (totalDuration / params.duration).toFloat()
|
||||
return (stepValue - startValue) * multiplier
|
||||
}
|
||||
val pixels = 100
|
||||
val job =
|
||||
underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
private fun step(value: Float): TransitionStep {
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
repository.sendTransitionStep(step(0.3f, TransitionState.CANCELED))
|
||||
|
||||
assertThat(values.size).isEqualTo(4)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
|
||||
|
||||
// Cancel will reset the translation
|
||||
assertThat(values[3]).isEqualTo(0)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun step(
|
||||
value: Float,
|
||||
state: TransitionState = TransitionState.RUNNING,
|
||||
): TransitionStep {
|
||||
return TransitionStep(
|
||||
from = KeyguardState.LOCKSCREEN,
|
||||
to = KeyguardState.OCCLUDED,
|
||||
value = value,
|
||||
transitionState = TransitionState.RUNNING,
|
||||
transitionState = state,
|
||||
ownerName = "LockscreenToOccludedTransitionViewModelTest"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,16 +18,12 @@ package com.android.systemui.keyguard.ui.viewmodel
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.AnimationParams
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel.Companion.LOCKSCREEN_ALPHA
|
||||
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
|
||||
import com.google.common.collect.Range
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -58,21 +54,19 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {
|
||||
|
||||
val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0.1f))
|
||||
// Should start running here...
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
repository.sendTransitionStep(step(0.4f))
|
||||
repository.sendTransitionStep(step(0.5f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(0.6f))
|
||||
// ...up to here
|
||||
repository.sendTransitionStep(step(0.8f))
|
||||
repository.sendTransitionStep(step(1f))
|
||||
|
||||
// Only two values should be present, since the dream overlay runs for a small fraction
|
||||
// of the overall animation time
|
||||
assertThat(values.size).isEqualTo(3)
|
||||
assertThat(values[0]).isEqualTo(animValue(0.3f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values[1]).isEqualTo(animValue(0.4f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values[2]).isEqualTo(animValue(0.5f, LOCKSCREEN_ALPHA))
|
||||
assertThat(values.size).isEqualTo(5)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -86,58 +80,27 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {
|
||||
val job =
|
||||
underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
|
||||
|
||||
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
|
||||
repository.sendTransitionStep(step(0f))
|
||||
repository.sendTransitionStep(step(0.3f))
|
||||
repository.sendTransitionStep(step(0.5f))
|
||||
repository.sendTransitionStep(step(1f))
|
||||
|
||||
assertThat(values.size).isEqualTo(4)
|
||||
assertThat(values[0])
|
||||
.isEqualTo(
|
||||
-pixels +
|
||||
EMPHASIZED_DECELERATE.getInterpolation(
|
||||
animValue(0f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[1])
|
||||
.isEqualTo(
|
||||
-pixels +
|
||||
EMPHASIZED_DECELERATE.getInterpolation(
|
||||
animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[2])
|
||||
.isEqualTo(
|
||||
-pixels +
|
||||
EMPHASIZED_DECELERATE.getInterpolation(
|
||||
animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values[3])
|
||||
.isEqualTo(
|
||||
-pixels +
|
||||
EMPHASIZED_DECELERATE.getInterpolation(
|
||||
animValue(1f, LOCKSCREEN_TRANSLATION_Y)
|
||||
) * pixels
|
||||
)
|
||||
assertThat(values.size).isEqualTo(5)
|
||||
values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) }
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun animValue(stepValue: Float, params: AnimationParams): Float {
|
||||
val totalDuration = TO_LOCKSCREEN_DURATION
|
||||
val startValue = (params.startTime / totalDuration).toFloat()
|
||||
|
||||
val multiplier = (totalDuration / params.duration).toFloat()
|
||||
return (stepValue - startValue) * multiplier
|
||||
}
|
||||
|
||||
private fun step(value: Float): TransitionStep {
|
||||
private fun step(
|
||||
value: Float,
|
||||
state: TransitionState = TransitionState.RUNNING
|
||||
): TransitionStep {
|
||||
return TransitionStep(
|
||||
from = KeyguardState.OCCLUDED,
|
||||
to = KeyguardState.LOCKSCREEN,
|
||||
value = value,
|
||||
transitionState = TransitionState.RUNNING,
|
||||
transitionState = state,
|
||||
ownerName = "OccludedToLockscreenTransitionViewModelTest"
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user