Loading services/core/java/com/android/server/wm/SurfaceAnimationRunner.java +33 −2 Original line number Original line Diff line number Diff line Loading @@ -67,6 +67,9 @@ class SurfaceAnimationRunner { @VisibleForTesting @VisibleForTesting final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>(); final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>(); @GuardedBy("mLock") private boolean mAnimationStartDeferred; SurfaceAnimationRunner() { SurfaceAnimationRunner() { this(null /* callbackProvider */, null /* animatorFactory */, new Transaction()); this(null /* callbackProvider */, null /* animatorFactory */, new Transaction()); } } Loading @@ -86,13 +89,41 @@ class SurfaceAnimationRunner { : SfValueAnimator::new; : SfValueAnimator::new; } } /** * Defers starting of animations until {@link #continueStartingAnimations} is called. This * method is NOT nestable. * * @see #continueStartingAnimations */ void deferStartingAnimations() { synchronized (mLock) { mAnimationStartDeferred = true; } } /** * Continues starting of animations. * * @see #deferStartingAnimations */ void continueStartingAnimations() { synchronized (mLock) { mAnimationStartDeferred = false; if (!mPendingAnimations.isEmpty()) { mChoreographer.postFrameCallback(this::startAnimations); } } } void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t, void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t, Runnable finishCallback) { Runnable finishCallback) { synchronized (mLock) { synchronized (mLock) { final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash, final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash, finishCallback); finishCallback); mPendingAnimations.put(animationLeash, runningAnim); mPendingAnimations.put(animationLeash, runningAnim); mChoreographer.postFrameCallback(this::stepAnimation); if (!mAnimationStartDeferred) { mChoreographer.postFrameCallback(this::startAnimations); } // Some animations (e.g. move animations) require the initial transform to be applied // Some animations (e.g. move animations) require the initial transform to be applied // immediately. // immediately. Loading Loading @@ -185,7 +216,7 @@ class SurfaceAnimationRunner { a.mAnimSpec.apply(t, a.mLeash, currentPlayTime); a.mAnimSpec.apply(t, a.mLeash, currentPlayTime); } } private void stepAnimation(long frameTimeNanos) { private void startAnimations(long frameTimeNanos) { synchronized (mLock) { synchronized (mLock) { startPendingAnimationsLocked(); startPendingAnimationsLocked(); } } Loading services/core/java/com/android/server/wm/WindowSurfacePlacer.java +22 −15 Original line number Original line Diff line number Diff line Loading @@ -349,21 +349,28 @@ class WindowSurfacePlacer { animLp = null; animLp = null; } } final int layoutRedo; mService.mSurfaceAnimationRunner.deferStartingAnimations(); try { processApplicationsAnimatingInPlace(transit); processApplicationsAnimatingInPlace(transit); mTmpLayerAndToken.token = null; mTmpLayerAndToken.token = null; handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken); handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken); final AppWindowToken topClosingApp = mTmpLayerAndToken.token; final AppWindowToken topClosingApp = mTmpLayerAndToken.token; final AppWindowToken topOpeningApp = handleOpeningApps(transit, animLp, voiceInteraction); final AppWindowToken topOpeningApp = handleOpeningApps(transit, animLp, voiceInteraction); mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp); mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp); final int flags = mService.mAppTransition.getTransitFlags(); final int flags = mService.mAppTransition.getTransitFlags(); int layoutRedo = mService.mAppTransition.goodToGo(transit, topOpeningApp, layoutRedo = mService.mAppTransition.goodToGo(transit, topOpeningApp, topClosingApp, mService.mOpeningApps, mService.mClosingApps); topClosingApp, mService.mOpeningApps, mService.mClosingApps); handleNonAppWindowsInTransition(transit, flags); handleNonAppWindowsInTransition(transit, flags); mService.mAppTransition.postAnimationCallback(); mService.mAppTransition.postAnimationCallback(); mService.mAppTransition.clear(); mService.mAppTransition.clear(); } finally { mService.mSurfaceAnimationRunner.continueStartingAnimations(); } mService.mTaskSnapshotController.onTransitionStarting(); mService.mTaskSnapshotController.onTransitionStarting(); Loading services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +14 −0 Original line number Original line Diff line number Diff line Loading @@ -162,6 +162,20 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase { verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L)); verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L)); } } @Test public void testDeferStartingAnimations() throws Exception { mSurfaceAnimationRunner.deferStartingAnimations(); mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction, this::finishedCallback); waitUntilNextFrame(); assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty()); mSurfaceAnimationRunner.continueStartingAnimations(); waitUntilNextFrame(); assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty()); mFinishCallbackLatch.await(1, SECONDS); assertFinishCallbackCalled(); } private void waitUntilNextFrame() throws Exception { private void waitUntilNextFrame() throws Exception { final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1); mSurfaceAnimationRunner.mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, mSurfaceAnimationRunner.mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, Loading Loading
services/core/java/com/android/server/wm/SurfaceAnimationRunner.java +33 −2 Original line number Original line Diff line number Diff line Loading @@ -67,6 +67,9 @@ class SurfaceAnimationRunner { @VisibleForTesting @VisibleForTesting final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>(); final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>(); @GuardedBy("mLock") private boolean mAnimationStartDeferred; SurfaceAnimationRunner() { SurfaceAnimationRunner() { this(null /* callbackProvider */, null /* animatorFactory */, new Transaction()); this(null /* callbackProvider */, null /* animatorFactory */, new Transaction()); } } Loading @@ -86,13 +89,41 @@ class SurfaceAnimationRunner { : SfValueAnimator::new; : SfValueAnimator::new; } } /** * Defers starting of animations until {@link #continueStartingAnimations} is called. This * method is NOT nestable. * * @see #continueStartingAnimations */ void deferStartingAnimations() { synchronized (mLock) { mAnimationStartDeferred = true; } } /** * Continues starting of animations. * * @see #deferStartingAnimations */ void continueStartingAnimations() { synchronized (mLock) { mAnimationStartDeferred = false; if (!mPendingAnimations.isEmpty()) { mChoreographer.postFrameCallback(this::startAnimations); } } } void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t, void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t, Runnable finishCallback) { Runnable finishCallback) { synchronized (mLock) { synchronized (mLock) { final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash, final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash, finishCallback); finishCallback); mPendingAnimations.put(animationLeash, runningAnim); mPendingAnimations.put(animationLeash, runningAnim); mChoreographer.postFrameCallback(this::stepAnimation); if (!mAnimationStartDeferred) { mChoreographer.postFrameCallback(this::startAnimations); } // Some animations (e.g. move animations) require the initial transform to be applied // Some animations (e.g. move animations) require the initial transform to be applied // immediately. // immediately. Loading Loading @@ -185,7 +216,7 @@ class SurfaceAnimationRunner { a.mAnimSpec.apply(t, a.mLeash, currentPlayTime); a.mAnimSpec.apply(t, a.mLeash, currentPlayTime); } } private void stepAnimation(long frameTimeNanos) { private void startAnimations(long frameTimeNanos) { synchronized (mLock) { synchronized (mLock) { startPendingAnimationsLocked(); startPendingAnimationsLocked(); } } Loading
services/core/java/com/android/server/wm/WindowSurfacePlacer.java +22 −15 Original line number Original line Diff line number Diff line Loading @@ -349,21 +349,28 @@ class WindowSurfacePlacer { animLp = null; animLp = null; } } final int layoutRedo; mService.mSurfaceAnimationRunner.deferStartingAnimations(); try { processApplicationsAnimatingInPlace(transit); processApplicationsAnimatingInPlace(transit); mTmpLayerAndToken.token = null; mTmpLayerAndToken.token = null; handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken); handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken); final AppWindowToken topClosingApp = mTmpLayerAndToken.token; final AppWindowToken topClosingApp = mTmpLayerAndToken.token; final AppWindowToken topOpeningApp = handleOpeningApps(transit, animLp, voiceInteraction); final AppWindowToken topOpeningApp = handleOpeningApps(transit, animLp, voiceInteraction); mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp); mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp); final int flags = mService.mAppTransition.getTransitFlags(); final int flags = mService.mAppTransition.getTransitFlags(); int layoutRedo = mService.mAppTransition.goodToGo(transit, topOpeningApp, layoutRedo = mService.mAppTransition.goodToGo(transit, topOpeningApp, topClosingApp, mService.mOpeningApps, mService.mClosingApps); topClosingApp, mService.mOpeningApps, mService.mClosingApps); handleNonAppWindowsInTransition(transit, flags); handleNonAppWindowsInTransition(transit, flags); mService.mAppTransition.postAnimationCallback(); mService.mAppTransition.postAnimationCallback(); mService.mAppTransition.clear(); mService.mAppTransition.clear(); } finally { mService.mSurfaceAnimationRunner.continueStartingAnimations(); } mService.mTaskSnapshotController.onTransitionStarting(); mService.mTaskSnapshotController.onTransitionStarting(); Loading
services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +14 −0 Original line number Original line Diff line number Diff line Loading @@ -162,6 +162,20 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase { verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L)); verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L)); } } @Test public void testDeferStartingAnimations() throws Exception { mSurfaceAnimationRunner.deferStartingAnimations(); mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction, this::finishedCallback); waitUntilNextFrame(); assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty()); mSurfaceAnimationRunner.continueStartingAnimations(); waitUntilNextFrame(); assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty()); mFinishCallbackLatch.await(1, SECONDS); assertFinishCallbackCalled(); } private void waitUntilNextFrame() throws Exception { private void waitUntilNextFrame() throws Exception { final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1); mSurfaceAnimationRunner.mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, mSurfaceAnimationRunner.mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, Loading