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

Commit 89eb6bd6 authored by Luca Zuccarini's avatar Luca Zuccarini
Browse files

Enable view anchoring in ActivityStarter.

This change will enable components in SystemUI to register a controller
factory long term, so that all launches and returns from the associated
activity use that factory to generate a controller. See
go/return-animations-framework-design for an idea of what that looks
like (design has evolved since then butthe principle is the same).

Bug: 202516970
Flag: com.android.systemui.shared.return_animation_framework_library
Flag: com.android.systemui.shared.return_animation_framework_long_lived
Test: atest ActivityStarterImplTest LegacyActivityStarterImplTest
Change-Id: I51892424fb196e209c206297d2fc85fa4bf5ac22
parent 5f07d0a5
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -18,9 +18,14 @@ package com.android.systemui.statusbar.phone

import android.app.PendingIntent
import android.content.Intent
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.shared.Flags as SharedFlags
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -32,6 +37,9 @@ import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.never

@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -54,6 +62,62 @@ class ActivityStarterImplTest : SysuiTestCase() {
            )
    }

    @EnableFlags(
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
    )
    @EnableSceneContainer
    @Test
    fun registerTransition_forwardsTheRequest() {
        val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java)
        val controllerFactory = mock(ActivityTransitionAnimator.ControllerFactory::class.java)

        underTest.registerTransition(cookie, controllerFactory)

        verify(activityStarterInternal).registerTransition(eq(cookie), eq(controllerFactory))
    }

    @DisableFlags(
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
    )
    @Test
    fun registerTransition_doesNotForwardTheRequest_whenFlaggedOff() {
        val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java)
        val controllerFactory = mock(ActivityTransitionAnimator.ControllerFactory::class.java)

        underTest.registerTransition(cookie, controllerFactory)

        verify(activityStarterInternal, never()).registerTransition(any(), any())
    }

    @EnableFlags(
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
    )
    @EnableSceneContainer
    @Test
    fun unregisterTransition_forwardsTheRequest() {
        val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java)

        underTest.unregisterTransition(cookie)

        verify(activityStarterInternal).unregisterTransition(eq(cookie))
    }

    @DisableFlags(
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
    )
    @Test
    fun unregisterTransition_doesNotForwardTheRequest_whenFlaggedOff() {
        val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java)

        underTest.unregisterTransition(cookie)

        verify(activityStarterInternal, never()).unregisterTransition(any())
    }

    @Test
    fun postStartActivityDismissingKeyguard_pendingIntent_postsOnMain() {
        val intent = mock(PendingIntent::class.java)
+68 −9
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import com.android.systemui.shade.ShadeController
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeAnimationRepository
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl
import com.android.systemui.shared.Flags as SharedFlags
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -63,6 +64,7 @@ import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -149,6 +151,63 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
        `when`(communalSceneInteractor.isLaunchingWidget).thenReturn(MutableStateFlow(false))
    }

    @EnableFlags(
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
    )
    @Test
    fun registerTransition_registers() {
        val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java)
        val controllerFactory = mock(ActivityTransitionAnimator.ControllerFactory::class.java)
        `when`(controllerFactory.cookie).thenReturn(cookie)

        underTest.registerTransition(cookie, controllerFactory)

        verify(activityTransitionAnimator).register(eq(cookie), any())
    }

    @DisableFlags(
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
    )
    @Test
    fun registerTransition_throws_whenFlagsAreDisabled() {
        val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java)
        val controllerFactory = mock(ActivityTransitionAnimator.ControllerFactory::class.java)

        assertThrows(IllegalStateException::class.java) {
            underTest.registerTransition(cookie, controllerFactory)
        }

        verify(activityTransitionAnimator, never()).register(any(), any())
    }

    @EnableFlags(
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
    )
    @Test
    fun unregisterTransition_unregisters() {
        val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java)

        underTest.unregisterTransition(cookie)

        verify(activityTransitionAnimator).unregister(eq(cookie))
    }

    @DisableFlags(
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
        SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
    )
    @Test
    fun unregisterTransition_throws_whenFlagsAreDisabled() {
        val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java)

        assertThrows(IllegalStateException::class.java) { underTest.unregisterTransition(cookie) }

        verify(activityTransitionAnimator, never()).unregister(eq(cookie))
    }

    @Test
    fun startActivityDismissingKeyguard_dismissShadeWhenOccluded_runAfterKeyguardGone() {
        val intent = mock(Intent::class.java)
@@ -216,7 +275,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
        underTest.startPendingIntentDismissingKeyguard(
            intent = pendingIntent,
            dismissShade = true,
            customMessage = customMessage
            customMessage = customMessage,
        )
        mainExecutor.runAllReady()

@@ -296,7 +355,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
                nullable(PendingIntent.OnFinished::class.java),
                nullable(Handler::class.java),
                nullable(String::class.java),
                bundleCaptor.capture()
                bundleCaptor.capture(),
            )
        val options = ActivityOptions.fromBundle(bundleCaptor.firstValue)
        assertThat(options.getPendingIntentBackgroundActivityStartMode())
@@ -339,7 +398,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
            dismissShade = true,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = true
            skipLockscreenChecks = true,
        )
        mainExecutor.runAllReady()

@@ -373,7 +432,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
            dismissShade = true,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = true
            skipLockscreenChecks = true,
        )
        mainExecutor.runAllReady()

@@ -413,7 +472,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
            dismissShade = false,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = false
            skipLockscreenChecks = false,
        )
        mainExecutor.runAllReady()

