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
This commit is contained in:
Jorim Jaggi
2017-03-14 18:21:40 +01:00
parent 0fe7ce968b
commit 8f4fe6eccb
6 changed files with 114 additions and 12 deletions

View File

@ -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 */);
}
/**

View File

@ -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()));
}
}

View File

@ -80,7 +80,8 @@
<receiver android:name="TrackTimeReceiver" />
<receiver android:name="AlarmSpamReceiver" />
<activity android:name="DisableScreenshotsActivity"
android:label="DisableScreenshots">
android:label="DisableScreenshots"
android:theme="@style/DisableScreenshots">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright (C) 2017 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.
-->
<resources>
<color name="blue">#0000ff</color>
</resources>

View File

@ -22,4 +22,8 @@
<item name="android:windowEnterAnimation">@anim/slow_enter</item>
<item name="android:windowExitAnimation">@anim/slow_exit</item>
</style>
<style name="DisableScreenshots" parent="@android:style/Theme.Material">
<item name="android:colorBackground">@color/blue</item>
<item name="android:windowBackground">@color/blue</item>
</style>
</resources>

View File

@ -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);
}
}