diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index bfc7659ea7f04..eeb007c33f6e3 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -691,8 +691,10 @@ public class AppTransition implements Dump { throw new RuntimeException("Invalid thumbnail transition state"); } - return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, - THUMBNAIL_APP_TRANSITION_DURATION, mThumbnailFastOutSlowInInterpolator); + int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION, + THUMBNAIL_APP_TRANSITION_DURATION); + return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, + mThumbnailFastOutSlowInInterpolator); } /** diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java index 69c914486f35f..bf96ea568bfa2 100644 --- a/services/core/java/com/android/server/wm/AppWindowAnimator.java +++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java @@ -58,7 +58,9 @@ public class AppWindowAnimator { // the state changes. boolean allDrawn; - // Special surface for thumbnail animation. + // Special surface for thumbnail animation. If deferThumbnailDestruction is enabled, then we + // will make sure that the thumbnail is destroyed after the other surface is completed. This + // requires that the duration of the two animations are the same. SurfaceControl thumbnail; int thumbnailTransactionSeq; int thumbnailX; @@ -68,13 +70,12 @@ public class AppWindowAnimator { Animation thumbnailAnimation; final Transformation thumbnailTransformation = new Transformation(); // This flag indicates that the destruction of the thumbnail surface is synchronized with - // another animation, so do not pre-emptively destroy the thumbnail surface when the animation - // completes + // another animation, so defer the destruction of this thumbnail surface for a single frame + // after the secondary animation completes. boolean deferThumbnailDestruction; - // This is the thumbnail surface that has been bestowed upon this animator, and when the - // surface for this animator's animation is complete, we will destroy the thumbnail surface - // as well. Do not animate or do anything with this surface. - SurfaceControl deferredThumbnail; + // This flag is set if the animator has deferThumbnailDestruction set and has reached the final + // frame of animation. It will extend the animation by one frame and then clean up afterwards. + boolean deferFinalFrameCleanup; /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */ ArrayList mAllAppWinAnimators = new ArrayList(); @@ -134,9 +135,7 @@ public class AppWindowAnimator { animation = null; animating = true; } - if (!deferThumbnailDestruction) { - clearThumbnail(); - } + clearThumbnail(); if (mAppToken.deferClearAllDrawn) { mAppToken.allDrawn = false; mAppToken.deferClearAllDrawn = false; @@ -148,13 +147,7 @@ public class AppWindowAnimator { thumbnail.destroy(); thumbnail = null; } - } - - public void clearDeferredThumbnail() { - if (deferredThumbnail != null) { - deferredThumbnail.destroy(); - deferredThumbnail = null; - } + deferThumbnailDestruction = false; } void updateLayers() { @@ -223,19 +216,26 @@ public class AppWindowAnimator { return false; } transformation.clear(); - final boolean more = animation.getTransformation(currentTime, transformation); - if (false && WindowManagerService.DEBUG_ANIM) Slog.v( - TAG, "Stepped animation in " + mAppToken + ": more=" + more + ", xform=" + transformation); - if (!more) { - animation = null; - if (!deferThumbnailDestruction) { + boolean hasMoreFrames = animation.getTransformation(currentTime, transformation); + if (!hasMoreFrames) { + if (deferThumbnailDestruction && !deferFinalFrameCleanup) { + // We are deferring the thumbnail destruction, so extend the animation for one more + // (dummy) frame before we clean up + deferFinalFrameCleanup = true; + hasMoreFrames = true; + } else { + if (false && WindowManagerService.DEBUG_ANIM) Slog.v( + TAG, "Stepped animation in " + mAppToken + ": more=" + hasMoreFrames + + ", xform=" + transformation); + deferFinalFrameCleanup = false; + animation = null; clearThumbnail(); + if (WindowManagerService.DEBUG_ANIM) Slog.v( + TAG, "Finished animation in " + mAppToken + " @ " + currentTime); } - if (WindowManagerService.DEBUG_ANIM) Slog.v( - TAG, "Finished animation in " + mAppToken + " @ " + currentTime); } - hasTransformation = more; - return more; + hasTransformation = hasMoreFrames; + return hasMoreFrames; } // This must be called while inside a transaction. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ccb5bfce59038..968b35c3c3d01 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -9244,12 +9244,6 @@ public class WindowManagerService extends IWindowManager.Stub topClosingLayer); openingAppAnimator.deferThumbnailDestruction = !mAppTransition.isNextThumbnailTransitionScaleUp(); - if (openingAppAnimator.deferThumbnailDestruction) { - if (closingAppAnimator != null && - closingAppAnimator.animation != null) { - closingAppAnimator.deferredThumbnail = surfaceControl; - } - } } else { anim = mAppTransition.createThumbnailScaleAnimationLocked( displayInfo.appWidth, displayInfo.appHeight, transit); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index e7c235f95d63a..1dadb17c0e28d 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -975,11 +975,6 @@ class WindowStateAnimator { mWin.mHasSurface = false; mDrawState = NO_SURFACE; } - - // Destroy any deferred thumbnail surfaces - if (mAppAnimator != null) { - mAppAnimator.clearDeferredThumbnail(); - } } void destroyDeferredSurfaceLocked() {