Add API to disable snapshotting of activities

Test: runtest frameworks-services -c
com.android.server.wm.TaskSnapshotControllerTest
Test: Launch DisableScreenshotsActivity, go to recents, make sure
content is white.
Bug: 31339431

Change-Id: I329925d2fca389e561da3389a67fe888b5bb1033
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 18befef..2821446 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -128,7 +128,6 @@
 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.MATCH_TASK_IN_STACKS_ONLY;
 import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
@@ -149,8 +148,6 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
-import static java.lang.Integer.MAX_VALUE;
-
 import android.Manifest;
 import android.Manifest.permission;
 import android.annotation.NonNull;
@@ -10826,6 +10823,25 @@
         }
     }
 
+    @Override
+    public void setDisablePreviewScreenshots(IBinder token, boolean disable)
+            throws RemoteException {
+        synchronized (this) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                Slog.w(TAG, "setDisablePreviewScreenshots: Unable to find activity for token="
+                        + token);
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                r.setDisablePreviewScreenshots(disable);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
     // =========================================================
     // CONTENT PROVIDERS
     // =========================================================
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7868fdf..ecaa751 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1973,6 +1973,10 @@
                 task.taskId, requestedOrientation);
     }
 
+    void setDisablePreviewScreenshots(boolean disable) {
+        mWindowContainerController.setDisablePreviewScreenshots(disable);
+    }
+
     /**
      * Set the last reported global configuration to the client. Should be called whenever a new
      * global configuration is sent to the client for this activity.
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index bd38be4..ef3d87c 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -35,7 +35,6 @@
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Trace;
 import android.util.Slog;
 import android.view.IApplicationToken;
@@ -228,7 +227,7 @@
             boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
             int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
             boolean alwaysFocusable, AppWindowContainerController controller) {
-        return  new AppWindowToken(service, token, voiceInteraction, dc,
+        return new AppWindowToken(service, token, voiceInteraction, dc,
                 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
                 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
                 controller);
@@ -298,6 +297,17 @@
         }
     }
 
+    public void setDisablePreviewScreenshots(boolean disable) {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
+                        + " token: " + mToken);
+                return;
+            }
+            mContainer.setDisablePreviewSnapshots(disable);
+        }
+    }
+
     public void setVisibility(boolean visible) {
         synchronized(mWindowMap) {
             if (mContainer == null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index c20ee97..27e9dea 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -166,6 +166,8 @@
     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
 
+    private boolean mDisbalePreviewScreenshots;
+
     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
@@ -1433,6 +1435,14 @@
         return candidate;
     }
 
+    void setDisablePreviewSnapshots(boolean disable) {
+        mDisbalePreviewScreenshots = disable;
+    }
+
+    boolean shouldDisablePreviewScreenshots() {
+        return mDisbalePreviewScreenshots;
+    }
+
     @Override
     int getAnimLayerAdjustment() {
         return mAppAnimator.animLayerAdjustment;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 469a8a7..4ae6dbe 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -152,8 +152,13 @@
         }
     }
 
-    private boolean canSnapshotTask(Task task) {
-        return !StackId.isHomeOrRecentsStack(task.mStack.mStackId);
+    @VisibleForTesting
+    boolean canSnapshotTask(Task task) {
+        // TODO: Figure out what happens when snapshots are disabled. Can we draw a splash screen
+        // instead?
+        final AppWindowToken topChild = task.getTopChild();
+        return !StackId.isHomeOrRecentsStack(task.mStack.mStackId)
+                && topChild != null && !topChild.shouldDisablePreviewScreenshots();
     }
 
     /**