Merge changes from topic "low_light_animations" into tm-qpr-dev am: b85665b316

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21456149

Change-Id: I148cf37ec79c3deda9c6d411bff4b8498e204cd3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
William Xiao
2023-03-07 02:32:59 +00:00
committed by Automerger Merge Worker
9 changed files with 441 additions and 55 deletions

View File

@@ -72,6 +72,7 @@ public final class LowLightDreamManager {
public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2;
private final DreamManager mDreamManager;
private final LowLightTransitionCoordinator mLowLightTransitionCoordinator;
@Nullable
private final ComponentName mLowLightDreamComponent;
@@ -81,8 +82,10 @@ public final class LowLightDreamManager {
@Inject
public LowLightDreamManager(
DreamManager dreamManager,
LowLightTransitionCoordinator lowLightTransitionCoordinator,
@Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) {
mDreamManager = dreamManager;
mLowLightTransitionCoordinator = lowLightTransitionCoordinator;
mLowLightDreamComponent = lowLightDreamComponent;
}
@@ -111,7 +114,9 @@ public final class LowLightDreamManager {
mAmbientLightMode = ambientLightMode;
mDreamManager.setSystemDreamComponent(mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT
? mLowLightDreamComponent : null);
boolean shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT;
mLowLightTransitionCoordinator.notifyBeforeLowLightTransition(shouldEnterLowLight,
() -> mDreamManager.setSystemDreamComponent(
shouldEnterLowLight ? mLowLightDreamComponent : null));
}
}

View File

@@ -0,0 +1,111 @@
/*
* 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.dream.lowlight;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Helper class that allows listening and running animations before entering or exiting low light.
*/
@Singleton
public class LowLightTransitionCoordinator {
/**
* Listener that is notified before low light entry.
*/
public interface LowLightEnterListener {
/**
* Callback that is notified before the device enters low light.
*
* @return an optional animator that will be waited upon before entering low light.
*/
Animator onBeforeEnterLowLight();
}
/**
* Listener that is notified before low light exit.
*/
public interface LowLightExitListener {
/**
* Callback that is notified before the device exits low light.
*
* @return an optional animator that will be waited upon before exiting low light.
*/
Animator onBeforeExitLowLight();
}
private LowLightEnterListener mLowLightEnterListener;
private LowLightExitListener mLowLightExitListener;
@Inject
public LowLightTransitionCoordinator() {
}
/**
* Sets the listener for the low light enter event.
*
* Only one listener can be set at a time. This method will overwrite any previously set
* listener. Null can be used to unset the listener.
*/
public void setLowLightEnterListener(@Nullable LowLightEnterListener lowLightEnterListener) {
mLowLightEnterListener = lowLightEnterListener;
}
/**
* Sets the listener for the low light exit event.
*
* Only one listener can be set at a time. This method will overwrite any previously set
* listener. Null can be used to unset the listener.
*/
public void setLowLightExitListener(@Nullable LowLightExitListener lowLightExitListener) {
mLowLightExitListener = lowLightExitListener;
}
/**
* Notifies listeners that the device is about to enter or exit low light.
*
* @param entering true if listeners should be notified before entering low light, false if this
* is notifying before exiting.
* @param callback callback that will be run after listeners complete.
*/
void notifyBeforeLowLightTransition(boolean entering, Runnable callback) {
Animator animator = null;
if (entering && mLowLightEnterListener != null) {
animator = mLowLightEnterListener.onBeforeEnterLowLight();
} else if (!entering && mLowLightExitListener != null) {
animator = mLowLightExitListener.onBeforeExitLowLight();
}
// If the listener returned an animator to indicate it was running an animation, run the
// callback after the animation completes, otherwise call the callback directly.
if (animator != null) {
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
callback.run();
}
});
} else {
callback.run();
}
}
}

View File

