Loading packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +117 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.app.ActivityManager import android.app.ActivityTaskManager import android.app.PendingIntent import android.app.TaskInfo import android.app.WindowConfiguration import android.content.ComponentName import android.graphics.Matrix import android.graphics.Rect import android.graphics.RectF Loading @@ -38,7 +40,9 @@ import android.view.View import android.view.ViewGroup import android.view.WindowManager import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.TRANSIT_TO_FRONT import android.view.animation.PathInterpolator import android.window.RemoteTransition import android.window.TransitionFilter Loading Loading @@ -203,6 +207,10 @@ constructor( } } /** Book-keeping for long-lived transitions that are currently registered. */ private val longLivedTransitions = HashMap<TransitionCookie, Pair<RemoteTransition, RemoteTransition>>() /** * Start an intent and animate the opening window. The intent will be started by running * [intentStarter], which should use the provided [RemoteAnimationAdapter] and return the launch Loading Loading @@ -497,6 +505,7 @@ constructor( view: View, cujType: Int? = null, cookie: TransitionCookie? = null, component: ComponentName? = null, returnCujType: Int? = null ): Controller? { // Make sure the View we launch from implements LaunchableView to avoid visibility Loading @@ -519,7 +528,13 @@ constructor( return null } return GhostedViewTransitionAnimatorController(view, cujType, cookie, returnCujType) return GhostedViewTransitionAnimatorController( view, cujType, cookie, component, returnCujType ) } } Loading Loading @@ -553,6 +568,16 @@ constructor( val transitionCookie: TransitionCookie? get() = null /** * The [ComponentName] of the activity whose window is tied to this [Controller]. * * This is used as a fallback when a cookie is defined but there is no match (e.g. when a * matching activity was launched by a mean different from the launchable in this * [Controller]), and should be defined for all long-lived registered [Controller]s. */ val component: ComponentName? get() = null /** * The intent was started. If [willAnimate] is false, nothing else will happen and the * animation will not be started. Loading @@ -571,6 +596,91 @@ constructor( fun onTransitionAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {} } /** * Registers [controller] as a long-lived transition handler for launch and return animations. * * The [controller] will only be used for transitions matching the [TransitionCookie] defined * within it, or the [ComponentName] if the cookie matching fails. Both fields are mandatory for * this registration. */ fun register(controller: Controller) { check(returnAnimationFrameworkLibrary()) { "Long-lived registrations cannot be used when the returnAnimationFrameworkLibrary " + "flag is disabled" } if (transitionRegister == null) { throw IllegalStateException( "A RemoteTransitionRegister must be provided when creating this animator in " + "order to use long-lived animations" ) } val cookie = controller.transitionCookie ?: throw IllegalStateException( "A cookie must be defined in order to use long-lived animations" ) val component = controller.component ?: throw IllegalStateException( "A component must be defined in order to use long-lived animations" ) // Make sure that any previous registrations linked to the same cookie are gone. unregister(cookie) val launchFilter = TransitionFilter().apply { mRequirements = arrayOf( TransitionFilter.Requirement().apply { mActivityType = WindowConfiguration.ACTIVITY_TYPE_STANDARD mModes = intArrayOf(TRANSIT_OPEN, TRANSIT_TO_FRONT) mTopActivity = component } ) } val launchRemoteTransition = RemoteTransition( RemoteAnimationRunnerCompat.wrap(createRunner(controller)), "${cookie}_launchTransition" ) transitionRegister.register(launchFilter, launchRemoteTransition) val returnController = object : Controller by controller { override val isLaunching: Boolean = false } val returnFilter = TransitionFilter().apply { mRequirements = arrayOf( TransitionFilter.Requirement().apply { mActivityType = WindowConfiguration.ACTIVITY_TYPE_STANDARD mModes = intArrayOf(TRANSIT_CLOSE, TRANSIT_TO_BACK) mTopActivity = component } ) } val returnRemoteTransition = RemoteTransition( RemoteAnimationRunnerCompat.wrap(createRunner(returnController)), "${cookie}_returnTransition" ) transitionRegister.register(returnFilter, returnRemoteTransition) longLivedTransitions[cookie] = Pair(launchRemoteTransition, returnRemoteTransition) } /** Unregisters all controllers previously registered that contain [cookie]. */ fun unregister(cookie: TransitionCookie) { val transitions = longLivedTransitions[cookie] ?: return transitionRegister?.unregister(transitions.first) transitionRegister?.unregister(transitions.second) longLivedTransitions.remove(cookie) } /** * Invokes [onAnimationComplete] when animation is either cancelled or completed. Delegates all * events to the passed [delegate]. Loading Loading @@ -817,13 +927,16 @@ constructor( if (it.mode == targetMode) { if (activityTransitionUseLargestWindow()) { if (returnAnimationFrameworkLibrary()) { // If the controller contains a cookie, _only_ match if the candidate // contains the matching cookie. // If the controller contains a cookie, _only_ match if either the // candidate contains the matching cookie, or a component is also // defined and is a match. if ( controller.transitionCookie != null && it.taskInfo ?.launchCookies ?.contains(controller.transitionCookie) != true ?.contains(controller.transitionCookie) != true && (controller.component == null || it.taskInfo?.topActivity != controller.component) ) { continue } Loading packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt +13 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.animation import android.content.ComponentName import android.view.View /** A piece of UI that can be expanded into a Dialog or an Activity. */ Loading @@ -28,13 +29,16 @@ interface Expandable { * @param launchCujType The CUJ type from the [com.android.internal.jank.InteractionJankMonitor] * associated to the launch that will use this controller. * @param cookie The unique cookie associated with the launch that will use this controller. * This is required iff the a return animation should be included. * This is required iff a return animation should be included. * @param component The name of the activity that will be launched by this controller. This is * required for long-lived registrations only. * @param returnCujType The CUJ type from the [com.android.internal.jank.InteractionJankMonitor] * associated to the return animation that will use this controller. */ fun activityTransitionController( launchCujType: Int? = null, cookie: ActivityTransitionAnimator.TransitionCookie? = null, component: ComponentName? = null, returnCujType: Int? = null ): ActivityTransitionAnimator.Controller? Loading @@ -47,7 +51,12 @@ interface Expandable { fun activityTransitionController( launchCujType: Int? = null ): ActivityTransitionAnimator.Controller? { return activityTransitionController(launchCujType, cookie = null, returnCujType = null) return activityTransitionController( launchCujType, cookie = null, component = null, returnCujType = null ) } /** Loading @@ -70,12 +79,14 @@ interface Expandable { override fun activityTransitionController( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? ): ActivityTransitionAnimator.Controller? { return ActivityTransitionAnimator.Controller.fromView( view, launchCujType, cookie, component, returnCujType ) } Loading packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.animation import android.content.ComponentName import android.graphics.Canvas import android.graphics.ColorFilter import android.graphics.Insets Loading Loading @@ -62,6 +63,7 @@ constructor( /** The [CujType] associated to this launch animation. */ private val launchCujType: Int? = null, override val transitionCookie: ActivityTransitionAnimator.TransitionCookie? = null, override val component: ComponentName? = null, /** The [CujType] associated to this return animation. */ private val returnCujType: Int? = null, Loading packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt +5 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.compose.animation import android.content.ComponentName import android.view.View import android.view.ViewGroup import android.view.ViewGroupOverlay Loading Loading @@ -136,13 +137,14 @@ internal class ExpandableControllerImpl( override fun activityTransitionController( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? ): ActivityTransitionAnimator.Controller? { if (!isComposed.value) { return null } return activityController(launchCujType, cookie, returnCujType) return activityController(launchCujType, cookie, component, returnCujType) } override fun dialogTransitionController( Loading Loading @@ -170,7 +172,6 @@ internal class ExpandableControllerImpl( override var transitionContainer: ViewGroup = composeViewRoot.rootView as ViewGroup // TODO(b/323863002): update to be dependant on usage. override val isLaunching: Boolean = true override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { Loading Loading @@ -267,6 +268,7 @@ internal class ExpandableControllerImpl( private fun activityController( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? ): ActivityTransitionAnimator.Controller { val delegate = transitionController() Loading @@ -284,6 +286,7 @@ internal class ExpandableControllerImpl( } override val transitionCookie = cookie override val component = component override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) { delegate.onTransitionAnimationStart(isExpandingFullyAbove) Loading packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt +135 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.shared.Flags import com.android.systemui.util.mockito.any import com.android.wm.shell.shared.ShellTransitions import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertFalse import junit.framework.Assert.assertNotNull import junit.framework.Assert.assertNull Loading Loading @@ -202,6 +203,140 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { assertTrue(testShellTransitions.remotesForTakeover.isEmpty()) } @Test fun registersLongLivedTransition() { setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) activityTransitionAnimator.register( object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie_1") override val component = ComponentName("com.test.package", "Test1") } ) assertEquals(2, testShellTransitions.remotes.size) activityTransitionAnimator.register( object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie_2") override val component = ComponentName("com.test.package", "Test2") } ) assertEquals(4, testShellTransitions.remotes.size) } @Test fun registersLongLivedTransitionOverridingPreviousRegistration() { setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) val cookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") activityTransitionAnimator.register( object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = cookie override val component = ComponentName("com.test.package", "Test1") } ) val transitions = testShellTransitions.remotes.values.toList() activityTransitionAnimator.register( object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = cookie override val component = ComponentName("com.test.package", "Test2") } ) assertEquals(2, testShellTransitions.remotes.size) for (transition in transitions) { assertThat(testShellTransitions.remotes.values).doesNotContain(transition) } } @Test fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() { setFlagsRule.disableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) val controller = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") override val component = ComponentName("com.test.package", "Test") } assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.register(controller) } } @Test fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() { setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) // No TransitionCookie val controllerWithoutCookie = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = null } assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.register(controllerWithoutCookie) } // No ComponentName val controllerWithoutComponent = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") override val component = null } assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.register(controllerWithoutComponent) } // No TransitionRegister activityTransitionAnimator = ActivityTransitionAnimator( mainExecutor, transitionRegister = null, testTransitionAnimator, testTransitionAnimator, disableWmTimeout = true, ) val validController = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") override val component = ComponentName("com.test.package", "Test") } assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.register(validController) } } @Test fun unregistersLongLivedTransition() { setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) val cookies = arrayOfNulls<ActivityTransitionAnimator.TransitionCookie>(3) for (index in 0 until 3) { cookies[index] = ActivityTransitionAnimator.TransitionCookie("test_cookie_$index") val controller = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = cookies[index] override val component = ComponentName("foo.bar", "Foobar") } activityTransitionAnimator.register(controller) } activityTransitionAnimator.unregister(cookies[0]!!) assertEquals(4, testShellTransitions.remotes.size) activityTransitionAnimator.unregister(cookies[2]!!) assertEquals(2, testShellTransitions.remotes.size) activityTransitionAnimator.unregister(cookies[1]!!) assertThat(testShellTransitions.remotes).isEmpty() } @Test fun doesNotStartIfAnimationIsCancelled() { val runner = activityTransitionAnimator.createRunner(controller) Loading Loading
packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +117 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.app.ActivityManager import android.app.ActivityTaskManager import android.app.PendingIntent import android.app.TaskInfo import android.app.WindowConfiguration import android.content.ComponentName import android.graphics.Matrix import android.graphics.Rect import android.graphics.RectF Loading @@ -38,7 +40,9 @@ import android.view.View import android.view.ViewGroup import android.view.WindowManager import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.TRANSIT_TO_FRONT import android.view.animation.PathInterpolator import android.window.RemoteTransition import android.window.TransitionFilter Loading Loading @@ -203,6 +207,10 @@ constructor( } } /** Book-keeping for long-lived transitions that are currently registered. */ private val longLivedTransitions = HashMap<TransitionCookie, Pair<RemoteTransition, RemoteTransition>>() /** * Start an intent and animate the opening window. The intent will be started by running * [intentStarter], which should use the provided [RemoteAnimationAdapter] and return the launch Loading Loading @@ -497,6 +505,7 @@ constructor( view: View, cujType: Int? = null, cookie: TransitionCookie? = null, component: ComponentName? = null, returnCujType: Int? = null ): Controller? { // Make sure the View we launch from implements LaunchableView to avoid visibility Loading @@ -519,7 +528,13 @@ constructor( return null } return GhostedViewTransitionAnimatorController(view, cujType, cookie, returnCujType) return GhostedViewTransitionAnimatorController( view, cujType, cookie, component, returnCujType ) } } Loading Loading @@ -553,6 +568,16 @@ constructor( val transitionCookie: TransitionCookie? get() = null /** * The [ComponentName] of the activity whose window is tied to this [Controller]. * * This is used as a fallback when a cookie is defined but there is no match (e.g. when a * matching activity was launched by a mean different from the launchable in this * [Controller]), and should be defined for all long-lived registered [Controller]s. */ val component: ComponentName? get() = null /** * The intent was started. If [willAnimate] is false, nothing else will happen and the * animation will not be started. Loading @@ -571,6 +596,91 @@ constructor( fun onTransitionAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {} } /** * Registers [controller] as a long-lived transition handler for launch and return animations. * * The [controller] will only be used for transitions matching the [TransitionCookie] defined * within it, or the [ComponentName] if the cookie matching fails. Both fields are mandatory for * this registration. */ fun register(controller: Controller) { check(returnAnimationFrameworkLibrary()) { "Long-lived registrations cannot be used when the returnAnimationFrameworkLibrary " + "flag is disabled" } if (transitionRegister == null) { throw IllegalStateException( "A RemoteTransitionRegister must be provided when creating this animator in " + "order to use long-lived animations" ) } val cookie = controller.transitionCookie ?: throw IllegalStateException( "A cookie must be defined in order to use long-lived animations" ) val component = controller.component ?: throw IllegalStateException( "A component must be defined in order to use long-lived animations" ) // Make sure that any previous registrations linked to the same cookie are gone. unregister(cookie) val launchFilter = TransitionFilter().apply { mRequirements = arrayOf( TransitionFilter.Requirement().apply { mActivityType = WindowConfiguration.ACTIVITY_TYPE_STANDARD mModes = intArrayOf(TRANSIT_OPEN, TRANSIT_TO_FRONT) mTopActivity = component } ) } val launchRemoteTransition = RemoteTransition( RemoteAnimationRunnerCompat.wrap(createRunner(controller)), "${cookie}_launchTransition" ) transitionRegister.register(launchFilter, launchRemoteTransition) val returnController = object : Controller by controller { override val isLaunching: Boolean = false } val returnFilter = TransitionFilter().apply { mRequirements = arrayOf( TransitionFilter.Requirement().apply { mActivityType = WindowConfiguration.ACTIVITY_TYPE_STANDARD mModes = intArrayOf(TRANSIT_CLOSE, TRANSIT_TO_BACK) mTopActivity = component } ) } val returnRemoteTransition = RemoteTransition( RemoteAnimationRunnerCompat.wrap(createRunner(returnController)), "${cookie}_returnTransition" ) transitionRegister.register(returnFilter, returnRemoteTransition) longLivedTransitions[cookie] = Pair(launchRemoteTransition, returnRemoteTransition) } /** Unregisters all controllers previously registered that contain [cookie]. */ fun unregister(cookie: TransitionCookie) { val transitions = longLivedTransitions[cookie] ?: return transitionRegister?.unregister(transitions.first) transitionRegister?.unregister(transitions.second) longLivedTransitions.remove(cookie) } /** * Invokes [onAnimationComplete] when animation is either cancelled or completed. Delegates all * events to the passed [delegate]. Loading Loading @@ -817,13 +927,16 @@ constructor( if (it.mode == targetMode) { if (activityTransitionUseLargestWindow()) { if (returnAnimationFrameworkLibrary()) { // If the controller contains a cookie, _only_ match if the candidate // contains the matching cookie. // If the controller contains a cookie, _only_ match if either the // candidate contains the matching cookie, or a component is also // defined and is a match. if ( controller.transitionCookie != null && it.taskInfo ?.launchCookies ?.contains(controller.transitionCookie) != true ?.contains(controller.transitionCookie) != true && (controller.component == null || it.taskInfo?.topActivity != controller.component) ) { continue } Loading
packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt +13 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.animation import android.content.ComponentName import android.view.View /** A piece of UI that can be expanded into a Dialog or an Activity. */ Loading @@ -28,13 +29,16 @@ interface Expandable { * @param launchCujType The CUJ type from the [com.android.internal.jank.InteractionJankMonitor] * associated to the launch that will use this controller. * @param cookie The unique cookie associated with the launch that will use this controller. * This is required iff the a return animation should be included. * This is required iff a return animation should be included. * @param component The name of the activity that will be launched by this controller. This is * required for long-lived registrations only. * @param returnCujType The CUJ type from the [com.android.internal.jank.InteractionJankMonitor] * associated to the return animation that will use this controller. */ fun activityTransitionController( launchCujType: Int? = null, cookie: ActivityTransitionAnimator.TransitionCookie? = null, component: ComponentName? = null, returnCujType: Int? = null ): ActivityTransitionAnimator.Controller? Loading @@ -47,7 +51,12 @@ interface Expandable { fun activityTransitionController( launchCujType: Int? = null ): ActivityTransitionAnimator.Controller? { return activityTransitionController(launchCujType, cookie = null, returnCujType = null) return activityTransitionController( launchCujType, cookie = null, component = null, returnCujType = null ) } /** Loading @@ -70,12 +79,14 @@ interface Expandable { override fun activityTransitionController( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? ): ActivityTransitionAnimator.Controller? { return ActivityTransitionAnimator.Controller.fromView( view, launchCujType, cookie, component, returnCujType ) } Loading
packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.animation import android.content.ComponentName import android.graphics.Canvas import android.graphics.ColorFilter import android.graphics.Insets Loading Loading @@ -62,6 +63,7 @@ constructor( /** The [CujType] associated to this launch animation. */ private val launchCujType: Int? = null, override val transitionCookie: ActivityTransitionAnimator.TransitionCookie? = null, override val component: ComponentName? = null, /** The [CujType] associated to this return animation. */ private val returnCujType: Int? = null, Loading
packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt +5 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.compose.animation import android.content.ComponentName import android.view.View import android.view.ViewGroup import android.view.ViewGroupOverlay Loading Loading @@ -136,13 +137,14 @@ internal class ExpandableControllerImpl( override fun activityTransitionController( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? ): ActivityTransitionAnimator.Controller? { if (!isComposed.value) { return null } return activityController(launchCujType, cookie, returnCujType) return activityController(launchCujType, cookie, component, returnCujType) } override fun dialogTransitionController( Loading Loading @@ -170,7 +172,6 @@ internal class ExpandableControllerImpl( override var transitionContainer: ViewGroup = composeViewRoot.rootView as ViewGroup // TODO(b/323863002): update to be dependant on usage. override val isLaunching: Boolean = true override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { Loading Loading @@ -267,6 +268,7 @@ internal class ExpandableControllerImpl( private fun activityController( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? ): ActivityTransitionAnimator.Controller { val delegate = transitionController() Loading @@ -284,6 +286,7 @@ internal class ExpandableControllerImpl( } override val transitionCookie = cookie override val component = component override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) { delegate.onTransitionAnimationStart(isExpandingFullyAbove) Loading
packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt +135 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.shared.Flags import com.android.systemui.util.mockito.any import com.android.wm.shell.shared.ShellTransitions import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertFalse import junit.framework.Assert.assertNotNull import junit.framework.Assert.assertNull Loading Loading @@ -202,6 +203,140 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { assertTrue(testShellTransitions.remotesForTakeover.isEmpty()) } @Test fun registersLongLivedTransition() { setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) activityTransitionAnimator.register( object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie_1") override val component = ComponentName("com.test.package", "Test1") } ) assertEquals(2, testShellTransitions.remotes.size) activityTransitionAnimator.register( object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie_2") override val component = ComponentName("com.test.package", "Test2") } ) assertEquals(4, testShellTransitions.remotes.size) } @Test fun registersLongLivedTransitionOverridingPreviousRegistration() { setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) val cookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") activityTransitionAnimator.register( object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = cookie override val component = ComponentName("com.test.package", "Test1") } ) val transitions = testShellTransitions.remotes.values.toList() activityTransitionAnimator.register( object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = cookie override val component = ComponentName("com.test.package", "Test2") } ) assertEquals(2, testShellTransitions.remotes.size) for (transition in transitions) { assertThat(testShellTransitions.remotes.values).doesNotContain(transition) } } @Test fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() { setFlagsRule.disableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) val controller = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") override val component = ComponentName("com.test.package", "Test") } assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.register(controller) } } @Test fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() { setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) // No TransitionCookie val controllerWithoutCookie = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = null } assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.register(controllerWithoutCookie) } // No ComponentName val controllerWithoutComponent = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") override val component = null } assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.register(controllerWithoutComponent) } // No TransitionRegister activityTransitionAnimator = ActivityTransitionAnimator( mainExecutor, transitionRegister = null, testTransitionAnimator, testTransitionAnimator, disableWmTimeout = true, ) val validController = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") override val component = ComponentName("com.test.package", "Test") } assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.register(validController) } } @Test fun unregistersLongLivedTransition() { setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) val cookies = arrayOfNulls<ActivityTransitionAnimator.TransitionCookie>(3) for (index in 0 until 3) { cookies[index] = ActivityTransitionAnimator.TransitionCookie("test_cookie_$index") val controller = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = cookies[index] override val component = ComponentName("foo.bar", "Foobar") } activityTransitionAnimator.register(controller) } activityTransitionAnimator.unregister(cookies[0]!!) assertEquals(4, testShellTransitions.remotes.size) activityTransitionAnimator.unregister(cookies[2]!!) assertEquals(2, testShellTransitions.remotes.size) activityTransitionAnimator.unregister(cookies[1]!!) assertThat(testShellTransitions.remotes).isEmpty() } @Test fun doesNotStartIfAnimationIsCancelled() { val runner = activityTransitionAnimator.createRunner(controller) Loading