Merge changes I2ff9bd44,I946e681e,If72df07b

* changes:
  Handle content insets for snapshots
  Always remove starting window in performShow
  Initial implementation of snapshots
diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl
index 5672f6b..29260e9 100644
--- a/core/java/android/app/ActivityManager.aidl
+++ b/core/java/android/app/ActivityManager.aidl
@@ -26,4 +26,6 @@
 /** @hide */
 parcelable ActivityManager.StackInfo;
 /** @hide */
-parcelable ActivityManager.TaskThumbnail;
\ No newline at end of file
+parcelable ActivityManager.TaskThumbnail;
+/** @hide */
+parcelable ActivityManager.TaskSnapshot;
\ No newline at end of file
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9037304..3170d0d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -26,6 +26,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
+import android.graphics.GraphicBuffer;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.os.BatteryStats;
@@ -125,6 +126,16 @@
 
     private static volatile boolean sSystemReady = false;
 
+    /**
+     * System property to enable task snapshots.
+     * @hide
+     */
+    public final static boolean ENABLE_TASK_SNAPSHOTS;
+
+    static {
+        ENABLE_TASK_SNAPSHOTS = SystemProperties.getBoolean("persist.enable_task_snapshots", false);
+    }
+
     static final class UidObserver extends IUidObserver.Stub {
         final OnUidImportanceListener mListener;
 
@@ -2115,6 +2126,62 @@
         };
     }
 
