Loading packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +469 −76 File changed.Preview size limit exceeded, changes collapsed. Show changes packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt +20 −5 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting import com.android.internal.dynamicanimation.animation.SpringAnimation import com.android.internal.dynamicanimation.animation.SpringForce import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived import java.util.concurrent.Executor import kotlin.math.abs import kotlin.math.max Loading Loading @@ -113,13 +114,26 @@ class TransitionAnimator( ) } internal fun checkReturnAnimationFrameworkFlag() { check(returnAnimationFrameworkLibrary()) { "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag is " + "disabled" internal fun assertReturnAnimations() { check(returnAnimationsEnabled()) { "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag " + "is disabled" } } internal fun returnAnimationsEnabled() = returnAnimationFrameworkLibrary() internal fun assertLongLivedReturnAnimations() { check(longLivedReturnAnimationsEnabled()) { "Long-lived registrations cannot be used when the " + "returnAnimationFrameworkLibrary or the " + "returnAnimationFrameworkLongLived flag are disabled" } } internal fun longLivedReturnAnimationsEnabled() = returnAnimationFrameworkLibrary() && returnAnimationFrameworkLongLived() internal fun WindowAnimationState.toTransitionState() = State().also { bounds?.let { b -> Loading Loading @@ -467,7 +481,8 @@ class TransitionAnimator( drawHole: Boolean = false, startVelocity: PointF? = null, ): Animation { if (!controller.isLaunching || startVelocity != null) checkReturnAnimationFrameworkFlag() if (!controller.isLaunching) assertReturnAnimations() if (startVelocity != null) assertLongLivedReturnAnimations() // We add an extra layer with the same color as the dialog/app splash screen background // color, which is usually the same color of the app background. We first fade in this layer Loading packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt +123 −6 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ import android.view.RemoteAnimationAdapter import android.view.RemoteAnimationTarget import android.view.SurfaceControl import android.view.ViewGroup import android.view.WindowManager.TRANSIT_NONE import android.widget.FrameLayout import android.widget.LinearLayout import android.window.RemoteTransition import android.window.TransitionFilter import android.window.WindowAnimationState import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading @@ -34,6 +36,10 @@ import junit.framework.Assert.assertTrue import junit.framework.AssertionFailedError import kotlin.concurrent.thread import kotlin.test.assertEquals import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout import org.junit.After import org.junit.Assert.assertThrows import org.junit.Before Loading Loading @@ -258,7 +264,6 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @DisableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() { val controller = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = Loading @@ -273,7 +278,6 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() { // No TransitionCookie val controllerWithoutCookie = object : DelegateTransitionAnimatorController(controller) { Loading Loading @@ -348,7 +352,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { fun doesNotStartIfAnimationIsCancelled() { val runner = activityTransitionAnimator.createRunner(controller) runner.onAnimationCancelled() runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback) runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) waitForIdleSync() verify(controller).onTransitionAnimationCancelled() Loading @@ -361,7 +365,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun cancelsIfNoOpeningWindowIsFound() { val runner = activityTransitionAnimator.createRunner(controller) runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback) runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) waitForIdleSync() verify(controller).onTransitionAnimationCancelled() Loading @@ -374,7 +378,13 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun startsAnimationIfWindowIsOpening() { val runner = activityTransitionAnimator.createRunner(controller) runner.onAnimationStart(0, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback) runner.onAnimationStart( TRANSIT_NONE, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback, ) waitForIdleSync() verify(listener).onTransitionAnimationStart() verify(controller).onTransitionAnimationStart(anyBoolean()) Loading @@ -387,6 +397,113 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { } } @DisableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun creatingRunnerWithLazyInitializationThrows_whenTheFlagsAreDisabled() { assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.createRunner(controller, initializeLazily = true) } } @EnableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun runnerCreatesDelegateLazily_whenPostingTimeouts() { val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true) assertNull(runner.delegate) runner.postTimeouts() assertNotNull(runner.delegate) } @EnableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun runnerCreatesDelegateLazily_onAnimationStart() { val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true) assertNull(runner.delegate) // The delegate is cleaned up after execution (which happens in another thread), so what we // do instead is check if it becomes non-null at any point with a 1 second timeout. This // will tell us that takeOverWithAnimation() triggered the lazy initialization. var delegateInitialized = false runBlocking { val initChecker = launch { withTimeout(1.seconds) { while (runner.delegate == null) continue delegateInitialized = true } } runner.onAnimationStart( TRANSIT_NONE, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback, ) initChecker.join() } assertTrue(delegateInitialized) } @EnableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun runnerCreatesDelegateLazily_onAnimationTakeover() { val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true) assertNull(runner.delegate) // The delegate is cleaned up after execution (which happens in another thread), so what we // do instead is check if it becomes non-null at any point with a 1 second timeout. This // will tell us that takeOverWithAnimation() triggered the lazy initialization. var delegateInitialized = false runBlocking { val initChecker = launch { withTimeout(1.seconds) { while (runner.delegate == null) continue delegateInitialized = true } } runner.takeOverAnimation( arrayOf(fakeWindow()), arrayOf(WindowAnimationState()), SurfaceControl.Transaction(), iCallback, ) initChecker.join() } assertTrue(delegateInitialized) } @DisableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun animationTakeoverThrows_whenTheFlagsAreDisabled() { val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = false) assertThrows(IllegalStateException::class.java) { runner.takeOverAnimation( arrayOf(fakeWindow()), emptyArray(), SurfaceControl.Transaction(), iCallback, ) } } @DisableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun disposeRunner_delegateDereferenced() { val runner = activityTransitionAnimator.createRunner(controller) Loading @@ -409,7 +526,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { false, Rect(), Rect(), 0, 1, Point(), Rect(), bounds, Loading Loading
packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +469 −76 File changed.Preview size limit exceeded, changes collapsed. Show changes
packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt +20 −5 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting import com.android.internal.dynamicanimation.animation.SpringAnimation import com.android.internal.dynamicanimation.animation.SpringForce import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived import java.util.concurrent.Executor import kotlin.math.abs import kotlin.math.max Loading Loading @@ -113,13 +114,26 @@ class TransitionAnimator( ) } internal fun checkReturnAnimationFrameworkFlag() { check(returnAnimationFrameworkLibrary()) { "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag is " + "disabled" internal fun assertReturnAnimations() { check(returnAnimationsEnabled()) { "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag " + "is disabled" } } internal fun returnAnimationsEnabled() = returnAnimationFrameworkLibrary() internal fun assertLongLivedReturnAnimations() { check(longLivedReturnAnimationsEnabled()) { "Long-lived registrations cannot be used when the " + "returnAnimationFrameworkLibrary or the " + "returnAnimationFrameworkLongLived flag are disabled" } } internal fun longLivedReturnAnimationsEnabled() = returnAnimationFrameworkLibrary() && returnAnimationFrameworkLongLived() internal fun WindowAnimationState.toTransitionState() = State().also { bounds?.let { b -> Loading Loading @@ -467,7 +481,8 @@ class TransitionAnimator( drawHole: Boolean = false, startVelocity: PointF? = null, ): Animation { if (!controller.isLaunching || startVelocity != null) checkReturnAnimationFrameworkFlag() if (!controller.isLaunching) assertReturnAnimations() if (startVelocity != null) assertLongLivedReturnAnimations() // We add an extra layer with the same color as the dialog/app splash screen background // color, which is usually the same color of the app background. We first fade in this layer Loading
packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt +123 −6 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ import android.view.RemoteAnimationAdapter import android.view.RemoteAnimationTarget import android.view.SurfaceControl import android.view.ViewGroup import android.view.WindowManager.TRANSIT_NONE import android.widget.FrameLayout import android.widget.LinearLayout import android.window.RemoteTransition import android.window.TransitionFilter import android.window.WindowAnimationState import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading @@ -34,6 +36,10 @@ import junit.framework.Assert.assertTrue import junit.framework.AssertionFailedError import kotlin.concurrent.thread import kotlin.test.assertEquals import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout import org.junit.After import org.junit.Assert.assertThrows import org.junit.Before Loading Loading @@ -258,7 +264,6 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @DisableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() { val controller = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = Loading @@ -273,7 +278,6 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() { // No TransitionCookie val controllerWithoutCookie = object : DelegateTransitionAnimatorController(controller) { Loading Loading @@ -348,7 +352,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { fun doesNotStartIfAnimationIsCancelled() { val runner = activityTransitionAnimator.createRunner(controller) runner.onAnimationCancelled() runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback) runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) waitForIdleSync() verify(controller).onTransitionAnimationCancelled() Loading @@ -361,7 +365,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun cancelsIfNoOpeningWindowIsFound() { val runner = activityTransitionAnimator.createRunner(controller) runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback) runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) waitForIdleSync() verify(controller).onTransitionAnimationCancelled() Loading @@ -374,7 +378,13 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun startsAnimationIfWindowIsOpening() { val runner = activityTransitionAnimator.createRunner(controller) runner.onAnimationStart(0, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback) runner.onAnimationStart( TRANSIT_NONE, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback, ) waitForIdleSync() verify(listener).onTransitionAnimationStart() verify(controller).onTransitionAnimationStart(anyBoolean()) Loading @@ -387,6 +397,113 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { } } @DisableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun creatingRunnerWithLazyInitializationThrows_whenTheFlagsAreDisabled() { assertThrows(IllegalStateException::class.java) { activityTransitionAnimator.createRunner(controller, initializeLazily = true) } } @EnableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun runnerCreatesDelegateLazily_whenPostingTimeouts() { val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true) assertNull(runner.delegate) runner.postTimeouts() assertNotNull(runner.delegate) } @EnableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun runnerCreatesDelegateLazily_onAnimationStart() { val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true) assertNull(runner.delegate) // The delegate is cleaned up after execution (which happens in another thread), so what we // do instead is check if it becomes non-null at any point with a 1 second timeout. This // will tell us that takeOverWithAnimation() triggered the lazy initialization. var delegateInitialized = false runBlocking { val initChecker = launch { withTimeout(1.seconds) { while (runner.delegate == null) continue delegateInitialized = true } } runner.onAnimationStart( TRANSIT_NONE, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback, ) initChecker.join() } assertTrue(delegateInitialized) } @EnableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun runnerCreatesDelegateLazily_onAnimationTakeover() { val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true) assertNull(runner.delegate) // The delegate is cleaned up after execution (which happens in another thread), so what we // do instead is check if it becomes non-null at any point with a 1 second timeout. This // will tell us that takeOverWithAnimation() triggered the lazy initialization. var delegateInitialized = false runBlocking { val initChecker = launch { withTimeout(1.seconds) { while (runner.delegate == null) continue delegateInitialized = true } } runner.takeOverAnimation( arrayOf(fakeWindow()), arrayOf(WindowAnimationState()), SurfaceControl.Transaction(), iCallback, ) initChecker.join() } assertTrue(delegateInitialized) } @DisableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun animationTakeoverThrows_whenTheFlagsAreDisabled() { val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = false) assertThrows(IllegalStateException::class.java) { runner.takeOverAnimation( arrayOf(fakeWindow()), emptyArray(), SurfaceControl.Transaction(), iCallback, ) } } @DisableFlags( Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, ) @Test fun disposeRunner_delegateDereferenced() { val runner = activityTransitionAnimator.createRunner(controller) Loading @@ -409,7 +526,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { false, Rect(), Rect(), 0, 1, Point(), Rect(), bounds, Loading