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

Commit 6f0ed612 authored by Marzia Favaro's avatar Marzia Favaro Committed by Android (Google) Code Review
Browse files

Merge "Wallpaper animation for keyguard unlocking." into udc-dev

parents 889b6b4c c9eadeb6
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -245,6 +245,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
    @VisibleForTesting
    var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null
    private var surfaceBehindRemoteAnimationTargets: Array<RemoteAnimationTarget>? = null
    private var wallpaperTargets: Array<RemoteAnimationTarget>? = null
    private var surfaceBehindRemoteAnimationStartTime: Long = 0

    /**
@@ -257,9 +258,13 @@ class KeyguardUnlockAnimationController @Inject constructor(
     */
    private var surfaceBehindAlpha = 1f

    private var wallpaperAlpha = 1f

    @VisibleForTesting
    var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)

    var wallpaperAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)

    /**
     * Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
     * app/launcher behind the keyguard.
@@ -335,6 +340,27 @@ class KeyguardUnlockAnimationController @Inject constructor(
            })
        }

        with(wallpaperAlphaAnimator) {
            duration = LAUNCHER_ICONS_ANIMATION_DURATION_MS
            interpolator = Interpolators.ALPHA_OUT
            addUpdateListener { valueAnimator: ValueAnimator ->
                wallpaperAlpha = valueAnimator.animatedValue as Float
                setWallpaperAppearAmount(wallpaperAlpha)
            }
            addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    Log.d(TAG, "wallpaperAlphaAnimator#onAnimationEnd, animation ended ")
                    if (wallpaperAlpha == 1f) {
                        wallpaperTargets = null
                        keyguardViewMediator.get().finishExitRemoteAnimation()
                    } else {
                        Log.d(TAG, "wallpaperAlphaAnimator#onAnimationEnd, " +
                                "animation was cancelled: skipping finishAnimation()")
                    }
                }
            })
        }

        with(surfaceBehindEntryAnimator) {
            duration = UNLOCK_ANIMATION_DURATION_MS
            startDelay = UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS
@@ -361,6 +387,11 @@ class KeyguardUnlockAnimationController @Inject constructor(
            context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat()
    }

    fun isAnyKeyguyardAnimatorPlaying(): Boolean {
        return surfaceBehindAlphaAnimator.isStarted ||
                wallpaperAlphaAnimator.isStarted || surfaceBehindEntryAnimator.isStarted
    }

    /**
     * Add a listener to be notified of various stages of the unlock animation.
     */
