Initial implementation of snapshots

All this functionality is hidden behind a flag. If this flag is
active, we disable the regular screenshots.

Instead, we take a screenshot when an app transition for which a
task is disappearing is starting. The screenshot gets stored
into a gralloc buffer. SystemUI uses a new method to retrieve
a snapshot gralloc buffer and then draws it using GraphicBuffer.
createHardwareBitmap().

When starting an existing activity in an existing tasks, or when
bringing an existing tasks to front from recents, we add a new
snapshot starting window. For that, we reuse the existing
starting window, but when creating the window, we use a fake
window that draws the contents of the starting window.

Test: runtest frameworks-services -c
com.android.server.wm.TaskSnapshotControllerTest
Bug: 31339431
Change-Id: If72df07b3e56f30413db5029d0887b8c9665aaf4
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()?