@@ -458,7 +517,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
            dismissShade = false,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = false
            skipLockscreenChecks = false,
        )
        mainExecutor.runAllReady()

@@ -583,7 +642,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
            },
            {},
            false,
            customMessage
            customMessage,
        )

        verify(centralSurfaces).awakenDreams()
@@ -602,7 +661,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
            cancelAction = null,
            dismissShade = false,
            afterKeyguardGone = false,
            deferred = false
            deferred = false,
        )

        verify(centralSurfaces, times(1)).awakenDreams()
@@ -620,7 +679,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
            cancelAction = null,
            dismissShade = false,
            afterKeyguardGone = false,
            deferred = false
            deferred = false,
        )

        verify(centralSurfaces, never()).awakenDreams()
+17 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ package com.android.systemui.plugins;

import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
@@ -33,6 +34,22 @@ import com.android.systemui.plugins.annotations.ProvidesInterface;
public interface ActivityStarter {
    int VERSION = 2;

    /**
     * Registers the given {@link ActivityTransitionAnimator.ControllerFactory} for launching and
     * closing transitions matching the {@link ActivityTransitionAnimator.TransitionCookie} and the
     * {@link ComponentName} that it contains.
     */
    void registerTransition(
            ActivityTransitionAnimator.TransitionCookie cookie,
            ActivityTransitionAnimator.ControllerFactory controllerFactory);

    /**
     * Unregisters the {@link ActivityTransitionAnimator.ControllerFactory} previously registered
     * containing the given {@link ActivityTransitionAnimator.TransitionCookie}. If no such
     * registration exists, this is a no-op.
     */
    void unregisterTransition(ActivityTransitionAnimator.TransitionCookie cookie);

    void startPendingIntentDismissingKeyguard(PendingIntent intent);

    /**
+3 −2
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.phone.ui.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.ui.StatusBarIconList;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wm.shell.shared.ShellTransitions;

import dagger.Binds;
import dagger.Lazy;
@@ -214,8 +215,8 @@ public interface CentralSurfacesDependenciesModule {
    @Provides
    @SysUISingleton
    static ActivityTransitionAnimator provideActivityTransitionAnimator(
            @Main Executor mainExecutor) {
        return new ActivityTransitionAnimator(mainExecutor);
            @Main Executor mainExecutor, ShellTransitions shellTransitions) {
        return new ActivityTransitionAnimator(mainExecutor, shellTransitions);
    }

    /** */
+20 −6
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.os.Bundle
import android.os.UserHandle
import android.view.View
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.animation.TransitionAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
@@ -38,7 +39,7 @@ constructor(
    private val statusBarStateController: SysuiStatusBarStateController,
    @Main private val mainExecutor: DelayableExecutor,
    activityStarterInternal: Lazy<ActivityStarterInternalImpl>,
    legacyActivityStarter: Lazy<LegacyActivityStarterInternalImpl>
    legacyActivityStarter: Lazy<LegacyActivityStarterInternalImpl>,
) : ActivityStarter {

    private val activityStarterInternal: ActivityStarterInternal =
@@ -48,10 +49,23 @@ constructor(
            legacyActivityStarter.get()
        }

    override fun registerTransition(
        cookie: ActivityTransitionAnimator.TransitionCookie,
        controllerFactory: ActivityTransitionAnimator.ControllerFactory,
    ) {
        if (!TransitionAnimator.longLivedReturnAnimationsEnabled()) return
        activityStarterInternal.registerTransition(cookie, controllerFactory)
    }

    override fun unregisterTransition(cookie: ActivityTransitionAnimator.TransitionCookie) {
        if (!TransitionAnimator.longLivedReturnAnimationsEnabled()) return
        activityStarterInternal.unregisterTransition(cookie)
    }

    override fun startPendingIntentDismissingKeyguard(intent: PendingIntent) {
        activityStarterInternal.startPendingIntentDismissingKeyguard(
            intent = intent,
            dismissShade = true
            dismissShade = true,
        )
    }

@@ -98,7 +112,7 @@ constructor(
        intentSentUiThreadCallback: Runnable?,
        animationController: ActivityTransitionAnimator.Controller?,
        fillInIntent: Intent?,
        extraOptions: Bundle?
        extraOptions: Bundle?,
    ) {
        activityStarterInternal.startPendingIntentDismissingKeyguard(
            intent = intent,
@@ -115,7 +129,7 @@ constructor(
    override fun startPendingIntentMaybeDismissingKeyguard(
        intent: PendingIntent,
        intentSentUiThreadCallback: Runnable?,
        animationController: ActivityTransitionAnimator.Controller?
        animationController: ActivityTransitionAnimator.Controller?,
    ) {
        activityStarterInternal.startPendingIntentDismissingKeyguard(
            intent = intent,
@@ -245,7 +259,7 @@ constructor(

    override fun postStartActivityDismissingKeyguard(
        intent: PendingIntent,
        animationController: ActivityTransitionAnimator.Controller?
        animationController: ActivityTransitionAnimator.Controller?,
    ) {
        postOnUiThread {
            activityStarterInternal.startPendingIntentDismissingKeyguard(
@@ -381,7 +395,7 @@ constructor(
        postOnUiThread {
            statusBarStateController.setLeaveOpenOnKeyguardHide(true)
            activityStarterInternal.executeRunnableDismissingKeyguard(
                runnable = { runnable?.let { postOnUiThread(runnable = it) } },
                runnable = { runnable?.let { postOnUiThread(runnable = it) } }
            )
        }
    }
Loading