+    /**
+     * Represents a task snapshot.
+     * @hide
+     */
+    public static class TaskSnapshot implements Parcelable {
+
+        private final GraphicBuffer mSnapshot;
+        private final int mOrientation;
+        private final Rect mContentInsets;
+
+        public TaskSnapshot(GraphicBuffer snapshot, int orientation, Rect contentInsets) {
+            mSnapshot = snapshot;
+            mOrientation = orientation;
+            mContentInsets = new Rect(contentInsets);
+        }
+
+        private TaskSnapshot(Parcel source) {
+            mSnapshot = source.readParcelable(null /* classLoader */);
+            mOrientation = source.readInt();
+            mContentInsets = source.readParcelable(null /* classLoader */);
+        }
+
+        public GraphicBuffer getSnapshot() {
+            return mSnapshot;
+        }
+
+        public int getOrientation() {
+            return mOrientation;
+        }
+
+        public Rect getContentInsets() {
+            return mContentInsets;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeParcelable(mSnapshot, 0);
+            dest.writeInt(mOrientation);
+            dest.writeParcelable(mContentInsets, 0);
+        }
+
+        public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
+            public TaskSnapshot createFromParcel(Parcel source) {
+                return new TaskSnapshot(source);
+            }
+            public TaskSnapshot[] newArray(int size) {
+                return new TaskSnapshot[size];
+            }
+        };
+    }
+
     /** @hide */
     public TaskThumbnail getTaskThumbnail(int id) throws SecurityException {
         try {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 2ed9eab..21ae853 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -53,6 +53,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.net.Uri;
@@ -596,6 +597,11 @@
     /** Cancels the thumbnail transitions for the given task. */
     void cancelTaskThumbnailTransition(int taskId);
 
+    /**
+     * @return a graphic buffer representing a screenshot of a task
+     */
+    ActivityManager.TaskSnapshot getTaskSnapshot(int taskId);
+
     // WARNING: when these transactions are updated, check if they are any callers on the native
     // side. If so, make sure they are using the correct transaction ids and arguments.
     // If a transaction which will also be used on the native side is being inserted, add it
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c0ebd2c..19edb5c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -48,6 +48,7 @@
 import android.view.IInputFilter;
 import android.view.AppTransitionAnimationSpec;
 import android.view.WindowContentFrameStats;
+import android.view.WindowManager;
 
 /**
  * System private interface to the window manager.
diff --git a/core/java/android/view/WindowManager.aidl b/core/java/android/view/WindowManager.aidl
index 556dc72..1363f05 100644
--- a/core/java/android/view/WindowManager.aidl
+++ b/core/java/android/view/WindowManager.aidl
@@ -18,4 +18,5 @@
 package android.view;
 
 parcelable WindowManager.LayoutParams;
-
+/** @hide */
+parcelable WindowManager.TaskSnapshot;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index aa7631d..e5a6ebd 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -22,6 +22,7 @@
 import android.app.Presentation;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.IBinder;
@@ -1319,6 +1320,17 @@
         public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00040000;
 
         /**
+         * Flag to indicate that this window is used as a task snapshot window. A task snapshot
+         * window is a starting window that gets shown with a screenshot from the previous state
+         * that is active until the app has drawn its first frame.
+         *
+         * <p>If this flag is set, SystemUI flags are ignored such that the real window behind can
+         * set the SystemUI flags.
+         * @hide
+         */
+        public static final int PRIVATE_FLAG_TASK_SNAPSHOT = 0x00080000;
+
+        /**
          * Control flags that are private to the platform.
          * @hide
          */
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index dd85256..3748134 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -439,10 +439,15 @@
     /**
      * Holds the contents of a starting window. {@link #addSplashScreen} needs to wrap the
      * contents of the starting window into an class implementing this interface, which then will be
-     * held by WM and passed into {@link #removeSplashScreen} when the starting window is no
-     * longer needed.
+     * held by WM and released with {@link #remove} when no longer needed.
      */
     interface StartingSurface {
+
+        /**
+         * Removes the starting window surface. Do not hold the window manager lock when calling
+         * this method!
+         */
+        void remove();
     }
 
     /**
@@ -746,35 +751,14 @@
      * @param overrideConfig override configuration to consider when generating
      *        context to for resources.
      *
-     * @return Optionally you can return the View that was used to create the
-     *         window, for easy removal in removeSplashScreen.
+     * @return The starting surface.
      *
-     * @see #removeSplashScreen
      */
     public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
             int logo, int windowFlags, Configuration overrideConfig);
 
     /**
-     * Called when the first window of an application has been displayed, while
-     * {@link #addSplashScreen} has created a temporary initial window for
-     * that application.  You should at this point remove the window from the
-     * window manager.  This is called without the window manager locked so
-     * that you can call back into it.
-     *
-     * <p>Note: due to the nature of these functions not being called with the
-     * window manager locked, you must be prepared for this function to be
-     * called multiple times and/or an initial time with a null View window
-     * even if you previously returned one.
-     *
-     * @param appToken Token of the application that has started.
-     * @param surface Surface that was returned by {@link #addSplashScreen}.
-     *
-     * @see #addSplashScreen
-     */
-    public void removeSplashScreen(IBinder appToken, StartingSurface surface);
-
-    /**
      * Prepare for a window being added to the window manager.  You can throw an
      * exception here to prevent the window being added, or do whatever setup
      * you need to keep track of the window.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 7791132..3587b89 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -28,7 +28,7 @@
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
-import android.app.ITaskStackListener;
+import android.app.KeyguardManager;
 import android.app.UiModeManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -74,7 +74,6 @@
 import android.view.WindowManager.KeyboardShortcutsReceiver;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
-import android.app.KeyguardManager;
 
 import com.android.internal.app.AssistUtils;
 import com.android.internal.os.BackgroundThread;
@@ -603,7 +602,7 @@
         }
 
         getThumbnail(taskId, thumbnailData);
-        if (thumbnailData.thumbnail != null) {
+        if (thumbnailData.thumbnail != null && !ActivityManager.ENABLE_TASK_SNAPSHOTS) {
             thumbnailData.thumbnail.setHasAlpha(false);
             // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
             // left pixel, then assume the whole thumbnail is transparent. Generally, proper
@@ -627,25 +626,42 @@
             return;
         }
 
-        ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId);
-        if (taskThumbnail == null) {
-            return;
-        }
-
-        Bitmap thumbnail = taskThumbnail.mainThumbnail;
-        ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor;
-        if (thumbnail == null && descriptor != null) {
-            thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor(),
-                    null, sBitmapOptions);
-        }
-        if (descriptor != null) {
+        if (ActivityManager.ENABLE_TASK_SNAPSHOTS) {
+            ActivityManager.TaskSnapshot snapshot = null;
             try {
-                descriptor.close();
-            } catch (IOException e) {
+                snapshot = ActivityManager.getService().getTaskSnapshot(taskId);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to retrieve snapshot", e);
             }
+            if (snapshot != null) {
+                thumbnailDataOut.thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot());
+                thumbnailDataOut.orientation = snapshot.getOrientation();
+                thumbnailDataOut.insets.set(snapshot.getContentInsets());
+            } else {
+                thumbnailDataOut.thumbnail = null;
+            }
+        } else {
+            ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId);
+            if (taskThumbnail == null) {
+                return;
+            }
+
+            Bitmap thumbnail = taskThumbnail.mainThumbnail;
+            ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor;
+            if (thumbnail == null && descriptor != null) {
+                thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor(),
+                        null, sBitmapOptions);
+            }
+            if (descriptor != null) {
+                try {
+                    descriptor.close();
+                } catch (IOException e) {
+                }
+            }
+            thumbnailDataOut.thumbnail = thumbnail;
+            thumbnailDataOut.orientation = taskThumbnail.thumbnailInfo.screenOrientation;
+            thumbnailDataOut.insets.setEmpty();
         }
-        thumbnailDataOut.thumbnail = thumbnail;
-        thumbnailDataOut.thumbnailInfo = taskThumbnail.thumbnailInfo;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index ba31e3e..6ea51e5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -220,8 +220,7 @@
                             mMainThreadHandler.post(new Runnable() {
                                 @Override
                                 public void run() {
-                                    t.notifyTaskDataLoaded(newThumbnailData.thumbnail, newIcon,
-                                            newThumbnailData.thumbnailInfo);
+                                    t.notifyTaskDataLoaded(newThumbnailData, newIcon);
                                 }
                             });
                         }
@@ -364,11 +363,9 @@
     public void loadTaskData(Task t) {
         Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
         Bitmap thumbnail = null;
-        ActivityManager.TaskThumbnailInfo thumbnailInfo = null;
         ThumbnailData thumbnailData = mThumbnailCache.getAndInvalidateIfModified(t.key);
         if (thumbnailData != null) {
             thumbnail = thumbnailData.thumbnail;
-            thumbnailInfo = thumbnailData.thumbnailInfo;
         }
 
         // Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and
@@ -378,8 +375,7 @@
         if (requiresLoad) {
             mLoadQueue.addTask(t);
         }
-        t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, icon,
-                thumbnailInfo);
+        t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnailData, icon);
     }
 
     /** Releases the task resource data back into the pool. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 53f713a..2f2e866 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -45,7 +45,7 @@
     /* Task callbacks */
     public interface TaskCallbacks {
         /* Notifies when a task has been bound */
-        public void onTaskDataLoaded(Task task, ActivityManager.TaskThumbnailInfo thumbnailInfo);
+        public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
         /* Notifies when a task has been unbound */
         public void onTaskDataUnloaded();
         /* Notifies when a task's stack id has changed. */
@@ -299,13 +299,12 @@
     }
 
     /** Notifies the callback listeners that this task has been loaded */
-    public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon,
-            ActivityManager.TaskThumbnailInfo thumbnailInfo) {
+    public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) {
         this.icon = applicationIcon;
-        this.thumbnail = thumbnail;
+        this.thumbnail = thumbnailData != null ? thumbnailData.thumbnail : null;
         int callbackCount = mCallbacks.size();
         for (int i = 0; i < callbackCount; i++) {
-            mCallbacks.get(i).onTaskDataLoaded(this, thumbnailInfo);
+            mCallbacks.get(i).onTaskDataLoaded(this, thumbnailData);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
index d0cdae5..18735ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
@@ -16,13 +16,14 @@
 
 package com.android.systemui.recents.model;
 
-import android.app.ActivityManager;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 
 /**
  * Data for a single thumbnail.
  */
 public class ThumbnailData {
     public Bitmap thumbnail;
-    public ActivityManager.TaskThumbnailInfo thumbnailInfo;
+    public int orientation;
+    public final Rect insets = new Rect();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 36d5f83..5f37349 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -57,6 +57,7 @@
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.model.ThumbnailData;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -620,9 +621,9 @@
     }
 
     @Override
-    public void onTaskDataLoaded(Task task, ActivityManager.TaskThumbnailInfo thumbnailInfo) {
+    public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
         // Update each of the views to the new task data
-        mThumbnailView.onTaskDataLoaded(thumbnailInfo);
+        mThumbnailView.onTaskDataLoaded(thumbnailData);
         mHeaderView.onTaskDataLoaded();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 58b929a..3ae51b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.recents.views;
 
-import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
@@ -37,7 +36,7 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
-
+import com.android.systemui.recents.model.ThumbnailData;
 import java.io.PrintWriter;
 
 
@@ -65,12 +64,12 @@
     private float mFullscreenThumbnailScale;
     private boolean mSizeToFit = false;
     private boolean mOverlayHeaderOnThumbnailActionBar = true;
-    private ActivityManager.TaskThumbnailInfo mThumbnailInfo;
+    private ThumbnailData mThumbnailData;
 
     private int mCornerRadius;
     @ViewDebug.ExportedProperty(category="recents")
     private float mDimAlpha;
-    private Matrix mScaleMatrix = new Matrix();
+    private Matrix mMatrix = new Matrix();
     private Paint mDrawPaint = new Paint();
     private Paint mLockedPaint = new Paint();
     private Paint mBgFillPaint = new Paint();
@@ -125,7 +124,7 @@
 
         mTaskViewRect.set(0, 0, width, height);
         setLeftTopRightBottom(0, 0, width, height);
-        updateThumbnailScale();
+        updateThumbnailMatrix();
     }
 
     @Override
@@ -174,19 +173,22 @@
     }
 
     /** Sets the thumbnail to a given bitmap. */
-    void setThumbnail(Bitmap bm, ActivityManager.TaskThumbnailInfo thumbnailInfo) {
-        if (bm != null) {
+    void setThumbnail(ThumbnailData thumbnailData) {
+        if (thumbnailData != null && thumbnailData.thumbnail != null) {
+            Bitmap bm = thumbnailData.thumbnail;
             bm.prepareToDraw();
             mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
             mDrawPaint.setShader(mBitmapShader);
-            mThumbnailRect.set(0, 0, bm.getWidth(), bm.getHeight());
-            mThumbnailInfo = thumbnailInfo;
-            updateThumbnailScale();
+            mThumbnailRect.set(0, 0,
+                    bm.getWidth() - thumbnailData.insets.left - thumbnailData.insets.right,
+                    bm.getHeight() - thumbnailData.insets.top - thumbnailData.insets.bottom);
+            mThumbnailData = thumbnailData;
+            updateThumbnailMatrix();
         } else {
             mBitmapShader = null;
             mDrawPaint.setShader(null);
             mThumbnailRect.setEmpty();
-            mThumbnailInfo = null;
+            mThumbnailData = null;
         }
     }
 
@@ -233,21 +235,21 @@
     /**
      * Updates the scale of the bitmap relative to this view.
      */
-    public void updateThumbnailScale() {
+    public void updateThumbnailMatrix() {
         mThumbnailScale = 1f;
-        if (mBitmapShader != null) {
+        if (mBitmapShader != null && mThumbnailData != null) {
             // We consider this a stack task if it is not freeform (ie. has no bounds) or has been
             // dragged into the stack from the freeform workspace
             boolean isStackTask = !mTask.isFreeformTask() || mTask.bounds == null;
-            if (mTaskViewRect.isEmpty() || mThumbnailInfo == null ||
-                    mThumbnailInfo.taskWidth == 0 || mThumbnailInfo.taskHeight == 0) {
-                // If we haven't measured or the thumbnail is invalid, skip the thumbnail drawing
-                // and only draw the background color
+            int xOffset, yOffset = 0;
+            if (mTaskViewRect.isEmpty()) {
+                // If we haven't measured , skip the thumbnail drawing and only draw the background
+                // color
                 mThumbnailScale = 0f;
             } else if (isStackTask && !mSizeToFit) {
                 float invThumbnailScale = 1f / mFullscreenThumbnailScale;
                 if (mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT) {
-                    if (mThumbnailInfo.screenOrientation == Configuration.ORIENTATION_PORTRAIT) {
+                    if (mThumbnailData.orientation == Configuration.ORIENTATION_PORTRAIT) {
                         // If we are in the same orientation as the screenshot, just scale it to the
                         // width of the task view
                         mThumbnailScale = (float) mTaskViewRect.width() / mThumbnailRect.width();
@@ -268,8 +270,9 @@
                         (float) mTaskViewRect.width() / mThumbnailRect.width(),
                         (float) mTaskViewRect.height() / mThumbnailRect.height());
             }
-            mScaleMatrix.setScale(mThumbnailScale, mThumbnailScale);
-            mBitmapShader.setLocalMatrix(mScaleMatrix);
+            mMatrix.setTranslate(-mThumbnailData.insets.left, -mThumbnailData.insets.top);
+            mMatrix.postScale(mThumbnailScale, mThumbnailScale);
+            mBitmapShader.setLocalMatrix(mMatrix);
         }
         if (!mInvisible) {
             invalidate();
@@ -333,18 +336,14 @@
      * Called when the bound task's data has loaded and this view should update to reflect the
      * changes.
      */
-    void onTaskDataLoaded(ActivityManager.TaskThumbnailInfo thumbnailInfo) {
-        if (mTask.thumbnail != null) {
-            setThumbnail(mTask.thumbnail, thumbnailInfo);
-        } else {
-            setThumbnail(null, null);
-        }
+    void onTaskDataLoaded(ThumbnailData thumbnailData) {
+        setThumbnail(thumbnailData);
     }
 
     /** Unbinds the thumbnail view from the task */
     void unbindFromTask() {
         mTask = null;
-        setThumbnail(null, null);
+        setThumbnail(null);
     }
 
     public void dump(String prefix, PrintWriter writer) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
index 6300400..a86abf6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
@@ -51,7 +51,7 @@
         // Show the full thumbnail and don't overlap with the header.
         mThumbnailView.setSizeToFit(true);
         mThumbnailView.setOverlayHeaderOnThumbnailActionBar(false);
-        mThumbnailView.updateThumbnailScale();
+        mThumbnailView.updateThumbnailMatrix();
         mThumbnailView.setTranslationY(mHeaderHeight);
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 48a7e7c..74304f0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,258 +16,11 @@
 
 package com.android.server.am;
 
-import android.annotation.Nullable;
-import android.app.ActivityManagerInternal.PictureInPictureArguments;
-import android.app.ApplicationThreadConstants;
-import android.app.ContentProviderHolder;
-import android.app.IActivityManager;
-import android.app.RemoteAction;
-import android.app.WaitResult;
-import android.os.IDeviceIdentifiersPolicyService;
-
-import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.internal.telephony.TelephonyIntents;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
-import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.AssistUtils;
-import com.android.internal.app.DumpHeapActivity;
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.app.ProcessMap;
-import com.android.internal.app.SystemUserHomeActivity;
-import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.BatteryStatsImpl;
-import com.android.internal.os.IResultReceiver;
-import com.android.internal.os.ProcessCpuTracker;
-import com.android.internal.os.TransferPipe;
-import com.android.internal.os.Zygote;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.MemInfoReader;
-import com.android.internal.util.Preconditions;
-import com.android.server.AppOpsService;
-import com.android.server.AttributeCache;
-import com.android.server.DeviceIdleController;
-import com.android.server.IntentResolver;
-import com.android.server.LocalServices;
-import com.android.server.LockGuard;
-import com.android.server.ServiceThread;
-import com.android.server.SystemService;
-import com.android.server.SystemServiceManager;
-import com.android.server.Watchdog;
-import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.firewall.IntentFirewall;
-import com.android.server.pm.Installer;
-import com.android.server.pm.Installer.InstallerException;
-import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.vr.VrManagerInternal;
-import com.android.server.wm.WindowManagerService;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import android.Manifest;
-import android.Manifest.permission;
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackId;
-import android.app.ActivityManager.StackInfo;
-import android.app.ActivityManager.TaskThumbnailInfo;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerInternal.SleepToken;
-import android.app.ActivityOptions;
-import android.app.ActivityThread;
-import android.app.AlertDialog;
-import android.app.AppGlobals;
-import android.app.AppOpsManager;
-import android.app.ApplicationErrorReport;
-import android.app.BroadcastOptions;
-import android.app.Dialog;
-import android.app.IActivityContainer;
-import android.app.IActivityContainerCallback;
-import android.app.IActivityController;
-import android.app.IAppTask;
-import android.app.IApplicationThread;
-import android.app.IInstrumentationWatcher;
-import android.app.INotificationManager;
-import android.app.IProcessObserver;
-import android.app.IServiceConnection;
-import android.app.IStopUserCallback;
-import android.app.ITaskStackListener;
-import android.app.IUiAutomationConnection;
-import android.app.IUidObserver;
-import android.app.IUserSwitchObserver;
-import android.app.Instrumentation;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.ProfilerInfo;
-import android.app.admin.DevicePolicyManager;
-import android.app.assist.AssistContent;
-import android.app.assist.AssistStructure;
-import android.app.backup.IBackupManager;
-import android.app.usage.UsageEvents;
-import android.app.usage.UsageStatsManagerInternal;
-import android.appwidget.AppWidgetManager;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ClipData;
-import android.content.ComponentCallbacks2;
-import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.IContentProvider;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageManager;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.PathPermission;
-import android.content.pm.PermissionInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.content.res.CompatibilityInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.location.LocationManager;
-import android.net.Proxy;
-import android.net.ProxyInfo;
-import android.net.Uri;
-import android.os.BatteryStats;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.DropBoxManager;
-import android.os.Environment;
-import android.os.FactoryTest;
-import android.os.FileObserver;
-import android.os.FileUtils;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IPermissionController;
-import android.os.IProcessInfoService;
-import android.os.IProgressListener;
-import android.os.LocaleList;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.PersistableBundle;
-import android.os.PowerManager;
-import android.os.PowerManagerInternal;
-import android.os.Process;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ServiceManager;
-import android.os.ShellCallback;
-import android.os.StrictMode;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.Trace;
-import android.os.TransactionTooLargeException;
-import android.os.UpdateLock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.WorkSource;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManagerInternal;
-import android.os.storage.StorageManager;
-import android.provider.Downloads;
-import android.provider.Settings;
-import android.service.autofill.AutoFillService;
-import android.service.voice.IVoiceInteractionSession;
-import android.service.voice.VoiceInteractionManagerInternal;
-import android.service.voice.VoiceInteractionSession;
-import android.telecom.TelecomManager;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.text.style.SuggestionSpan;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.BootTimingsTraceLog;
-import android.util.DebugUtils;
-import android.util.DisplayMetrics;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.Pair;
-import android.util.PrintWriterPrinter;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.util.TimeUtils;
-import android.util.Xml;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.ref.WeakReference;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.CountDownLatch;
-
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
 import static android.Manifest.permission.CHANGE_CONFIGURATION;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
@@ -301,7 +54,6 @@
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
 import static android.provider.Settings.System.FONT_SCALE;
 import static android.view.Display.DEFAULT_DISPLAY;
-
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -367,7 +119,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
-import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
@@ -387,6 +138,256 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
+import android.Manifest;
+import android.Manifest.permission;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.StackId;
+import android.app.ActivityManager.StackInfo;
+import android.app.ActivityManager.TaskSnapshot;
+import android.app.ActivityManager.TaskThumbnailInfo;
+import android.app.ActivityManagerInternal;
+import android.app.ActivityManagerInternal.PictureInPictureArguments;
+import android.app.ActivityManagerInternal.SleepToken;
+import android.app.ActivityOptions;
+import android.app.ActivityThread;
+import android.app.AlertDialog;
+import android.app.AppGlobals;
+import android.app.AppOpsManager;
+import android.app.ApplicationErrorReport;
+import android.app.ApplicationThreadConstants;
+import android.app.BroadcastOptions;
+import android.app.ContentProviderHolder;
+import android.app.Dialog;
+import android.app.IActivityContainer;
+import android.app.IActivityContainerCallback;
+import android.app.IActivityController;
+import android.app.IActivityManager;
+import android.app.IAppTask;
+import android.app.IApplicationThread;
+import android.app.IInstrumentationWatcher;
+import android.app.INotificationManager;
+import android.app.IProcessObserver;
+import android.app.IServiceConnection;
+import android.app.IStopUserCallback;
+import android.app.ITaskStackListener;
+import android.app.IUiAutomationConnection;
+import android.app.IUidObserver;
+import android.app.IUserSwitchObserver;
+import android.app.Instrumentation;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.ProfilerInfo;
+import android.app.RemoteAction;
+import android.app.WaitResult;
+import android.app.admin.DevicePolicyManager;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.app.backup.IBackupManager;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.appwidget.AppWidgetManager;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ClipData;
+import android.content.ComponentCallbacks2;
+import android.content.ComponentName;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.IContentProvider;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageManager;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PathPermission;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.location.LocationManager;
+import android.net.Proxy;
+import android.net.ProxyInfo;
+import android.net.Uri;
+import android.os.BatteryStats;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.DropBoxManager;
+import android.os.Environment;
+import android.os.FactoryTest;
+import android.os.FileObserver;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IDeviceIdentifiersPolicyService;
+import android.os.IPermissionController;
+import android.os.IProcessInfoService;
+import android.os.IProgressListener;
+import android.os.LocaleList;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal;
+import android.os.Process;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.StrictMode;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.os.TransactionTooLargeException;
+import android.os.UpdateLock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.WorkSource;
+import android.os.storage.IStorageManager;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
+import android.provider.Downloads;
+import android.provider.Settings;
+import android.service.autofill.AutoFillService;
+import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.VoiceInteractionManagerInternal;
+import android.service.voice.VoiceInteractionSession;
+import android.telecom.TelecomManager;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.text.style.SuggestionSpan;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.BootTimingsTraceLog;
+import android.util.DebugUtils;
+import android.util.DisplayMetrics;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Pair;
+import android.util.PrintWriterPrinter;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.TimeUtils;
+import android.util.Xml;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.AssistUtils;
+import com.android.internal.app.DumpHeapActivity;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ProcessMap;
+import com.android.internal.app.SystemUserHomeActivity;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.os.ProcessCpuTracker;
+import com.android.internal.os.TransferPipe;
+import com.android.internal.os.Zygote;
+import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.MemInfoReader;
+import com.android.internal.util.Preconditions;
+import com.android.server.AppOpsService;
+import com.android.server.AttributeCache;
+import com.android.server.DeviceIdleController;
+import com.android.server.IntentResolver;
+import com.android.server.LocalServices;
+import com.android.server.LockGuard;
+import com.android.server.ServiceThread;
+import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
+import com.android.server.Watchdog;
+import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.firewall.IntentFirewall;
+import com.android.server.pm.Installer;
+import com.android.server.pm.Installer.InstallerException;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.WindowManagerService;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.ref.WeakReference;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 public class ActivityManagerService extends IActivityManager.Stub
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
 
@@ -9654,6 +9655,25 @@
     }
 
     @Override
+    public TaskSnapshot getTaskSnapshot(int taskId) {
+        enforceCallingPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
+                        taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+                if (task == null) {
+                    Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
+                    return null;
+                }
+                return task.getSnapshot();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
         if (userId != UserHandle.getCallingUserId()) {
             enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -9802,6 +9822,15 @@
             }
             mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront",
                     false /* forceNonResizable */);
+
+            final ActivityRecord topActivity = task.getTopActivity();
+            if (topActivity != null) {
+
+                // We are reshowing a task, use a starting window to hide the initial draw delay
+                // so the transition can start earlier.
+                topActivity.showStartingWindow(null /* prev */, false /* newTask */,
+                        true /* taskSwitch */);
+            }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2963ad1..47c3e6f 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
 import static android.app.ActivityManager.StackId;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
@@ -26,11 +27,11 @@
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
 import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
@@ -103,6 +104,10 @@
 import com.android.server.wm.AppWindowContainerListener;
 import com.android.server.wm.TaskWindowContainerController;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -113,10 +118,6 @@
 import java.util.List;
 import java.util.Objects;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 /**
  * An entry in the history stack, representing an activity.
  */
@@ -1204,6 +1205,14 @@
 
     final Bitmap screenshotActivityLocked() {
         if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "screenshotActivityLocked: " + this);
+
+        if (ENABLE_TASK_SNAPSHOTS) {
+            // No need to screenshot if snapshots are enabled.
+            if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS,
+                    "\tSnapshots are enabled, abort taking screenshot");
+            return null;
+        }
+
         if (noDisplay) {
             if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tNo display");
             return null;
@@ -1792,12 +1801,12 @@
         pendingVoiceInteractionStart = false;
     }
 
-    void showStartingWindow(ActivityRecord prev, boolean createIfNeeded) {
+    void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
         final CompatibilityInfo compatInfo =
                 service.compatibilityInfoForPackageLocked(info.applicationInfo);
         final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
                 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
-                prev != null ? prev.appToken : null, createIfNeeded);
+                prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning());
         if (shown) {
             mStartingWindowState = STARTING_WINDOW_SHOWN;
         }
@@ -2089,6 +2098,14 @@
         preserveWindowOnDeferredRelaunch = false;
     }
 
+    boolean isProcessRunning() {
+        ProcessRecord proc = app;
+        if (proc == null) {
+            proc = service.mProcessNames.get(processName, info.applicationInfo.uid);
+        }
+        return proc != null && proc.thread != null;
+    }
+
     void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
         out.attribute(null, ATTR_ID, String.valueOf(createTime));
         out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ab65eb1..abcaa24 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2459,7 +2459,8 @@
                     next.hasBeenLaunched = true;
                 } else  if (SHOW_APP_STARTING_PREVIEW && lastStack != null &&
                         mStackSupervisor.isFrontStack(lastStack)) {
-                    next.showStartingWindow(null, true);
+                    next.showStartingWindow(null /* prev */, false /* newTask */,
+                            false /* taskSwitch */);
                 }
                 mStackSupervisor.startSpecificActivityLocked(next, true, false);
                 if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2485,7 +2486,8 @@
                 next.hasBeenLaunched = true;
             } else {
                 if (SHOW_APP_STARTING_PREVIEW) {
-                    next.showStartingWindow(null, true);
+                    next.showStartingWindow(null /* prev */, false /* newTask */,
+                            false /* taskSwich */);
                 }
                 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
             }
@@ -2686,17 +2688,6 @@
         task.setFrontOfTask();
 
         if (!isHomeOrRecentsStack() || numActivities() > 0) {
-            // We want to show the starting preview window if we are
-            // switching to a new task, or the next activity's process is
-            // not currently running.
-            boolean showStartingIcon = newTask;
-            ProcessRecord proc = r.app;
-            if (proc == null) {
-                proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
-            }
-            if (proc == null || proc.thread == null) {
-                showStartingIcon = true;
-            }
             if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                     "Prepare open transition: starting " + r);
             if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
@@ -2756,7 +2747,7 @@
                         prev = null;
                     }
                 }
-                r.showStartingWindow(prev, showStartingIcon);
+                r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
             }
         } else {
             // If this is the first activity, don't do any fancy animations,
@@ -2765,6 +2756,11 @@
         }
     }
 
