summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt63
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt144
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java7
8 files changed, 282 insertions, 17 deletions
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f37d22146b25..584823746662 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1275,6 +1275,9 @@
<!-- DREAMING -> LOCKSCREEN transition: Amount to shift lockscreen content on entering -->
<dimen name="dreaming_to_lockscreen_transition_lockscreen_translation_y">40dp</dimen>
+ <!-- OCCLUDED -> LOCKSCREEN transition: Amount to shift lockscreen content on entering -->
+ <dimen name="occluded_to_lockscreen_transition_lockscreen_translation_y">40dp</dimen>
+
<!-- The amount of vertical offset for the keyguard during the full shade transition. -->
<dimen name="lockscreen_shade_keyguard_transition_vertical_offset">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 937e8ffd9f61..88789019b10f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -80,7 +80,7 @@ constructor(
name,
KeyguardState.OCCLUDED,
KeyguardState.LOCKSCREEN,
- getAnimator(),
+ getAnimator(TO_LOCKSCREEN_DURATION),
)
)
}
@@ -97,6 +97,6 @@ constructor(
companion object {
private val DEFAULT_DURATION = 500.milliseconds
- val TO_LOCKSCREEN_DURATION = 1183.milliseconds
+ val TO_LOCKSCREEN_DURATION = 933.milliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 3b9d6f59a8e7..04024be571c8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -24,7 +24,9 @@ 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.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
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.time.Duration
@@ -50,6 +52,10 @@ constructor(
val dreamingToLockscreenTransition: Flow<TransitionStep> =
repository.transition(DREAMING, LOCKSCREEN)
+ /** OCCLUDED->LOCKSCREEN transition information. */
+ val occludedToLockscreenTransition: Flow<TransitionStep> =
+ repository.transition(OCCLUDED, LOCKSCREEN)
+
/** (any)->AOD transition information */
val anyStateToAodTransition: Flow<TransitionStep> =
repository.transitions.filter { step -> step.to == KeyguardState.AOD }
@@ -93,7 +99,14 @@ constructor(
val start = (params.startTime / totalDuration).toFloat()
val chunks = (totalDuration / params.duration).toFloat()
return flow
- .map { step -> (step.value - start) * chunks }
+ // When starting, emit a value of 0f to give animations a chance to set initial state
+ .map { step ->
+ if (step.transitionState == STARTED) {
+ 0f
+ } else {
+ (step.value - start) * chunks
+ }
+ }
.filter { value -> value >= 0f && value <= 1f }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
new file mode 100644
index 000000000000..e804562bc85f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.ui.viewmodel
+
+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 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
+ * consume.
+ */
+@SysUISingleton
+class OccludedToLockscreenTransitionViewModel
+@Inject
+constructor(
+ private val interactor: KeyguardTransitionInteractor,
+) {
+ /** 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
+ )
+ }
+
+ 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)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 8054f27029ae..fe9b73315e72 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -144,6 +144,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.media.controls.ui.MediaHierarchyManager;
@@ -238,6 +239,8 @@ import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Provider;
+import kotlinx.coroutines.CoroutineDispatcher;
+
@CentralSurfacesComponent.CentralSurfacesScope
public final class NotificationPanelViewController implements Dumpable {
@@ -683,10 +686,13 @@ public final class NotificationPanelViewController implements Dumpable {
private boolean mIgnoreXTouchSlop;
private boolean mExpandLatencyTracking;
private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
+ private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
- private boolean mIsDreamToLockscreenTransitionRunning = false;
+ private CoroutineDispatcher mMainDispatcher;
+ private boolean mIsToLockscreenTransitionRunning = false;
private int mDreamingToLockscreenTransitionTranslationY;
+ private int mOccludedToLockscreenTransitionTranslationY;
private boolean mUnocclusionTransitionFlagEnabled = false;
private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
@@ -705,7 +711,13 @@ public final class NotificationPanelViewController implements Dumpable {
private final Consumer<TransitionStep> mDreamingToLockscreenTransition =
(TransitionStep step) -> {
- mIsDreamToLockscreenTransitionRunning =
+ mIsToLockscreenTransitionRunning =
+ step.getTransitionState() == TransitionState.RUNNING;
+ };
+
+ private final Consumer<TransitionStep> mOccludedToLockscreenTransition =
+ (TransitionStep step) -> {
+ mIsToLockscreenTransitionRunning =
step.getTransitionState() == TransitionState.RUNNING;
};
@@ -778,6 +790,8 @@ public final class NotificationPanelViewController implements Dumpable {
KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
KeyguardBottomAreaInteractor keyguardBottomAreaInteractor,
DreamingToLockscreenTransitionViewModel dreamingToLockscreenTransitionViewModel,
+ OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel,
+ @Main CoroutineDispatcher mainDispatcher,
KeyguardTransitionInteractor keyguardTransitionInteractor,
DumpManager dumpManager) {
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@@ -795,6 +809,7 @@ public final class NotificationPanelViewController implements Dumpable {
mShadeHeightLogger = shadeHeightLogger;
mGutsManager = gutsManager;
mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel;
+ mOccludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
@@ -873,6 +888,7 @@ public final class NotificationPanelViewController implements Dumpable {
mFalsingCollector = falsingCollector;
mPowerManager = powerManager;
mWakeUpCoordinator = coordinator;
+ mMainDispatcher = mainDispatcher;
mAccessibilityManager = accessibilityManager;
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
setPanelAlpha(255, false /* animate */);
@@ -1097,15 +1113,27 @@ public final class NotificationPanelViewController implements Dumpable {
controller.setup(mNotificationContainerParent));
if (mUnocclusionTransitionFlagEnabled) {
+ // Dreaming->Lockscreen
+ collectFlow(mView, mKeyguardTransitionInteractor.getDreamingToLockscreenTransition(),
+ mDreamingToLockscreenTransition, mMainDispatcher);
collectFlow(mView, mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha(),
- dreamingToLockscreenTransitionAlpha(mNotificationStackScrollLayoutController));
-
+ toLockscreenTransitionAlpha(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
collectFlow(mView, mDreamingToLockscreenTransitionViewModel.lockscreenTranslationY(
mDreamingToLockscreenTransitionTranslationY),
- dreamingToLockscreenTransitionY(mNotificationStackScrollLayoutController));
+ toLockscreenTransitionY(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
- collectFlow(mView, mKeyguardTransitionInteractor.getDreamingToLockscreenTransition(),
- mDreamingToLockscreenTransition);
+ // Occluded->Lockscreen
+ collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
+ mOccludedToLockscreenTransition, mMainDispatcher);
+ collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
+ toLockscreenTransitionAlpha(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
+ collectFlow(mView, mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY(
+ mOccludedToLockscreenTransitionTranslationY),
+ toLockscreenTransitionY(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
}
}
@@ -1143,6 +1171,8 @@ public final class NotificationPanelViewController implements Dumpable {
R.dimen.split_shade_scrim_transition_distance);
mDreamingToLockscreenTransitionTranslationY = mResources.getDimensionPixelSize(
R.dimen.dreaming_to_lockscreen_transition_lockscreen_translation_y);
+ mOccludedToLockscreenTransitionTranslationY = mResources.getDimensionPixelSize(
+ R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y);
}
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
@@ -1806,7 +1836,7 @@ public final class NotificationPanelViewController implements Dumpable {
}
private void updateClock() {
- if (mIsDreamToLockscreenTransitionRunning) {
+ if (mIsToLockscreenTransitionRunning) {
return;
}
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
@@ -2697,7 +2727,7 @@ public final class NotificationPanelViewController implements Dumpable {
} else if (statusBarState == KEYGUARD
|| statusBarState == StatusBarState.SHADE_LOCKED) {
mKeyguardBottomArea.setVisibility(View.VISIBLE);
- if (!mIsDreamToLockscreenTransitionRunning) {
+ if (!mIsToLockscreenTransitionRunning) {
mKeyguardBottomArea.setAlpha(1f);
}
} else {
@@ -3566,7 +3596,7 @@ public final class NotificationPanelViewController implements Dumpable {
}
private void updateNotificationTranslucency() {
- if (mIsDreamToLockscreenTransitionRunning) {
+ if (mIsToLockscreenTransitionRunning) {
return;
}
float alpha = 1f;
@@ -3624,7 +3654,7 @@ public final class NotificationPanelViewController implements Dumpable {
}
private void updateKeyguardBottomAreaAlpha() {
- if (mIsDreamToLockscreenTransitionRunning) {
+ if (mIsToLockscreenTransitionRunning) {
return;
}
// There are two possible panel expansion behaviors:
@@ -5856,7 +5886,7 @@ public final class NotificationPanelViewController implements Dumpable {
mCurrentPanelState = state;
}
- private Consumer<Float> dreamingToLockscreenTransitionAlpha(
+ private Consumer<Float> toLockscreenTransitionAlpha(
NotificationStackScrollLayoutController stackScroller) {
return (Float alpha) -> {
mKeyguardStatusViewController.setAlpha(alpha);
@@ -5874,7 +5904,7 @@ public final class NotificationPanelViewController implements Dumpable {
};
}
- private Consumer<Float> dreamingToLockscreenTransitionY(
+ private Consumer<Float> toLockscreenTransitionY(
NotificationStackScrollLayoutController stackScroller) {
return (Float translationY) -> {
mKeyguardStatusViewController.setTranslationY(translationY, /* excludeMedia= */false);
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
index 9653985cb6e6..d6b3b22bfd02 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
@@ -21,6 +21,8 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.lifecycle.repeatWhenAttached
import java.util.function.Consumer
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
@@ -34,7 +36,10 @@ fun <T> collectFlow(
view: View,
flow: Flow<T>,
consumer: Consumer<T>,
+ coroutineContext: CoroutineContext = EmptyCoroutineContext,
state: Lifecycle.State = Lifecycle.State.CREATED,
) {
- view.repeatWhenAttached { repeatOnLifecycle(state) { flow.collect { consumer.accept(it) } } }
+ view.repeatWhenAttached(coroutineContext) {
+ repeatOnLifecycle(state) { flow.collect { consumer.accept(it) } }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
new file mode 100644
index 000000000000..98d292d689e4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
@@ -0,0 +1,144 @@
+/*
+ * 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.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.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+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 OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: OccludedToLockscreenTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ val interactor = KeyguardTransitionInteractor(repository)
+ underTest = OccludedToLockscreenTransitionViewModel(interactor)
+ }
+
+ @Test
+ fun lockscreenFadeIn() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
+
+ repository.sendTransitionStep(step(0f))
+ // 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))
+ 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))
+
+ job.cancel()
+ }
+
+ @Test
+ fun lockscreenTranslationY() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val pixels = 100
+ val job =
+ underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
+
+ 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
+ )
+
+ 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 {
+ return TransitionStep(
+ from = KeyguardState.OCCLUDED,
+ to = KeyguardState.LOCKSCREEN,
+ value = value,
+ transitionState = TransitionState.RUNNING,
+ ownerName = "OccludedToLockscreenTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index ad993c391bcd..65b2ac0eb2d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -107,6 +107,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInterac
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.media.controls.ui.MediaHierarchyManager;
@@ -188,6 +189,8 @@ import org.mockito.stubbing.Answer;
import java.util.List;
import java.util.Optional;
+import kotlinx.coroutines.CoroutineDispatcher;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -289,7 +292,9 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock private KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
@Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@Mock private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
+ @Mock private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ @Mock private CoroutineDispatcher mMainDispatcher;
@Mock private MotionEvent mDownMotionEvent;
@Captor
private ArgumentCaptor<NotificationStackScrollLayout.OnEmptySpaceClickListener>
@@ -507,6 +512,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mKeyguardBottomAreaViewModel,
mKeyguardBottomAreaInteractor,
mDreamingToLockscreenTransitionViewModel,
+ mOccludedToLockscreenTransitionViewModel,
+ mMainDispatcher,
mKeyguardTransitionInteractor,
mDumpManager);
mNotificationPanelViewController.initDependencies(