@@ -21,7 +21,10 @@ import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE
import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -43,45 +46,53 @@ public class LowLightDreamManagerTest {
@Mock
private DreamManager mDreamManager;
@Mock
private LowLightTransitionCoordinator mTransitionCoordinator;
@Mock
private ComponentName mDreamComponent;
LowLightDreamManager mLowLightDreamManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
// Automatically run any provided Runnable to mTransitionCoordinator to simplify testing.
doAnswer(invocation -> {
((Runnable) invocation.getArgument(1)).run();
return null;
}).when(mTransitionCoordinator).notifyBeforeLowLightTransition(anyBoolean(),
any(Runnable.class));
mLowLightDreamManager = new LowLightDreamManager(mDreamManager, mTransitionCoordinator,
mDreamComponent);
}
@Test
public void setAmbientLightMode_lowLight_setSystemDream() {
final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
mDreamComponent);
lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(true), any());
verify(mDreamManager).setSystemDreamComponent(mDreamComponent);
}
@Test
public void setAmbientLightMode_regularLight_clearSystemDream() {
final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
mDreamComponent);
lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR);
mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR);
verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(false), any());
verify(mDreamManager).setSystemDreamComponent(null);
}
@Test
public void setAmbientLightMode_defaultUnknownMode_clearSystemDream() {
final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
mDreamComponent);
// Set to low light first.
lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
clearInvocations(mDreamManager);
// Return to default unknown mode.
lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN);
mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN);
verify(mDreamManager).setSystemDreamComponent(null);
}
@@ -89,7 +100,7 @@ public class LowLightDreamManagerTest {
@Test
public void setAmbientLightMode_dreamComponentNotSet_doNothing() {
final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
null /*dream component*/);
mTransitionCoordinator, null /*dream component*/);
lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);

View File