+    private boolean isTaskSwitch(ActivityRecord r,
+            ActivityRecord topFocusedActivity) {
+        return topFocusedActivity != null && r.task != topFocusedActivity.task;
+    }
+
     /**
      * Perform a reset of the given task, if needed as part of launching it.
      * Returns the new HistoryRecord at the top of the task.
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 61e3ad5..f401863 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -31,8 +31,8 @@
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.ActivityManager.StackId.isStaticStack;
 import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.ActivityManager.StackId.isStaticStack;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -53,7 +53,6 @@
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
 import static android.view.Display.INVALID_DISPLAY;
-
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
@@ -106,7 +105,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.PowerManagerInternal;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -1509,6 +1507,11 @@
                         mMovedToFront = true;
                     }
                     mOptions = null;
+
+                    // We are moving a task to the front, use starting window to hide initial drawn
+                    // delay.
+                    intentActivity.showStartingWindow(null /* prev */, false /* newTask */,
+                            true /* taskSwitch */);
                 }
                 updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
             }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index d0eac77..9e22c50 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.TaskDescription;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityManager.TaskThumbnail;
 import android.app.ActivityManager.TaskThumbnailInfo;
 import android.app.ActivityOptions;
@@ -34,6 +35,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Debug;
@@ -545,6 +547,13 @@
         mWindowContainerController.cancelThumbnailTransition();
     }
 
