am 5284dd8d: am 91283969: Merge "Fixing crash in recents window transition.  (Bug 18246975, 18159006)" into lmp-mr1-dev

* commit '5284dd8d6933156ee785d3270754cc6671252625':
  Fixing crash in recents window transition.  (Bug 18246975, 18159006)
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index bfc7659..eeb007c 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 @@
                 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 69c9144..bf96ea5 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 @@
     // 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 @@
     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<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<WindowStateAnimator>();
@@ -134,9 +135,7 @@
             animation = null;
             animating = true;
         }
-        if (!deferThumbnailDestruction) {
-            clearThumbnail();
-        }
+        clearThumbnail();
         if (mAppToken.deferClearAllDrawn) {
             mAppToken.allDrawn = false;
             mAppToken.deferClearAllDrawn = false;
@@ -148,13 +147,7 @@
             thumbnail.destroy();
             thumbnail = null;
         }
-    }
-
-    public void clearDeferredThumbnail() {
-        if (deferredThumbnail != null) {
-            deferredThumbnail.destroy();
-            deferredThumbnail = null;
-        }
+        deferThumbnailDestruction = false;
     }
 
     void updateLayers() {
@@ -223,19 +216,26 @@
             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 ccb5bfc..968b35c 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 @@
                                 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 e7c235f..1dadb17 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 @@
             mWin.mHasSurface = false;
             mDrawState = NO_SURFACE;
         }
-
-        // Destroy any deferred thumbnail surfaces
-        if (mAppAnimator != null) {
-            mAppAnimator.clearDeferredThumbnail();
-        }
     }
 
     void destroyDeferredSurfaceLocked() {