Loading services/core/java/com/android/server/wm/TaskSnapshotController.java +74 −8 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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)) { 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); Loading Loading @@ -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 */); } /** Loading services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java +6 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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())); } } tests/ActivityTests/AndroidManifest.xml +2 −1 Original line number Diff line number Diff line Loading @@ -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" /> Loading tests/ActivityTests/res/values/colors.xml 0 → 100644 +18 −0 Original line number Diff line number Diff line <?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> No newline at end of file tests/ActivityTests/res/values/themes.xml +4 −0 Original line number Diff line number Diff line Loading @@ -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> Loading
services/core/java/com/android/server/wm/TaskSnapshotController.java +74 −8 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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)) { 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); Loading Loading @@ -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 */); } /** Loading
services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java +6 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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())); } }
tests/ActivityTests/AndroidManifest.xml +2 −1 Original line number Diff line number Diff line Loading @@ -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" /> Loading
tests/ActivityTests/res/values/colors.xml 0 → 100644 +18 −0 Original line number Diff line number Diff line <?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> No newline at end of file
tests/ActivityTests/res/values/themes.xml +4 −0 Original line number Diff line number Diff line Loading @@ -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>