From 16d0d07df83eb00edd719715e6e42d91b600602f Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Mon, 12 Feb 2018 23:50:28 +0000 Subject: [PATCH] Fix flicker with remote animations There was a race condition where we notified the controlling app already about transition start, which itself started the animation and applied the transform of the first frame. However, a little bit later, we applied the pending transaction from window manager, which overrode the properties again, leading to a flicker. Original CL: ag/3535475 Test: go/wm-smoke Test: Press home button, observe never a flicker Bug: Surprisingly there isn't one yet. Change-Id: I84b2e0fd4dcd7a01687e18f428a8f900ed43d75f --- .../server/wm/RemoteAnimationController.java | 18 +++++++++++------- .../android/server/wm/RootWindowContainer.java | 2 ++ .../com/android/server/wm/WindowAnimator.java | 17 ++++++++++++++++- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index c353c1d36d600..ae0f412a99bbd 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -96,13 +96,17 @@ class RemoteAnimationController { // Scale the timeout with the animator scale the controlling app is using. mHandler.postDelayed(mTimeoutRunnable, (long) (TIMEOUT_MS * mService.getCurrentAnimatorScale())); - try { - mRemoteAnimationAdapter.getRunner().onAnimationStart(createAnimations(), - mFinishedCallback); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to start remote animation", e); - onAnimationFinished(); - } + + final RemoteAnimationTarget[] animations = createAnimations(); + mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { + try { + mRemoteAnimationAdapter.getRunner().onAnimationStart(animations, + mFinishedCallback); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to start remote animation", e); + onAnimationFinished(); + } + }); } private RemoteAnimationTarget[] createAnimations() { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index f5760e593f375..3d60ee4b5e1ee 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -588,6 +588,8 @@ class RootWindowContainer extends WindowContainer { "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces"); } + mService.mAnimator.executeAfterPrepareSurfacesRunnables(); + final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked; // If we are ready to perform an app transition, check through all of the app tokens to be diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 49a30d5382c33..20349b990dfea 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -92,6 +92,7 @@ public class WindowAnimator { * executed and the corresponding transaction is closed and applied. */ private final ArrayList mAfterPrepareSurfacesRunnables = new ArrayList<>(); + private boolean mInExecuteAfterPrepareSurfacesRunnables; WindowAnimator(final WindowManagerService service) { mService = service; @@ -434,11 +435,24 @@ public class WindowAnimator { * the corresponding transaction is closed and applied. */ void addAfterPrepareSurfacesRunnable(Runnable r) { + // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just + // immediately execute the runnable passed in. + if (mInExecuteAfterPrepareSurfacesRunnables) { + r.run(); + return; + } + mAfterPrepareSurfacesRunnables.add(r); scheduleAnimation(); } - private void executeAfterPrepareSurfacesRunnables() { + void executeAfterPrepareSurfacesRunnables() { + + // Don't even think about to start recursing! + if (mInExecuteAfterPrepareSurfacesRunnables) { + return; + } + mInExecuteAfterPrepareSurfacesRunnables = true; // Traverse in order they were added. final int size = mAfterPrepareSurfacesRunnables.size(); @@ -446,5 +460,6 @@ public class WindowAnimator { mAfterPrepareSurfacesRunnables.get(i).run(); } mAfterPrepareSurfacesRunnables.clear(); + mInExecuteAfterPrepareSurfacesRunnables = false; } }