Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c7e4554 authored by William Xiao's avatar William Xiao
Browse files

Reverse dream overlay animations on exiting low light

This CL reuses the callback added in ag/20953423 to reverse the
direction the overlay text animates in upon exiting low light to match
the spec, instead of disabling the animation altogether.

Bug: 260638159
Test: atest DreamOverlayAnimationsControllerTest DreamOverlayContainerViewControllerTest
Change-Id: Ib9925bf6424753daed6334c606a353874e8a1337
parent 98b21ffc
Loading
Loading
Loading
Loading
+11 −17
Original line number Diff line number Diff line
@@ -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
@@ -182,19 +189,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,
+9 −14
Original line number Diff line number Diff line
@@ -143,19 +143,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;
                }
            };

@@ -219,14 +218,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;
        }
    }

+50 −1
Original line number Diff line number Diff line
package com.android.systemui.dreams

import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.testing.AndroidTestingRunner
import android.view.View
import androidx.test.filters.SmallTest
@@ -14,9 +15,11 @@ 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
@@ -87,7 +90,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 +103,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()
            }
        )
    }
}
+5 −5
Original line number Diff line number Diff line
@@ -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;
@@ -200,7 +201,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {

        mController.onViewAttached();

        verify(mAnimationsController).startEntryAnimations();
        verify(mAnimationsController).startEntryAnimations(false);
        verify(mAnimationsController, never()).cancelAnimations();
    }

@@ -210,11 +211,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 +231,7 @@ 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