+    public TaskSnapshot getSnapshot() {
+        if (mWindowContainerController == null) {
+            return null;
+        }
+        return mWindowContainerController.getSnapshot();
+    }
+
     void touchActiveTime() {
         lastActiveTime = System.currentTimeMillis();
         if (firstActiveTime == 0) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0a312f0..4b2b184 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -51,6 +51,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
@@ -2907,7 +2908,7 @@
 
             // Only return the view if it was successfully added to the
             // window manager... which we can tell by it having a parent.
-            return view.getParent() != null ? new SplashScreenSurface(view) : null;
+            return view.getParent() != null ? new SplashScreenSurface(view, appToken) : null;
         } catch (WindowManager.BadTokenException e) {
             // ignore
             Log.w(TAG, appToken + " already running, starting window not displayed. " +
@@ -2927,18 +2928,6 @@
         return null;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public void removeSplashScreen(IBinder appToken, StartingSurface surface) {
-        if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + appToken + ": "
-                + surface + " Callers=" + Debug.getCallers(4));
-
-        if (surface != null) {
-            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
-            wm.removeView(((SplashScreenSurface) surface).view);
-        }
-    }
-
     /**
      * Preflight adding a window to the system.
      *
@@ -5185,7 +5174,7 @@
     @Override
     public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
             WindowState attached, WindowState imeTarget) {
-        final boolean visible = win.isVisibleLw();
+        final boolean visible = !win.isGoneForLayoutLw();
         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisible=" + visible);
         applyKeyguardPolicyLw(win, imeTarget);
         final int fl = PolicyControl.getWindowFlags(win, attrs);
@@ -5202,8 +5191,11 @@
             }
         }
 
+        // Don't allow snapshots to influence SystemUI visibility flags.
+        // TODO: Revisit this once SystemUI flags for snapshots are handled correctly
         boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
-                && attrs.type < FIRST_SYSTEM_WINDOW;
+                && attrs.type < FIRST_SYSTEM_WINDOW
+                && (attrs.privateFlags & PRIVATE_FLAG_TASK_SNAPSHOT) == 0;
         final int stackId = win.getStackId();
         if (mTopFullscreenOpaqueWindowState == null && visible) {
             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
diff --git a/services/core/java/com/android/server/policy/SplashScreenSurface.java b/services/core/java/com/android/server/policy/SplashScreenSurface.java
index d421291..37d6c0b 100644
--- a/services/core/java/com/android/server/policy/SplashScreenSurface.java
+++ b/services/core/java/com/android/server/policy/SplashScreenSurface.java
@@ -16,7 +16,13 @@
 
 package com.android.server.policy;
 
+import static com.android.server.policy.PhoneWindowManager.DEBUG_SPLASH_SCREEN;
+
+import android.os.Debug;
+import android.os.IBinder;
+import android.util.Slog;
 import android.view.View;
+import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 import android.view.WindowManagerPolicy.StartingSurface;
 
@@ -30,9 +36,21 @@
  */
 class SplashScreenSurface implements StartingSurface {
 
-    final View view;
+    private static final String TAG = PhoneWindowManager.TAG;
+    private final View mView;
+    private final IBinder mAppToken;
 
-    SplashScreenSurface(View view) {
-        this.view = view;
+    SplashScreenSurface(View view, IBinder appToken) {
+        mView = view;
+        mAppToken = appToken;
+    }
+
+    @Override
+    public void remove() {
+        if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + mAppToken + ": "
+                        + this + " Callers=" + Debug.getCallers(4));
+
+        final WindowManager wm = mView.getContext().getSystemService(WindowManager.class);
+        wm.removeView(mView);
     }
 }
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index d2f604d..1eb74fa4 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -28,6 +28,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.app.ActivityManager.TaskSnapshot;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
@@ -50,6 +51,10 @@
 public class AppWindowContainerController
         extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
 
+    private static final int STARTING_WINDOW_TYPE_NONE = 0;
+    private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
+    private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
+
     private final IApplicationToken mToken;
     private final Handler mHandler = new Handler(Looper.getMainLooper());
 
@@ -80,16 +85,39 @@
         mListener.onWindowsGone();
     };
 
