From 8f4fe6eccbc3849686f08389cb5868f2d59f5fbb Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Tue, 14 Mar 2017 18:21:40 +0100 Subject: [PATCH] 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 --- .../server/wm/TaskSnapshotController.java | 82 +++++++++++++++++-- .../server/wm/TaskSnapshotControllerTest.java | 9 +- tests/ActivityTests/AndroidManifest.xml | 3 +- tests/ActivityTests/res/values/colors.xml | 18 ++++ tests/ActivityTests/res/values/themes.xml | 4 + .../activity/DisableScreenshotsActivity.java | 10 +++ 6 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 tests/ActivityTests/res/values/colors.xml diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 4ae6dbe21721a..b8d0b8c096fe7 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 @@ import java.io.PrintWriter; */ 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 @@ class TaskSnapshotController { 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 @@ class TaskSnapshotController { } @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 45a7999488010..275234095887f 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 @@ 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 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 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { } @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())); } } diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml index 4dd51dcc7d095..64cdcf78fdcc3 100644 --- a/tests/ActivityTests/AndroidManifest.xml +++ b/tests/ActivityTests/AndroidManifest.xml @@ -80,7 +80,8 @@ + android:label="DisableScreenshots" + android:theme="@style/DisableScreenshots"> diff --git a/tests/ActivityTests/res/values/colors.xml b/tests/ActivityTests/res/values/colors.xml new file mode 100644 index 0000000000000..99257228dc483 --- /dev/null +++ b/tests/ActivityTests/res/values/colors.xml @@ -0,0 +1,18 @@ + + + + #0000ff + \ No newline at end of file diff --git a/tests/ActivityTests/res/values/themes.xml b/tests/ActivityTests/res/values/themes.xml index 67f5938ff2177..b8dd83039ed89 100644 --- a/tests/ActivityTests/res/values/themes.xml +++ b/tests/ActivityTests/res/values/themes.xml @@ -22,4 +22,8 @@ @anim/slow_enter @anim/slow_exit + diff --git a/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java b/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java index de24ca2ac9e84..fa5724ea64bcb 100644 --- a/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java +++ b/tests/ActivityTests/src/com/google/android/test/activity/DisableScreenshotsActivity.java @@ -20,6 +20,7 @@ import android.annotation.Nullable; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; +import android.os.SystemClock; /** * Activity for which screenshotting is disabled. @@ -32,4 +33,13 @@ public class DisableScreenshotsActivity extends Activity { setDisablePreviewScreenshots(true); getWindow().getDecorView().setBackgroundColor(Color.RED); } + + @Override + protected void onResume() { + super.onResume(); + + // This is to simulate slowness over resuming the app, such that we have plenty of time to + // see the starting window. + SystemClock.sleep(500); + } }