@@ -492,6 +523,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
     */
    fun notifyStartSurfaceBehindRemoteAnimation(
        targets: Array<RemoteAnimationTarget>,
        wallpapers: Array<RemoteAnimationTarget>,
        startTime: Long,
        requestedShowSurfaceBehindKeyguard: Boolean
    ) {
@@ -501,8 +533,11 @@ class KeyguardUnlockAnimationController @Inject constructor(
        }

        surfaceBehindRemoteAnimationTargets = targets
        wallpaperTargets = wallpapers
        surfaceBehindRemoteAnimationStartTime = startTime

        fadeInWallpaper()

        // If we specifically requested that the surface behind be made visible (vs. it being made
        // visible because we're unlocking), then we're in the middle of a swipe-to-unlock touch
        // gesture and the surface behind the keyguard should be made visible so that we can animate
@@ -838,6 +873,38 @@ class KeyguardUnlockAnimationController @Inject constructor(
        }
    }

    /**
     * Modify the opacity of a wallpaper window.
     */
    fun setWallpaperAppearAmount(amount: Float) {
        wallpaperTargets?.forEach { wallpaper ->
            val animationAlpha = when {
                // If the screen has turned back off, the unlock animation is going to be cancelled,
                // so set the surface alpha to 0f so it's no longer visible.
                !powerManager.isInteractive -> 0f
                else -> amount
            }

            // SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is
            // unable to draw
            val sc: SurfaceControl? = wallpaper.leash
            if (keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE &&
                    sc?.isValid == true) {
                with(SurfaceControl.Transaction()) {
                    setAlpha(sc, animationAlpha)
                    apply()
                }
            } else {
                applyParamsToSurface(
                        SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
                                wallpaper.leash)
                                .withAlpha(animationAlpha)
                                .build()
                )
            }
        }
    }

    /**
     * Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and
     * we should clean up all of our state.
@@ -903,6 +970,12 @@ class KeyguardUnlockAnimationController @Inject constructor(
        surfaceBehindAlphaAnimator.start()
    }

    private fun fadeInWallpaper() {
        Log.d(TAG, "fadeInWallpaper")
        wallpaperAlphaAnimator.cancel()
        wallpaperAlphaAnimator.start()
    }

    private fun fadeOutSurfaceBehind() {
        Log.d(TAG, "fadeOutSurfaceBehind")
        surfaceBehindAlphaAnimator.cancel()
+19 −1
Original line number Diff line number Diff line
@@ -159,6 +159,7 @@ import dagger.Lazy;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.Executor;

/**
@@ -2710,9 +2711,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                                CUJ_LOCKSCREEN_UNLOCK_ANIMATION, "DismissPanel"));

                // Pass the surface and metadata to the unlock animation controller.
                RemoteAnimationTarget[] openingWallpapers = Arrays.stream(wallpapers).filter(
                        w -> w.mode == RemoteAnimationTarget.MODE_OPENING).toArray(
                        RemoteAnimationTarget[]::new);
                mKeyguardUnlockAnimationControllerLazy.get()
                        .notifyStartSurfaceBehindRemoteAnimation(
                                apps, startTime, mSurfaceBehindRemoteAnimationRequested);
                                apps, openingWallpapers, startTime,
                                mSurfaceBehindRemoteAnimationRequested);
            } else {
                mInteractionJankMonitor.begin(
                        createInteractionJankMonitorConf(
@@ -2961,6 +2966,19 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        mSurfaceBehindRemoteAnimationRequested = false;
        mSurfaceBehindRemoteAnimationRunning = false;
        mKeyguardStateController.notifyKeyguardGoingAway(false);
        finishExitRemoteAnimation();
    }

    void finishExitRemoteAnimation() {
        if (mKeyguardUnlockAnimationControllerLazy.get().isAnyKeyguyardAnimatorPlaying()
                || mKeyguardStateController.isDismissingFromSwipe()) {
            // If the animation is ongoing, or we are not done with the swipe gesture,
            // it's too early to terminate the animation
            Log.d(TAG, "finishAnimation not executing now because "
                    + "not all animations have finished");
            return;
        }
        Log.d(TAG, "finishAnimation executing");

        if (mSurfaceBehindRemoteAnimationFinishedCallback != null) {
            try {
+82 −18
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.argThat
import com.android.systemui.util.mockito.whenever
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
@@ -28,13 +29,14 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor.forClass
import org.mockito.Mock
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
import java.util.function.Predicate

@RunWith(AndroidTestingRunner::class)
@RunWithLooper
@@ -77,6 +79,13 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
            mock(ActivityManager.RunningTaskInfo::class.java), false)
    private lateinit var remoteAnimationTargets: Array<RemoteAnimationTarget>

    private var surfaceControlWp = mock(SurfaceControl::class.java)
    private var wallpaperTarget = RemoteAnimationTarget(
            2 /* taskId */, 0, surfaceControlWp, false, Rect(), Rect(), 0, Point(), Rect(), Rect(),
            mock(WindowConfiguration::class.java), false, surfaceControlWp, Rect(),
            mock(ActivityManager.RunningTaskInfo::class.java), false)
    private lateinit var wallpaperTargets: Array<RemoteAnimationTarget>

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
@@ -94,6 +103,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
        // All of these fields are final, so we can't mock them, but are needed so that the surface
        // appear amount setter doesn't short circuit.
        remoteAnimationTargets = arrayOf(remoteTarget1)
        wallpaperTargets = arrayOf(wallpaperTarget)

        // Set the surface applier to our mock so that we can verify the arguments passed to it.
        // This applier does not have any side effects within the unlock animation controller, so
@@ -119,18 +129,20 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {

        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
            remoteAnimationTargets,
            arrayOf(),
            0 /* startTime */,
            false /* requestedShowSurfaceBehindKeyguard */
        )

        val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java)
        verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture())
        val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
        verify(surfaceTransactionApplier, times(1)).scheduleApply(
                captorSb.capture { sp -> sp.surface == surfaceControl1 })

        val params = captor.value
        val params = captorSb.getLastValue()

        // We expect that we've instantly set the surface behind to alpha = 1f, and have no
        // transforms (translate, scale) on its matrix.
        assertEquals(params.alpha, 1f)
        assertEquals(1f, params.alpha)
        assertTrue(params.matrix.isIdentity)

        // Also expect we've immediately asked the keyguard view mediator to finish the remote
@@ -150,6 +162,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {

        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
            remoteAnimationTargets,
            wallpaperTargets,
            0 /* startTime */,
            false /* requestedShowSurfaceBehindKeyguard */
        )
@@ -174,6 +187,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {

        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
            remoteAnimationTargets,
            wallpaperTargets,
            0 /* startTime */,
            true /* requestedShowSurfaceBehindKeyguard */
        )