@@ -0,0 +1,113 @@
/*
* 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.dream.lowlight;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.animation.Animator;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class LowLightTransitionCoordinatorTest {
@Mock
private LowLightTransitionCoordinator.LowLightEnterListener mEnterListener;
@Mock
private LowLightTransitionCoordinator.LowLightExitListener mExitListener;
@Mock
private Animator mAnimator;
@Captor
private ArgumentCaptor<Animator.AnimatorListener> mAnimatorListenerCaptor;
@Mock
private Runnable mRunnable;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void onEnterCalledOnListeners() {
LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
coordinator.setLowLightEnterListener(mEnterListener);
coordinator.notifyBeforeLowLightTransition(true, mRunnable);
verify(mEnterListener).onBeforeEnterLowLight();
verify(mRunnable).run();
}
@Test
public void onExitCalledOnListeners() {
LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
coordinator.setLowLightExitListener(mExitListener);
coordinator.notifyBeforeLowLightTransition(false, mRunnable);
verify(mExitListener).onBeforeExitLowLight();
verify(mRunnable).run();
}
@Test
public void listenerNotCalledAfterRemoval() {
LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
coordinator.setLowLightEnterListener(mEnterListener);
coordinator.setLowLightEnterListener(null);
coordinator.notifyBeforeLowLightTransition(true, mRunnable);
verifyZeroInteractions(mEnterListener);
verify(mRunnable).run();
}
@Test
public void runnableCalledAfterAnimationEnds() {
when(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator);
LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
coordinator.setLowLightEnterListener(mEnterListener);
coordinator.notifyBeforeLowLightTransition(true, mRunnable);
// Animator listener is added and the runnable is not run yet.
verify(mAnimator).addListener(mAnimatorListenerCaptor.capture());
verifyZeroInteractions(mRunnable);
// Runnable is run once the animation ends.
mAnimatorListenerCaptor.getValue().onAnimationEnd(null);
verify(mRunnable).run();
}
}

View File

@@ -774,7 +774,7 @@
<!-- Duration in milliseconds of the dream in complications fade-in animation. -->
<integer name="config_dreamOverlayInComplicationsDurationMs">250</integer>
<!-- Duration in milliseconds of the y-translation animation when entering a dream -->
<integer name="config_dreamOverlayInTranslationYDurationMs">917</integer>
<integer name="config_dreamOverlayInTranslationYDurationMs">1167</integer>
<!-- Delay in milliseconds before switching to the dock user and dreaming if a secondary user is
active when the device is locked and docked. 0 indicates disabled. Default is 1 minute. -->

View File

@@ -43,7 +43,6 @@ import com.android.systemui.util.concurrency.DelayableExecutor
import javax.inject.Inject
import javax.inject.Named
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.launch
@@ -131,9 +130,17 @@ constructor(
}
}
/** Starts the dream content and dream overlay entry animations. */
/**
* Starts the dream content and dream overlay entry animations.
*
* @param downwards if true, the entry animation translations downwards into position rather
* than upwards.
*/
@JvmOverloads
fun startEntryAnimations(animatorBuilder: () -> AnimatorSet = { AnimatorSet() }) {
fun startEntryAnimations(
downwards: Boolean,
animatorBuilder: () -> AnimatorSet = { AnimatorSet() }
) {
cancelAnimations()
mAnimator =
@@ -153,7 +160,7 @@ constructor(
interpolator = Interpolators.LINEAR
),
translationYAnimator(
from = mDreamInTranslationYDistance.toFloat(),
from = mDreamInTranslationYDistance.toFloat() * (if (downwards) -1 else 1),
to = 0f,
durationMs = mDreamInTranslationYDurationMs,
interpolator = Interpolators.EMPHASIZED_DECELERATE
@@ -167,6 +174,71 @@ constructor(
}
}
/**
* Starts the dream content and dream overlay exit animations.
*
* This should only be used when the low light dream is entering, animations to/from other SysUI
* views is controlled by `transitionViewModel`.
*/
// TODO(b/256916668): integrate with the keyguard transition model once dream surfaces work is
// done.
@JvmOverloads
fun startExitAnimations(animatorBuilder: () -> AnimatorSet = { AnimatorSet() }): Animator {
cancelAnimations()
mAnimator =
animatorBuilder().apply {
playTogether(
translationYAnimator(
from = 0f,
to = -mDreamInTranslationYDistance.toFloat(),
durationMs = mDreamInTranslationYDurationMs,
delayMs = 0,
interpolator = Interpolators.EMPHASIZED
),
alphaAnimator(
from =
mCurrentAlphaAtPosition.getOrDefault(
key = POSITION_BOTTOM,
defaultValue = 1f
),
to = 0f,
durationMs = mDreamInComplicationsAnimDurationMs,
delayMs = 0,
positions = POSITION_BOTTOM
)
.apply {
doOnEnd {
// The logical end of the animation is once the alpha and blur
// animations finish, end the animation so that any listeners are
// notified. The Y translation animation is much longer than all of
// the other animations due to how the spec is defined, but is not
// expected to run to completion.
mAnimator?.end()
}
},
alphaAnimator(
from =
mCurrentAlphaAtPosition.getOrDefault(
key = POSITION_TOP,
defaultValue = 1f
),
to = 0f,
durationMs = mDreamInComplicationsAnimDurationMs,
delayMs = 0,
positions = POSITION_TOP
)
)
doOnEnd {
mAnimator = null
mOverlayStateController.setExitAnimationsRunning(false)
}
start()
}
mOverlayStateController.setExitAnimationsRunning(true)
return mAnimator as AnimatorSet
}
/** Starts the dream content and dream overlay exit animations. */
fun wakeUp(doneCallback: Runnable, executor: DelayableExecutor) {
cancelAnimations()
@@ -182,19 +254,6 @@ constructor(
}
}
/**
* Ends the dream content and dream overlay animations, if they're currently running.
*
* @see [AnimatorSet.end]
*/
fun endAnimations() {
mAnimator =
mAnimator?.let {
it.end()
null
}
}
private fun blurAnimator(
view: View,
fromBlurRadius: Float,

View File

@@ -23,6 +23,7 @@ import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_BOTTOM;
import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_TOP;
import android.animation.Animator;
import android.content.res.Resources;
import android.os.Handler;
import android.util.MathUtils;
@@ -31,6 +32,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
@@ -54,11 +56,14 @@ import javax.inject.Named;
* View controller for {@link DreamOverlayContainerView}.
*/
@DreamOverlayComponent.DreamOverlayScope
public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
public class DreamOverlayContainerViewController extends
ViewController<DreamOverlayContainerView> implements
LowLightTransitionCoordinator.LowLightEnterListener {
private final DreamOverlayStatusBarViewController mStatusBarViewController;
private final BlurUtils mBlurUtils;
private final DreamOverlayAnimationsController mDreamOverlayAnimationsController;
private final DreamOverlayStateController mStateController;
private final LowLightTransitionCoordinator mLowLightTransitionCoordinator;
private final ComplicationHostViewController mComplicationHostViewController;
@@ -143,19 +148,18 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
};
/**
* If true, overlay entry animations should be skipped once.
*
* This is turned on when exiting low light and should be turned off once the entry animations
* are skipped once.
* If {@code true}, the dream has just transitioned from the low light dream back to the user
* dream and we should play an entry animation where the overlay slides in downwards from the
* top instead of the typicla slide in upwards from the bottom.
*/
private boolean mSkipEntryAnimations;
private boolean mExitingLowLight;
private final DreamOverlayStateController.Callback
mDreamOverlayStateCallback =
new DreamOverlayStateController.Callback() {
@Override
public void onExitLowLight() {
mSkipEntryAnimations = true;
mExitingLowLight = true;
}
};
@@ -165,6 +169,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
ComplicationHostViewController complicationHostViewController,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
DreamOverlayStatusBarViewController statusBarViewController,
LowLightTransitionCoordinator lowLightTransitionCoordinator,
BlurUtils blurUtils,
@Main Handler handler,
@Main Resources resources,
@@ -182,6 +187,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
mBlurUtils = blurUtils;
mDreamOverlayAnimationsController = animationsController;
mStateController = stateController;
mLowLightTransitionCoordinator = lowLightTransitionCoordinator;
mBouncerlessScrimController = bouncerlessScrimController;
mBouncerlessScrimController.addCallback(mBouncerlessExpansionCallback);
@@ -208,6 +214,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
mStatusBarViewController.init();
mComplicationHostViewController.init();
mDreamOverlayAnimationsController.init(mView);
mLowLightTransitionCoordinator.setLowLightEnterListener(this);
}
@Override
@@ -219,14 +226,10 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
// Start dream entry animations. Skip animations for low light clock.
if (!mStateController.isLowLightActive()) {
mDreamOverlayAnimationsController.startEntryAnimations();
if (mSkipEntryAnimations) {
// If we're transitioning from the low light dream back to the user dream, skip the
// overlay animations and show immediately.
mDreamOverlayAnimationsController.endAnimations();
mSkipEntryAnimations = false;
}
// If this is transitioning from the low light dream to the user dream, the overlay
// should translate in downwards instead of upwards.
mDreamOverlayAnimationsController.startEntryAnimations(mExitingLowLight);
mExitingLowLight = false;
}
}
@@ -310,4 +313,12 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor);
}
@Override
public Animator onBeforeEnterLowLight() {
// Return the animator so that the transition coordinator waits for the overlay exit
// animations to finish before entering low light, as otherwise the default DreamActivity
// animation plays immediately and there's no time for this animation to play.
return mDreamOverlayAnimationsController.startExitAnimations();
}
}