+    private final Runnable mRemoveStartingWindow = () -> {
+        StartingSurface surface = null;
+        StartingData data = null;
+        synchronized (mWindowMap) {
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer
+                    + ": startingWindow=" + mContainer.startingWindow
+                    + " startingView=" + mContainer.startingSurface);
+            if (mContainer.startingWindow != null) {
+                surface = mContainer.startingSurface;
+                data = mContainer.startingData;
+                mContainer.startingData = null;
+                mContainer.startingSurface = null;
+                mContainer.startingWindow = null;
+                mContainer.startingDisplayed = false;
+            }
+        }
+        if (data != null && surface != null) {
+            try {
+                surface.remove();
+            } catch (Exception e) {
+                Slog.w(TAG_WM, "Exception when removing starting window", e);
+            }
+        }
+    };
+
     private final Runnable mAddStartingWindow = () -> {
         final StartingData startingData;
-        final Configuration mergedOverrideConfiguration;
 
         synchronized (mWindowMap) {
             if (mContainer == null) {
                 return;
             }
             startingData = mContainer.startingData;
-            mergedOverrideConfiguration = mContainer.getMergedOverrideConfiguration();
         }
 
         if (startingData == null) {
@@ -98,20 +126,16 @@
         }
 
         if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
-                + this + ": pkg=" + mContainer.startingData.pkg);
+                + this + ": startingData=" + mContainer.startingData);
 
-        StartingSurface contents = null;
+        StartingSurface surface = null;
         try {
-            contents = mService.mPolicy.addSplashScreen(mContainer.token, startingData.pkg,
-                    startingData.theme, startingData.compatInfo, startingData.nonLocalizedLabel,
-                    startingData.labelRes, startingData.icon, startingData.logo,
-                    startingData.windowFlags, mergedOverrideConfiguration);
+            surface = startingData.createStartingSurface();
         } catch (Exception e) {
             Slog.w(TAG_WM, "Exception when adding starting window", e);
         }
-        if (contents != null) {
+        if (surface != null) {
             boolean abort = false;
-
             synchronized(mWindowMap) {
                 if (mContainer.removed || mContainer.startingData == null) {
                     // If the window was successfully added, then
@@ -121,12 +145,10 @@
                                 "Aborted starting " + mContainer
                                         + ": removed=" + mContainer.removed
                                         + " startingData=" + mContainer.startingData);
-                        mContainer.startingWindow = null;
-                        mContainer.startingData = null;
                         abort = true;
                     }
                 } else {
-                    mContainer.startingSurface = contents;
+                    mContainer.startingSurface = surface;
                 }
                 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
                         "Added starting " + mContainer
@@ -134,42 +156,11 @@
                                 + mContainer.startingWindow + " startingView="
                                 + mContainer.startingSurface);
             }
-
             if (abort) {
-                try {
-                    mService.mPolicy.removeSplashScreen(mContainer.token, contents);
-                } catch (Exception e) {
-                    Slog.w(TAG_WM, "Exception when removing starting window", e);
-                }
-            }
-        }
-    };
-
-    private final Runnable mRemoveStartingWindow = () -> {
-        IBinder token = null;
-        StartingSurface contents = null;
-        synchronized (mWindowMap) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting "
-                    + mContainer + ": startingWindow="
-                    + mContainer.startingWindow + " startingView="
-                    + mContainer.startingSurface);
+                mRemoveStartingWindow.run();
             if (mContainer == null) {
                 return;
             }
-            if (mContainer.startingWindow != null) {
-                contents = mContainer.startingSurface;
-                token = mContainer.token;
-                mContainer.startingData = null;
-                mContainer.startingSurface = null;
-                mContainer.startingWindow = null;
-                mContainer.startingDisplayed = false;
-            }
-        }
-        if (contents != null) {
-            try {
-                mService.mPolicy.removeSplashScreen(token, contents);
-            } catch (Exception e) {
-                Slog.w(TAG_WM, "Exception when removing starting window", e);
             }
         }
     };
@@ -389,7 +380,7 @@
 
     public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
             CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
-            IBinder transferFrom, boolean createIfNeeded) {
+            IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning) {
         synchronized(mWindowMap) {
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
                     + " pkg=" + pkg + " transferFrom=" + transferFrom);
@@ -409,6 +400,12 @@
                 return false;
             }
 
+            final int type = getStartingWindowType(newTask, taskSwitch, processRunning);
+
+            if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
+                return createSnapshot();
+            }
+
             // If this is a translucent window, then don't show a starting window -- the current
             // effect (a full-screen opaque starting window that fades away to the real contents
             // when it is ready) does not work for this.
@@ -458,22 +455,32 @@
                 return true;
             }
 
-            // There is no existing starting window, and the caller doesn't
-            // want us to create one, so that's it!
-            if (!createIfNeeded) {
+            // There is no existing starting window, and we don't want to create a splash screen, so
+            // that's it!
+            if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
                 return false;
             }
 
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
-            mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
-                    labelRes, icon, logo, windowFlags);
+            mContainer.startingData = new SplashScreenStartingData(mService, mContainer, pkg, theme,
+                    compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
+                    mContainer.getMergedOverrideConfiguration());
             scheduleAddStartingWindow();
         }
         return true;
     }
 
-    void scheduleAddStartingWindow() {
+    private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning) {
+        if (newTask || !processRunning) {
+            return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+        } else if (taskSwitch) {
+            return STARTING_WINDOW_TYPE_SNAPSHOT;
+        } else {
+            return STARTING_WINDOW_TYPE_NONE;
+        }
+    }
 
+    void scheduleAddStartingWindow() {
         // Note: we really want to do sendMessageAtFrontOfQueue() because we
         // want to process the message ASAP, before any other queued
         // messages.
@@ -481,6 +488,20 @@
         mHandler.postAtFrontOfQueue(mAddStartingWindow);
     }
 
+    private boolean createSnapshot() {
+        final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
+                mContainer.mTask);
+
+        if (snapshot == null) {
+            return false;
+        }
+
+        mContainer.startingData = new SnapshotStartingData(mService, mContainer,
+                snapshot.getSnapshot());
+        scheduleAddStartingWindow();
+        return true;
+    }
+
     public void removeStartingWindow() {
         synchronized (mWindowMap) {
             if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
@@ -593,7 +614,7 @@
             }
             return dc.screenshotApplications(mToken.asBinder(), width, height,
                     false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
-                    false /* wallpaperOnly */);
+                    false /* wallpaperOnly */, false /* includeDecor */, true /* toAshmem */);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
         }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f4fa220..10d1d8b 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -205,7 +205,7 @@
         // We now have a good window to show, remove dead placeholders
         removeDeadWindows();
 