@@ -196,6 +210,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {

        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
            remoteAnimationTargets,
            wallpaperTargets,
            0 /* startTime */,
            true /* requestedShowSurfaceBehindKeyguard */
        )
@@ -216,6 +231,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
    fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() {
        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
            remoteAnimationTargets,
            wallpaperTargets,
            0 /* startTime */,
            false /* requestedShowSurfaceBehindKeyguard */
        )
@@ -230,6 +246,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {

        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
            remoteAnimationTargets,
            wallpaperTargets,
            0 /* startTime */,
            true /* requestedShowSurfaceBehindKeyguard */
        )
@@ -245,6 +262,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {

        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
                remoteAnimationTargets,
                wallpaperTargets,
                0 /* startTime */,
                false /* requestedShowSurfaceBehindKeyguard */
        )
@@ -259,6 +277,7 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
    fun surfaceAnimation_multipleTargets() {
        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
                arrayOf(remoteTarget1, remoteTarget2),
                wallpaperTargets,
                0 /* startTime */,
                false /* requestedShowSurfaceBehindKeyguard */
        )
@@ -267,10 +286,15 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
        // means an animation is in progress.
        keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(0.5f)

        val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java)
        verify(surfaceTransactionApplier, times(2)).scheduleApply(captor.capture())
        val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
        verify(surfaceTransactionApplier, times(2)).scheduleApply(captorSb
                .capture { sp -> sp.surface == surfaceControl1 || sp.surface == surfaceControl2 })
        val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
        verify(surfaceTransactionApplier, times(1).description(
                "WallpaperSurface was expected to receive scheduleApply once"
        )).scheduleApply(captorWp.capture { sp -> sp.surface == surfaceControlWp})

        val allParams = captor.allValues
        val allParams = captorSb.getAllValues()

        val remainingTargets = mutableListOf(surfaceControl1, surfaceControl2)
        allParams.forEach { params ->
@@ -293,20 +317,29 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {

        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
                remoteAnimationTargets,
                wallpaperTargets,
                0 /* startTime */,
                false /* requestedShowSurfaceBehindKeyguard */
        )

        keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f)
        keyguardUnlockAnimationController.setWallpaperAppearAmount(1f)

        val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java)
        verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture())
        val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
        verify(surfaceTransactionApplier, times(1)).scheduleApply(
                captorSb.capture { sp -> sp.surface == surfaceControl1})
        val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
        verify(surfaceTransactionApplier, atLeastOnce().description("Wallpaper surface has  not " +
                "received scheduleApply")).scheduleApply(
                captorWp.capture { sp -> sp.surface == surfaceControlWp })

        val params = captor.value
        val params = captorSb.getLastValue()

        // We expect that we've set the surface behind to alpha = 0f since we're not interactive.
        assertEquals(params.alpha, 0f)
        assertEquals(0f, params.alpha)
        assertTrue(params.matrix.isIdentity)
        assertEquals("Wallpaper surface was expected to have opacity 0",
                0f, captorWp.getLastValue().alpha)

        verifyNoMoreInteractions(surfaceTransactionApplier)
    }
@@ -317,19 +350,50 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {

        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
                remoteAnimationTargets,
                wallpaperTargets,
                0 /* startTime */,
                false /* requestedShowSurfaceBehindKeyguard */
        )

        keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(1f)

        val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java)
        verify(surfaceTransactionApplier, times(1)).scheduleApply(captor.capture())

        val params = captor.value
        assertEquals(params.alpha, 1f)
        keyguardUnlockAnimationController.setWallpaperAppearAmount(1f)

        val captorSb = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
        verify(surfaceTransactionApplier, times(1)).scheduleApply(
                captorSb.capture { sp -> sp.surface == surfaceControl1 })
        val captorWp = ArgThatCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>()
        verify(surfaceTransactionApplier, atLeastOnce().description("Wallpaper surface has  not " +
                "received scheduleApply")).scheduleApply(
                captorWp.capture { sp -> sp.surface == surfaceControlWp })

        val params = captorSb.getLastValue()
        assertEquals(1f, params.alpha)
        assertTrue(params.matrix.isIdentity)
        assertEquals("Wallpaper surface was expected to have opacity 1",
                1f, captorWp.getLastValue().alpha)

        verifyNoMoreInteractions(surfaceTransactionApplier)
    }

    private class ArgThatCaptor<T> {
        private var allArgs: MutableList<T> = mutableListOf()

        fun capture(predicate: Predicate<T>): T {
            return argThat{x: T ->
                if (predicate.test(x)) {
                    allArgs.add(x)
                    return@argThat true
                }
                return@argThat false
            }
        }

        fun getLastValue(): T {
            return allArgs.last()
        }

        fun getAllValues(): List<T> {
            return allArgs
        }
    }
}