View File

@@ -1,6 +1,8 @@
package com.android.systemui.dreams
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.testing.AndroidTestingRunner
import android.view.View
import androidx.test.filters.SmallTest
@@ -10,13 +12,16 @@ import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransition
import com.android.systemui.statusbar.BlurUtils
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.anyLong
import org.mockito.Mockito.eq
@@ -70,6 +75,19 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
runBlocking(Dispatchers.Main.immediate) { controller.init(mockView) }
}
@Test
fun testExitAnimationUpdatesState() {
controller.startExitAnimations(animatorBuilder = { mockAnimator })
verify(stateController).setExitAnimationsRunning(true)
val captor = argumentCaptor<Animator.AnimatorListener>()
verify(mockAnimator).addListener(captor.capture())
captor.value.onAnimationEnd(mockAnimator)
verify(stateController).setExitAnimationsRunning(false)
}
@Test
fun testWakeUpCallsExecutor() {
val mockExecutor: DelayableExecutor = mock()
@@ -87,7 +105,7 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
fun testWakeUpAfterStartWillCancel() {
val mockStartAnimator: AnimatorSet = mock()
controller.startEntryAnimations(animatorBuilder = { mockStartAnimator })
controller.startEntryAnimations(false, animatorBuilder = { mockStartAnimator })
verify(mockStartAnimator, never()).cancel()
@@ -100,4 +118,50 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
// animator.
verify(mockStartAnimator, times(1)).cancel()
}
@Test
fun testEntryAnimations_translatesUpwards() {
val mockStartAnimator: AnimatorSet = mock()
controller.startEntryAnimations(
/* downwards= */ false,
animatorBuilder = { mockStartAnimator }
)
val animatorCaptor = ArgumentCaptor.forClass(Animator::class.java)
verify(mockStartAnimator).playTogether(animatorCaptor.capture())
// Check if there's a ValueAnimator starting at the expected Y distance.
val animators: List<ValueAnimator> = animatorCaptor.allValues as List<ValueAnimator>
assertTrue(
animators.any {
// Call setCurrentFraction so the animated value jumps to the initial value.
it.setCurrentFraction(0f)
it.animatedValue == DREAM_IN_TRANSLATION_Y_DISTANCE.toFloat()
}
)
}
@Test
fun testEntryAnimations_translatesDownwards() {
val mockStartAnimator: AnimatorSet = mock()
controller.startEntryAnimations(
/* downwards= */ true,
animatorBuilder = { mockStartAnimator }
)
val animatorCaptor = ArgumentCaptor.forClass(Animator::class.java)
verify(mockStartAnimator).playTogether(animatorCaptor.capture())
// Check if there's a ValueAnimator starting at the expected Y distance.
val animators: List<ValueAnimator> = animatorCaptor.allValues as List<ValueAnimator>
assertTrue(
animators.any {
// Call setCurrentFraction so the animated value jumps to the initial value.
it.setCurrentFraction(0f)
it.animatedValue == -DREAM_IN_TRANSLATION_Y_DISTANCE.toFloat()
}
)
}
}