-        if (startingData != null) {
+        if (startingWindow != null) {
             if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
                     + win.mToken + ": first real window is shown, no animation");
             // If this initial window is animating, stop it -- we will do an animation to reveal
@@ -671,7 +671,7 @@
         } else if (mChildren.size() == 0 && startingData != null) {
             // If this is the last window and we had requested a starting transition window,
             // well there is no point now.
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingWindow");
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData");
             startingData = null;
         } else if (mChildren.size() == 1 && startingSurface != null) {
             // If this is the last window except for a starting transition window,
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d86c4da..66267bd 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -106,6 +106,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
+import android.util.MutableBoolean;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
@@ -2102,10 +2103,14 @@
      * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
      * @param config of the output bitmap
      * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
+     * @param includeDecor whether to include window decors, like the status or navigation bar
+     *                     background of the window
+     * @param toAshmem whether to convert the resulting bitmap to ashmem; this should be set to
+     *                 true if the Bitmap is sent over binder, and false otherwise
      */
     Bitmap screenshotApplications(IBinder appToken, int width, int height,
             boolean includeFullDisplay, float frameScale, Bitmap.Config config,
-            boolean wallpaperOnly) {
+            boolean wallpaperOnly, boolean includeDecor, boolean toAshmem) {
         int dw = mDisplayInfo.logicalWidth;
         int dh = mDisplayInfo.logicalHeight;
         if (dw == 0 || dh == 0) {
@@ -2137,7 +2142,7 @@
 
         final int aboveAppLayer = (mService.mPolicy.windowTypeToLayerLw(TYPE_APPLICATION) + 1)
                 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
-
+        final MutableBoolean mutableIncludeFullDisplay = new MutableBoolean(includeFullDisplay);
         synchronized(mService.mWindowMap) {
             // Figure out the part of the screen that is actually the app.
             mScreenshotApplicationState.appWin = null;
@@ -2194,7 +2199,11 @@
                 }
 
                 // Don't include wallpaper in bounds calculation
-                if (!includeFullDisplay && !w.mIsWallpaper) {
+                if (includeDecor && !stackBounds.isEmpty()) {
+                    frame.set(stackBounds);
+                } else if (includeDecor) {
+                    mutableIncludeFullDisplay.value = true;
+                } else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
                     final Rect wf = w.mFrame;
                     final Rect cr = w.mContentInsets;
                     int left = wf.left + cr.left;
@@ -2252,7 +2261,7 @@
                 return null;
             }
 
-            if (!includeFullDisplay) {
+            if (!mutableIncludeFullDisplay.value) {
                 // Constrain frame to the screen size.
                 if (!frame.intersect(0, 0, dw, dh)) {
                     frame.setEmpty();
@@ -2353,9 +2362,13 @@
 
         // Create a copy of the screenshot that is immutable and backed in ashmem.
         // This greatly reduces the overhead of passing the bitmap between processes.
-        Bitmap ret = bm.createAshmemBitmap(config);
-        bm.recycle();
-        return ret;
+        if (toAshmem) {
+            Bitmap ret = bm.createAshmemBitmap(config);
+            bm.recycle();
+            return ret;
+        } else {
+            return bm;
+        }
     }
 
     // TODO: Can this use createRotationMatrix()?
diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java
new file mode 100644
index 0000000..9d97a0c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.graphics.GraphicBuffer;
+import android.view.WindowManagerPolicy.StartingSurface;
+
+/**
+ * Represents starting data for snapshot starting windows.
+ */
+class SnapshotStartingData extends StartingData {
+
+    private final WindowManagerService mService;
+    private final GraphicBuffer mSnapshot;
+
+    SnapshotStartingData(WindowManagerService service, AppWindowToken appWindowToken,
+            GraphicBuffer snapshot) {
+        super(service, appWindowToken);
+        mService = service;
+        mSnapshot = snapshot;
+    }
+
+    @Override
+    StartingSurface createStartingSurface() {
+        return mService.mTaskSnapshotController.createStartingSurface(
+                mAppWindowToken, mSnapshot);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
new file mode 100644
index 0000000..664e600
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.view.WindowManagerPolicy.StartingSurface;
+
+/**
+ * Represents starting data for splash screens, i.e. "traditional" starting windows.
+ */
+class SplashScreenStartingData extends StartingData {
+
+    private final String mPkg;
+    private final int mTheme;
+    private final CompatibilityInfo mCompatInfo;
+    private final CharSequence mNonLocalizedLabel;
+    private final int mLabelRes;
+    private final int mIcon;
+    private final int mLogo;
+    private final int mWindowFlags;
+    private final Configuration mMergedOverrideConfiguration;
+
+    SplashScreenStartingData(WindowManagerService service, AppWindowToken appWindowToken,
+            String pkg, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel,
+            int labelRes, int icon, int logo, int windowFlags,
+            Configuration mergedOverrideConfiguration) {
+        super(service, appWindowToken);
+        mPkg = pkg;
+        mTheme = theme;
+        mCompatInfo = compatInfo;
+        mNonLocalizedLabel = nonLocalizedLabel;
+        mLabelRes = labelRes;
+        mIcon = icon;
+        mLogo = logo;
+        mWindowFlags = windowFlags;
+        mMergedOverrideConfiguration = mergedOverrideConfiguration;
+    }
+
+    @Override
+    StartingSurface createStartingSurface() {
+        return mService.mPolicy.addSplashScreen(mAppWindowToken.token, mPkg, mTheme, mCompatInfo,
+                mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags,
+                mMergedOverrideConfiguration);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 7115b0f..fcc4c3c 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -16,28 +16,27 @@
 
 package com.android.server.wm;
 
-import android.content.res.CompatibilityInfo;
+import android.view.WindowManagerPolicy.StartingSurface;
 
-final class StartingData {
-    final String pkg;
-    final int theme;
-    final CompatibilityInfo compatInfo;
-    final CharSequence nonLocalizedLabel;
-    final int labelRes;
-    final int icon;
-    final int logo;
-    final int windowFlags;
+/**
+ * Represents the model about how a starting window should be constructed.
+ */
+public abstract class StartingData {
 
-    StartingData(String _pkg, int _theme, CompatibilityInfo _compatInfo,
-            CharSequence _nonLocalizedLabel,
-            int _labelRes, int _icon, int _logo, int _windowFlags) {
-        pkg = _pkg;
-        theme = _theme;
-        compatInfo = _compatInfo;
-        nonLocalizedLabel = _nonLocalizedLabel;
-        labelRes = _labelRes;
-        icon = _icon;
-        logo = _logo;
-        windowFlags = _windowFlags;
+    protected final WindowManagerService mService;
+    protected final AppWindowToken mAppWindowToken;
+
+    protected StartingData(WindowManagerService service, AppWindowToken appWindowToken) {
+        mService = service;
+        mAppWindowToken = appWindowToken;
     }
+
+    /**
+     * Creates the actual starting window surface. DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING
+     * THIS METHOD.
+     *
+     * @return a class implementing {@link StartingSurface} for easy removal with
+     *         {@link StartingSurface#remove}
+     */
+    abstract StartingSurface createStartingSurface();
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
new file mode 100644
index 0000000..994a155
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager.TaskSnapshot;
+import android.util.ArrayMap;
+
+/**
+ * Caches snapshots. See {@link TaskSnapshotController}.
+ * <p>
+ * Access to this class should be guarded by the global window manager lock.
+ */
+class TaskSnapshotCache {
+
+    private final ArrayMap<Task, TaskSnapshot> mCache = new ArrayMap<>();
+
+    void putSnapshot(Task task, TaskSnapshot snapshot) {
+        mCache.put(task, snapshot);
+    }
+
+    @Nullable TaskSnapshot getSnapshot(Task task) {
+        return mCache.get(task);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
new file mode 100644
index 0000000..4421d61
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
+import static android.graphics.Bitmap.Config.ARGB_8888;
+import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
+import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER;
+import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER;
+import static android.graphics.PixelFormat.RGBA_8888;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager.StackId;
+import android.app.ActivityManager.TaskSnapshot;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.GraphicBuffer;
+import android.util.ArraySet;
+import android.view.WindowManagerPolicy.StartingSurface;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * When an app token becomes invisible, we take a snapshot (bitmap) of the corresponding task and
+ * put it into our cache. Internally we use gralloc buffers to be able to draw them wherever we
+ * like without any copying.
+ * <p>
+ * System applications may retrieve a snapshot to represent the current state of a task, and draw
+ * them in their own process.
+ * <p>
+ * When we task becomes visible again, we show a starting window with the snapshot as the content to
+ * make app transitions more responsive.
+ * <p>
+ * To access this class, acquire the global window manager lock.
+ */
+class TaskSnapshotController {
+
+    private final WindowManagerService mService;
+    private final TaskSnapshotCache mCache = new TaskSnapshotCache();
+
+    private final ArraySet<Task> mTmpTasks = new ArraySet<>();
+
+    TaskSnapshotController(WindowManagerService service) {
+        mService = service;
+    }
+
+    void onTransitionStarting() {
+        if (!ENABLE_TASK_SNAPSHOTS) {
+            return;
+        }
+
+        // We need to take a snapshot of the task if and only if all activities of the task are
+        // either closing or hidden.
+        getClosingTasks(mService.mClosingApps, mTmpTasks);
+        for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
+            final Task task = mTmpTasks.valueAt(i);
+            if (!canSnapshotTask(task)) {
+                continue;
+            }
+            final TaskSnapshot snapshot = snapshotTask(task);
+            if (snapshot != null) {
+                mCache.putSnapshot(task, snapshot);
+            }
+        }
+    }
+
+    @Nullable TaskSnapshot getSnapshot(Task task) {
+        return mCache.getSnapshot(task);
+    }
+
+    /**
+     * Creates a starting surface for {@param token} with {@param snapshot}. DO NOT HOLD THE WINDOW
+     * MANAGER LOCK WHEN CALLING THIS METHOD!
+     */
+    StartingSurface createStartingSurface(AppWindowToken token,
+            GraphicBuffer snapshot) {
+        return TaskSnapshotSurface.create(mService, token, snapshot);
+    }
+
+    private TaskSnapshot snapshotTask(Task task) {
+        final AppWindowToken top = (AppWindowToken) task.getTop();
+        if (top == null) {
+            return null;
+        }
+        final Bitmap bmp = top.mDisplayContent.screenshotApplications(top.token, -1, -1, false,
+                1.0f, ARGB_8888, false, true, false);
+        if (bmp == null) {
+            return null;
+        }
+        // TODO: Already use a GraphicBuffer when snapshotting the content.
+        final GraphicBuffer buffer = GraphicBuffer.create(bmp.getWidth(), bmp.getHeight(),
+                RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_WRITE_NEVER | USAGE_SW_READ_NEVER);
+        final Canvas c = buffer.lockCanvas();
+        c.drawBitmap(bmp, 0, 0, null);
+        buffer.unlockCanvasAndPost(c);
+        return new TaskSnapshot(buffer, top.getConfiguration().orientation,
+                top.findMainWindow().mStableInsets);
+    }
+
+    /**
+     * Retrieves all closing tasks based on the list of closing apps during an app transition.
+     */
+    @VisibleForTesting
+    void getClosingTasks(ArraySet<AppWindowToken> closingApps, ArraySet<Task> outClosingTasks) {
+        outClosingTasks.clear();
+        for (int i = closingApps.size() - 1; i >= 0; i--) {
+            final AppWindowToken atoken = closingApps.valueAt(i);
+
+            // If the task of the app is not visible anymore, it means no other app in that task
+            // is opening. Thus, the task is closing.
+            if (atoken.mTask != null && !atoken.mTask.isVisible()) {
+                outClosingTasks.add(closingApps.valueAt(i).mTask);
+            }
+        }
+    }
+
+    private boolean canSnapshotTask(Task task) {
+        return !StackId.isHomeOrRecentsStack(task.mStack.mStackId);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
new file mode 100644
index 0000000..c3e3141
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.GraphicBuffer;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.Display;
+import android.view.IWindowSession;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerPolicy.StartingSurface;
+
+import com.android.internal.view.BaseIWindow;
+
+/**
+ * This class represents a starting window that shows a snapshot.
+ * <p>
+ * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING METHODS OF THIS CLASS!
+ */
+class TaskSnapshotSurface implements StartingSurface {
+
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
+    private static final int MSG_REPORT_DRAW = 0;
+    private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
+    private final Window mWindow;
+    private final Surface mSurface;
+    private final IWindowSession mSession;
+    private final WindowManagerService mService;
+    private boolean mHasDrawn;
+    private boolean mReportNextDraw;
+
+    static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
+            GraphicBuffer snapshot) {
+
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+        final Window window = new Window();
+        final IWindowSession session = WindowManagerGlobal.getWindowSession();
+        window.setSession(session);
+        final Surface surface = new Surface();
+        final Rect tmpRect = new Rect();
+        final Rect tmpFrame = new Rect();
+        final Configuration tmpConfiguration = new Configuration();
+        synchronized (service.mWindowMap) {
+            layoutParams.type = TYPE_APPLICATION_STARTING;
+            layoutParams.format = snapshot.getFormat();
+            layoutParams.flags = FLAG_LAYOUT_INSET_DECOR
+                    | FLAG_LAYOUT_IN_SCREEN
+                    | FLAG_NOT_FOCUSABLE
+                    | FLAG_NOT_TOUCHABLE
+                    | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+            layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT;
+            layoutParams.token = token.token;
+            layoutParams.width = LayoutParams.MATCH_PARENT;
+            layoutParams.height = LayoutParams.MATCH_PARENT;
+
+            // TODO: Inherit behavior whether to draw behind status bar/nav bar.
+            layoutParams.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+            layoutParams.setTitle(String.format(TITLE_FORMAT, token.mTask.mTaskId));
+        }
+        try {
+            final int res = session.addToDisplay(window, window.mSeq, layoutParams,
+                    View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
+                    tmpRect, null);
+            if (res < 0) {
+                Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
+                return null;
+            }
+        } catch (RemoteException e) {
+            // Local call.
+        }
+        final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
+                surface);
+        window.setOuter(snapshotSurface);
+        try {
+            session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
+                    tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpConfiguration,
+                    surface);
+        } catch (RemoteException e) {
+            // Local call.
+        }
+        snapshotSurface.drawSnapshot(snapshot);
+        return snapshotSurface;
+    }
+
+    private TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface) {
+        mService = service;
+        mSession = WindowManagerGlobal.getWindowSession();
+        mWindow = window;
+        mSurface = surface;
+    }
+
+    @Override
+    public void remove() {
+        try {
+            mSession.remove(mWindow);
+        } catch (RemoteException e) {
+            // Local call.
+        }
+    }
+
+    private void drawSnapshot(GraphicBuffer snapshot) {
+
+        // TODO: Just wrap the buffer here without any copying.
+        final Canvas c = mSurface.lockHardwareCanvas();
+        c.drawBitmap(Bitmap.createHardwareBitmap(snapshot), 0, 0, null);
+        mSurface.unlockCanvasAndPost(c);
+        final boolean reportNextDraw;
+        synchronized (mService.mWindowMap) {
+            mHasDrawn = true;
+            reportNextDraw = mReportNextDraw;
+        }
+        if (reportNextDraw) {
+            reportDrawn();
+        }
+    }
+
+    private void reportDrawn() {
+        synchronized (mService.mWindowMap) {
+            mReportNextDraw = false;
+        }
+        try {
+            mSession.finishDrawing(mWindow);
+        } catch (RemoteException e) {
+            // Local call.
+        }
+    }
+
+    private static Handler sHandler = new Handler() {
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_REPORT_DRAW:
+                    final boolean hasDrawn;
+                    final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
+                    synchronized (surface.mService.mWindowMap) {
+                        hasDrawn = surface.mHasDrawn;
+                        if (!hasDrawn) {
+                            surface.mReportNextDraw = true;
+                        }
+                    }
+                    if (hasDrawn) {
+                        surface.reportDrawn();
+                    }
+                    break;
+            }
+        }
+    };
+
+    private static class Window extends BaseIWindow {
+
+        private TaskSnapshotSurface mOuter;
+
+        public void setOuter(TaskSnapshotSurface outer) {
+            mOuter = outer;
+        }
+
+        @Override
+        public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
+                Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
+                Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar) {
+            if (reportDraw) {
+                sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index 9c303f8..0e4d048 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -16,7 +16,9 @@
 
 package com.android.server.wm;
 
+import android.app.ActivityManager.TaskSnapshot;
 import android.content.res.Configuration;
+import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.util.EventLog;
 import android.util.Slog;
@@ -238,6 +240,19 @@
         }
     }
 
+    /**
+     * @return a graphic buffer representing a screenshot of a task
+     */
+    public TaskSnapshot getSnapshot() {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "getSnapshot: taskId " + mTaskId + " not found.");
+                return null;
+            }
+            return mService.mTaskSnapshotController.getSnapshot(mContainer);
+        }
+    }
+
     @Override
     public String toString() {
         return "{TaskWindowContainerController taskId=" + mTaskId + "}";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 048affb..195d4c3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,6 +16,80 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.MANAGE_APP_TOKENS;
+import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.StatusBarManager.DISABLE_MASK;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
+import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
 import android.Manifest;
 import android.Manifest.permission;
 import android.animation.ValueAnimator;
@@ -39,8 +113,8 @@
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
-import android.graphics.PixelFormat;
 import android.graphics.Matrix;
+import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -88,7 +162,6 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Gravity;
-import android.view.PointerIcon;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IDockedStackListener;
 import android.view.IInputFilter;
@@ -107,6 +180,7 @@
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
 import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
@@ -161,83 +235,6 @@
 import java.util.HashMap;
 import java.util.List;
 
-import static android.Manifest.permission.MANAGE_APP_TOKENS;
-import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.StatusBarManager.DISABLE_MASK;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
-import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.EventLogTags.WM_TASK_CREATED;
-import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
-import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
-import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
         implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
@@ -580,6 +577,7 @@
 
     final UnknownAppVisibilityController mUnknownAppVisibilityController =
             new UnknownAppVisibilityController(this);
+    final TaskSnapshotController mTaskSnapshotController = new TaskSnapshotController(this);
 
     boolean mIsTouchDevice;
 
@@ -1215,7 +1213,9 @@
                           + token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_APP_EXITING;
                 }
-                if (rootType == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
+                if (rootType == TYPE_APPLICATION_STARTING
+                        && (attrs.privateFlags & PRIVATE_FLAG_TASK_SNAPSHOT) == 0
+                        && atoken.firstWindowDrawn) {
                     // No need for this guy!
                     if (DEBUG_STARTING_WINDOW || localLOGV) Slog.v(
                             TAG_WM, "**** NO NEED TO START: " + attrs.getTitle());
@@ -1966,7 +1966,8 @@
                         + " newVis=" + viewVisibility, stack);
             }
             if (viewVisibility == View.VISIBLE &&
-                    (win.mAppToken == null || !win.mAppToken.clientHidden)) {
+                    (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
+                            || !win.mAppToken.clientHidden)) {
                 result = relayoutVisibleWindow(outConfig, result, win, winAnimator, attrChanges,
                         oldVisibility);
                 try {
@@ -2073,7 +2074,10 @@
             win.setDisplayLayoutNeeded();
             win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             configChanged = updateOrientationFromAppTokensLocked(false, displayId);
-            mWindowPlacerLocked.performSurfacePlacement();
+
+            // We may be deferring layout passes at the moment, but since the client is interested
+            // in the new out values right now we need to force a layout.
+            mWindowPlacerLocked.performSurfacePlacement(true /* force */);
             if (toBeDisplayed && win.mIsWallpaper) {
                 DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo();
                 dc.mWallpaperController.updateWallpaperOffset(
@@ -3858,7 +3862,8 @@
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
             return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
                     -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */,
-                    Bitmap.Config.ARGB_8888, true /* wallpaperOnly */);
+                    Bitmap.Config.ARGB_8888, true /* wallpaperOnly */, false /* includeDecor */,
+                    true /* toAshmem */);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
         }
@@ -3879,7 +3884,8 @@
         FgThread.getHandler().post(() -> {
             Bitmap bm = screenshotApplications(null /* appToken */, DEFAULT_DISPLAY,
                     -1 /* width */, -1 /* height */, true /* includeFullDisplay */,
-                    1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */);
+                    1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */,
+                    false /* includeDecor */, true /* toAshmem */);
             try {
                 receiver.send(bm);
             } catch (RemoteException e) {
@@ -3900,10 +3906,14 @@
      * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
      * @param config of the output bitmap
      * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
+     * @param includeDecor whether to include window decors, like the status or navigation bar
+     *                     background of the window
+     * @param toAshmem whether to convert the resulting bitmap to ashmem; this should be set to
+     *                 true if the Bitmap is sent over binder, and false otherwise
      */
     private Bitmap screenshotApplications(IBinder appToken, int displayId, int width,
             int height, boolean includeFullDisplay, float frameScale, Bitmap.Config config,
-            boolean wallpaperOnly) {
+            boolean wallpaperOnly, boolean includeDecor, boolean toAshmem) {
         final DisplayContent displayContent;
         synchronized(mWindowMap) {
             displayContent = mRoot.getDisplayContentOrCreate(displayId);
@@ -3914,7 +3924,7 @@
             }
         }
         return displayContent.screenshotApplications(appToken, width, height,
-                includeFullDisplay, frameScale, config, wallpaperOnly);
+                includeFullDisplay, frameScale, config, wallpaperOnly, includeDecor, toAshmem);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3daad43..608f056 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,7 +16,84 @@
 
 package com.android.server.wm;
 
-import android.app.ActivityManager;
+import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
+import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.isLowRamDeviceStatic;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static android.view.WindowManagerPolicy.TRANSIT_ENTER;
+import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
+import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
+import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
+import static com.android.server.wm.WindowManagerService.localLOGV;
+import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
+import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
+import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
+import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
+
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -62,82 +139,6 @@
 import java.util.LinkedList;
 import java.util.function.Predicate;
 
-import static android.app.ActivityManager.StackId;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static android.view.WindowManagerPolicy.TRANSIT_ENTER;
-import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
-import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
-import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
-import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
-import static com.android.server.wm.WindowManagerService.localLOGV;
-import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
-import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
-import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
-import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
-
 /** A window in the window manager. */
 class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {
     static final String TAG = TAG_WITH_CLASS_NAME ? "WindowState" : TAG_WM;
@@ -152,7 +153,8 @@
     // to capture touch events in that area.
     static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
 
-    private static final boolean DEBUG_DISABLE_SAVING_SURFACES = false;
+    private static final boolean DEBUG_DISABLE_SAVING_SURFACES = false ||
+            ENABLE_TASK_SNAPSHOTS;
 
     final WindowManagerService mService;
     final WindowManagerPolicy mPolicy;
@@ -2652,7 +2654,7 @@
             return false;
         }
 
-        if (ActivityManager.isLowRamDeviceStatic()) {
+        if (isLowRamDeviceStatic()) {
             // Don't save surfaces on Svelte devices.
             return false;
         }
@@ -3713,6 +3715,12 @@
 
         logPerformShow("performShow on ");
 
+        final int drawState = mWinAnimator.mDrawState;
+        if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW)
+                && mAttrs.type != TYPE_APPLICATION_STARTING && mAppToken != null) {
+            mAppToken.onFirstWindowDrawn(this, mWinAnimator);
+        }
+
         if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
             return false;
         }
@@ -3747,10 +3755,6 @@
             }
         }
 
-        if (mAttrs.type != TYPE_APPLICATION_STARTING && mAppToken != null) {
-            mAppToken.onFirstWindowDrawn(this, mWinAnimator);
-        }
-
         if (mAttrs.type == TYPE_INPUT_METHOD) {
             getDisplayContent().mDividerControllerLocked.resetImeHideRequested();
         }
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 4df1001..897d5b86 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -117,7 +117,11 @@
     }
 
     final void performSurfacePlacement() {
-        if (mDeferDepth > 0) {
+        performSurfacePlacement(false /* force */);
+    }
+
+    final void performSurfacePlacement(boolean force) {
+        if (mDeferDepth > 0 && !force) {
             return;
         }
         int loopCount = 6;
@@ -343,6 +347,8 @@
         mService.mAppTransition.postAnimationCallback();
         mService.mAppTransition.clear();
 
+        mService.mTaskSnapshotController.onTransitionStarting();
+
         mService.mOpeningApps.clear();
         mService.mClosingApps.clear();
         mService.mUnknownAppVisibilityController.clear();
@@ -513,17 +519,14 @@
                         + wtoken.startingMoved + " isRelaunching()="
                         + wtoken.isRelaunching());
 
-                if (wtoken.isRelaunching()) {
-                    return false;
-                }
-
                 final boolean drawnBeforeRestoring = wtoken.allDrawn;
                 wtoken.restoreSavedSurfaceForInterestingWindows();
 
-                if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
+                final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
+                if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
                     return false;
                 }
-                if (wtoken.allDrawn) {
+                if (allDrawn) {
                     reason = drawnBeforeRestoring ? APP_TRANSITION_WINDOWS_DRAWN
                             : APP_TRANSITION_SAVED_SURFACE;
                 } else {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
new file mode 100644
index 0000000..5dff997
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import static junit.framework.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link TaskSnapshotController}.
+ *
+ * runtest frameworks-services -c com.android.server.wm.TaskSnapshotControllerTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class TaskSnapshotControllerTest extends WindowTestsBase {
+
+    @Test
+    public void testGetClosingApps_closing() throws Exception {
+        final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
+                "closingWindow");
+        closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
+                true /* performLayout */, false /* isVoiceInteraction */);
+        final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
+        closingApps.add(closingWindow.mAppToken);
+        final ArraySet<Task> closingTasks = new ArraySet<>();
+        sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+        assertEquals(1, closingTasks.size());
+        assertEquals(closingWindow.mAppToken.mTask, closingTasks.valueAt(0));
+    }
+
+    @Test
+    public void testGetClosingApps_notClosing() throws Exception {
+        final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
+                "closingWindow");
+        final WindowState openingWindow = createAppWindow(closingWindow.getTask(),
+                FIRST_APPLICATION_WINDOW, "openingWindow");
+        closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
+                true /* performLayout */, false /* isVoiceInteraction */);
+        openingWindow.mAppToken.setVisibility(null, true /* visible */, TRANSIT_UNSET,
+                true /* performLayout */, false /* isVoiceInteraction */);
+        final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
+        closingApps.add(closingWindow.mAppToken);
+        final ArraySet<Task> closingTasks = new ArraySet<>();
+        sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+        assertEquals(0, closingTasks.size());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index c4fd722..12e7a15 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -313,11 +313,6 @@
     }
 
     @Override
-    public void removeSplashScreen(IBinder appToken, StartingSurface surface) {
-
-    }
-
-    @Override
     public int prepareAddWindowLw(WindowState win,
             WindowManager.LayoutParams attrs) {
         return 0;
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index be080f5..466bd67 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -119,6 +119,12 @@
                 : createWindow(parent, type, parent.mToken, name);
     }
 
+    WindowState createAppWindow(Task task, int type, String name) {
+        final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+        task.addChild(token, 0);
+        return createWindow(null, type, token, name);
+    }
+
     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
         final WindowToken token = createWindowToken(dc, type);
         return createWindow(parent, type, token, name);
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 5e5ebd7..5ed5460 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -16,18 +16,10 @@
 
 package android.view;
 
-import android.graphics.Point;
-import android.graphics.Rect;
-import com.android.internal.app.IAssistScreenshotReceiver;
-import com.android.internal.os.IResultReceiver;
-import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.internal.policy.IShortcutService;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
-
-import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
@@ -35,7 +27,12 @@
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
 
-import java.lang.Override;
+import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.IShortcutService;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodClient;
 
 /**
  * Basic implementation of {@link IWindowManager} so that {@link Display} (and