When snapshots are disabled, fill it with single color.

Test: Launch DisableScreenshotsActivity, go to recents, make sure
content is blue. Reopen activity from home, make sure starting
window is blue.

Bug: 31339431
Change-Id: I29689774c3cdcb784d8f5bfa4f947a6f35b91e01
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 4ae6dbe..b8d0b8c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -17,11 +17,16 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
+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_RARELY;
+import static android.graphics.PixelFormat.RGBA_8888;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.TaskSnapshot;
+import android.graphics.Canvas;
 import android.graphics.GraphicBuffer;
 import android.os.Environment;
 import android.util.ArraySet;
@@ -48,6 +53,26 @@
  */
 class TaskSnapshotController {
 
+    /**
+     * Return value for {@link #getSnapshotMode}: We are allowed to take a real screenshot to be
+     * used as the snapshot.
+     */
+    @VisibleForTesting
+    static final int SNAPSHOT_MODE_REAL = 0;
+
+    /**
+     * Return value for {@link #getSnapshotMode}: We are not allowed to take a real screenshot but
+     * we should try to use the app theme to create a dummy representation of the app.
+     */
+    @VisibleForTesting
+    static final int SNAPSHOT_MODE_APP_THEME = 1;
+
+    /**
+     * Return value for {@link #getSnapshotMode}: We aren't allowed to take any snapshot.
+     */
+    @VisibleForTesting
+    static final int SNAPSHOT_MODE_NONE = 2;
+
     private final WindowManagerService mService;
 
     private final TaskSnapshotCache mCache;
@@ -88,10 +113,21 @@
         getClosingTasks(closingApps, mTmpTasks);
         for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
             final Task task = mTmpTasks.valueAt(i);
-            if (!canSnapshotTask(task)) {
-                continue;
+            final int mode = getSnapshotMode(task);
+            final TaskSnapshot snapshot;
+            switch (mode) {
+                case SNAPSHOT_MODE_NONE:
+                    continue;
+                case SNAPSHOT_MODE_APP_THEME:
+                    snapshot = drawAppThemeSnapshot(task);
+                    break;
+                case SNAPSHOT_MODE_REAL:
+                    snapshot = snapshotTask(task);
+                    break;
+                default:
+                    snapshot = null;
+                    break;
             }
-            final TaskSnapshot snapshot = snapshotTask(task);
             if (snapshot != null) {
                 mCache.putSnapshot(task, snapshot);
                 mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
@@ -153,12 +189,42 @@
     }
 
     @VisibleForTesting
-    boolean canSnapshotTask(Task task) {
-        // TODO: Figure out what happens when snapshots are disabled. Can we draw a splash screen
-        // instead?
+    int getSnapshotMode(Task task) {
         final AppWindowToken topChild = task.getTopChild();
-        return !StackId.isHomeOrRecentsStack(task.mStack.mStackId)
-                && topChild != null && !topChild.shouldDisablePreviewScreenshots();
+        if (StackId.isHomeOrRecentsStack(task.mStack.mStackId)) {
+            return SNAPSHOT_MODE_NONE;
+        } else if (topChild != null && topChild.shouldDisablePreviewScreenshots()) {
+            return SNAPSHOT_MODE_APP_THEME;
+        } else {
+            return SNAPSHOT_MODE_REAL;
+        }
+    }
+
+    /**
+     * If we are not allowed to take a real screenshot, this attempts to represent the app as best
+     * as possible by using the theme's window background.
+     */
+    private TaskSnapshot drawAppThemeSnapshot(Task task) {
+        final AppWindowToken topChild = task.getTopChild();
+        if (topChild == null) {
+            return null;
+        }
+        final WindowState mainWindow = topChild.findMainWindow();
+        if (mainWindow == null) {
+            return null;
+        }
+        final int color = task.getTaskDescription().getBackgroundColor();
+        final GraphicBuffer buffer = GraphicBuffer.create(mainWindow.getFrameLw().width(),
+                mainWindow.getFrameLw().height(),
+                RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_WRITE_RARELY | USAGE_SW_READ_NEVER);
+        if (buffer == null) {
+            return null;
+        }
+        final Canvas c = buffer.lockCanvas();
+        c.drawColor(color);
+        buffer.unlockCanvasAndPost(c);
+        return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
+                mainWindow.mStableInsets, false /* reduced */, 1.0f /* scale */);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 45a7999..2752340 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -18,6 +18,7 @@
 
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import static com.android.server.wm.TaskSnapshotController.*;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -72,13 +73,15 @@
     }
 
     @Test
-    public void testSnapshotsDisabled() throws Exception {
+    public void testGetSnapshotMode() throws Exception {
         final WindowState disabledWindow = createWindow(null,
                 FIRST_APPLICATION_WINDOW, sDisplayContent, "disabledWindow");
         disabledWindow.mAppToken.setDisablePreviewSnapshots(true);
-        assertFalse(sWm.mTaskSnapshotController.canSnapshotTask(disabledWindow.getTask()));
+        assertEquals(SNAPSHOT_MODE_APP_THEME,
+                sWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
         final WindowState normalWindow = createWindow(null,
                 FIRST_APPLICATION_WINDOW, sDisplayContent, "normalWindow");
-        assertTrue(sWm.mTaskSnapshotController.canSnapshotTask(normalWindow.getTask()));
+        assertEquals(SNAPSHOT_MODE_REAL,
+                sWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask()));
     }
 }