diff options
3 files changed, 66 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index bc7f33021c77..ecf9067b55c9 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -18,6 +18,8 @@ package com.android.server.wm; import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS; +import static com.android.server.wm.TaskSnapshotPersister.DISABLE_FULL_SIZED_BITMAPS; +import static com.android.server.wm.TaskSnapshotPersister.REDUCED_SCALE; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -188,7 +190,8 @@ class TaskSnapshotController { */ @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk, boolean reducedResolution) { - return mCache.getSnapshot(taskId, userId, restoreFromDisk, reducedResolution); + return mCache.getSnapshot(taskId, userId, restoreFromDisk, reducedResolution + || DISABLE_FULL_SIZED_BITMAPS); } /** @@ -209,14 +212,16 @@ class TaskSnapshotController { if (mainWindow == null) { return null; } + final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic(); + final float scaleFraction = isLowRamDevice ? REDUCED_SCALE : 1f; final GraphicBuffer buffer = top.mDisplayContent.screenshotApplicationsToBuffer(top.token, - -1, -1, false, 1.0f, false, true); + -1, -1, false, scaleFraction, false, true); if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) { return null; } return new TaskSnapshot(buffer, top.getConfiguration().orientation, - minRect(mainWindow.mContentInsets, mainWindow.mStableInsets), false /* reduced */, - 1f /* scale */); + minRect(mainWindow.mContentInsets, mainWindow.mStableInsets), + isLowRamDevice /* reduced */, scaleFraction /* scale */); } private boolean shouldDisableSnapshots() { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index f90b3fb6c1de..1252aee14964 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -21,6 +21,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.TestApi; +import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; @@ -53,6 +54,7 @@ class TaskSnapshotPersister { private static final String SNAPSHOTS_DIRNAME = "snapshots"; private static final String REDUCED_POSTFIX = "_reduced"; static final float REDUCED_SCALE = 0.5f; + static final boolean DISABLE_FULL_SIZED_BITMAPS = ActivityManager.isLowRamDeviceStatic(); private static final long DELAY_MS = 100; private static final int QUALITY = 95; private static final String PROTO_EXTENSION = ".proto"; @@ -183,6 +185,11 @@ class TaskSnapshotPersister { } File getBitmapFile(int taskId, int userId) { + // Full sized bitmaps are disabled on low ram devices + if (DISABLE_FULL_SIZED_BITMAPS) { + Slog.wtf(TAG, "This device does not support full sized resolution bitmaps."); + return null; + } return new File(getDirectory(userId), taskId + BITMAP_EXTENSION); } @@ -197,11 +204,15 @@ class TaskSnapshotPersister { private void deleteSnapshot(int taskId, int userId) { final File protoFile = getProtoFile(taskId, userId); - final File bitmapFile = getBitmapFile(taskId, userId); final File bitmapReducedFile = getReducedResolutionBitmapFile(taskId, userId); protoFile.delete(); - bitmapFile.delete(); bitmapReducedFile.delete(); + + // Low ram devices do not have a full sized file to delete + if (!DISABLE_FULL_SIZED_BITMAPS) { + final File bitmapFile = getBitmapFile(taskId, userId); + bitmapFile.delete(); + } } interface DirectoryResolver { @@ -323,7 +334,6 @@ class TaskSnapshotPersister { boolean writeBuffer() { final File file = getBitmapFile(mTaskId, mUserId); - final File reducedFile = getReducedResolutionBitmapFile(mTaskId, mUserId); final Bitmap bitmap = Bitmap.createHardwareBitmap(mSnapshot.getSnapshot()); if (bitmap == null) { Slog.e(TAG, "Invalid task snapshot hw bitmap"); @@ -331,18 +341,32 @@ class TaskSnapshotPersister { } final Bitmap swBitmap = bitmap.copy(Config.ARGB_8888, false /* isMutable */); - final Bitmap reduced = Bitmap.createScaledBitmap(swBitmap, - (int) (bitmap.getWidth() * REDUCED_SCALE), - (int) (bitmap.getHeight() * REDUCED_SCALE), true /* filter */); + final File reducedFile = getReducedResolutionBitmapFile(mTaskId, mUserId); + final Bitmap reduced = mSnapshot.isReducedResolution() + ? swBitmap + : Bitmap.createScaledBitmap(swBitmap, + (int) (bitmap.getWidth() * REDUCED_SCALE), + (int) (bitmap.getHeight() * REDUCED_SCALE), true /* filter */); try { - FileOutputStream fos = new FileOutputStream(file); - swBitmap.compress(JPEG, QUALITY, fos); - fos.close(); FileOutputStream reducedFos = new FileOutputStream(reducedFile); reduced.compress(JPEG, QUALITY, reducedFos); reducedFos.close(); } catch (IOException e) { - Slog.e(TAG, "Unable to open " + file + " or " + reducedFile +" for persisting.", e); + Slog.e(TAG, "Unable to open " + reducedFile +" for persisting.", e); + return false; + } + + // For snapshots with reduced resolution, do not create or save full sized bitmaps + if (mSnapshot.isReducedResolution()) { + return true; + } + + try { + FileOutputStream fos = new FileOutputStream(file); + swBitmap.compress(JPEG, QUALITY, fos); + fos.close(); + } catch (IOException e) { + Slog.e(TAG, "Unable to open " + file + " for persisting.", e); return false; } return true; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 0610b945d20e..4698d72567c4 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -320,6 +320,10 @@ class TaskSnapshotSurface implements StartingSurface { mChildSurfaceControl.show(); mChildSurfaceControl.setWindowCrop(crop); mChildSurfaceControl.setPosition(frame.left, frame.top); + + // Scale the mismatch dimensions to fill the task bounds + final float scale = 1 / mSnapshot.getScale(); + mChildSurfaceControl.setMatrix(scale, 0, 0, scale); } finally { SurfaceControl.closeTransaction(); } @@ -332,6 +336,11 @@ class TaskSnapshotSurface implements StartingSurface { mSurface.release(); } + /** + * Calculates the snapshot crop in snapshot coordinate space. + * + * @return crop rect in snapshot coordinate space. + */ @VisibleForTesting Rect calculateSnapshotCrop() { final Rect rect = new Rect(); @@ -340,16 +349,28 @@ class TaskSnapshotSurface implements StartingSurface { // Let's remove all system decorations except the status bar, but only if the task is at the // very top of the screen. - rect.inset(insets.left, mTaskBounds.top != 0 ? insets.top : 0, insets.right, insets.bottom); + rect.inset((int) (insets.left * mSnapshot.getScale()), + mTaskBounds.top != 0 ? (int) (insets.top * mSnapshot.getScale()) : 0, + (int) (insets.right * mSnapshot.getScale()), + (int) (insets.bottom * mSnapshot.getScale())); return rect; } + /** + * Calculates the snapshot frame in window coordinate space from crop. + * + * @param crop rect that is in snapshot coordinate space. + */ @VisibleForTesting Rect calculateSnapshotFrame(Rect crop) { final Rect frame = new Rect(crop); + final float scale = mSnapshot.getScale(); + + // Rescale the frame from snapshot to window coordinate space + frame.scale(1 / scale); // By default, offset it to to top/left corner - frame.offsetTo(-crop.left, -crop.top); + frame.offsetTo((int) (-crop.left / scale), (int) (-crop.top / scale)); // However, we also need to make space for the navigation bar on the left side. final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left, |