View File

@@ -17,6 +17,7 @@
package com.android.systemui.dreams;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -33,6 +34,7 @@ import android.view.ViewTreeObserver;
import androidx.test.filters.SmallTest;
import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
@@ -64,6 +66,9 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
@Mock
DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
@Mock
LowLightTransitionCoordinator mLowLightTransitionCoordinator;
@Mock
DreamOverlayContainerView mDreamOverlayContainerView;
@@ -109,6 +114,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mComplicationHostViewController,
mDreamOverlayContentView,
mDreamOverlayStatusBarViewController,
mLowLightTransitionCoordinator,
mBlurUtils,
mHandler,
mResources,
@@ -200,7 +206,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mController.onViewAttached();
verify(mAnimationsController).startEntryAnimations();
verify(mAnimationsController).startEntryAnimations(false);
verify(mAnimationsController, never()).cancelAnimations();
}
@@ -210,11 +216,11 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mController.onViewAttached();
verify(mAnimationsController, never()).startEntryAnimations();
verify(mAnimationsController, never()).startEntryAnimations(anyBoolean());
}
@Test
public void testSkipEntryAnimationsWhenExitingLowLight() {
public void testDownwardEntryAnimationsWhenExitingLowLight() {
ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor =
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
when(mStateController.isLowLightActive()).thenReturn(false);
@@ -230,8 +236,14 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mController.onViewAttached();
// Entry animations should be started then immediately ended to skip to the end.
verify(mAnimationsController).startEntryAnimations();
verify(mAnimationsController).endAnimations();
verify(mAnimationsController).startEntryAnimations(true);
}
@Test
public void testStartsExitAnimationsBeforeEnteringLowLight() {
mController.onBeforeEnterLowLight();
verify(mAnimationsController).startExitAnimations();
}
@Test