summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Peter Kalauskas <peskal@google.com> 2020-02-25 18:29:50 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-02-25 18:29:50 +0000
commit81a320279e8f917c143b79aed5c8fd83d9456777 (patch)
tree96cf5111343d79679081f49de3de64aeba844b05
parent7def6932cb9734626310c41ca538243e743f589d (diff)
parent84f02a81e865cecf42e938b00b28c10091708373 (diff)
Merge changes from topic "new-task-snapshots-rvc-dev" into rvc-dev
* changes: Disable reduced scale if reduced scale config is 0 Store original task width and height instead of scale
-rw-r--r--core/java/android/app/ActivityManager.java70
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java4
-rw-r--r--proto/src/task_snapshot.proto7
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java69
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotLoader.java119
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotPersister.java100
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java41
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java171
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java17
12 files changed, 467 insertions, 174 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 82fdb90be165..b51bbdf62286 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2012,15 +2012,16 @@ public class ActivityManager {
/** See {@link android.view.Surface.Rotation} */
@Surface.Rotation
private int mRotation;
+ /** The size of the snapshot before scaling */
+ private final Point mTaskSize;
private final Rect mContentInsets;
- // Whether this snapshot is a down-sampled version of the full resolution, used mainly for
- // low-ram devices
+ // Whether this snapshot is a down-sampled version of the high resolution snapshot, used
+ // mainly for loading snapshots quickly from disk when user is flinging fast
private final boolean mIsLowResolution;
// Whether or not the snapshot is a real snapshot or an app-theme generated snapshot due to
// the task having a secure window or having previews disabled
private final boolean mIsRealSnapshot;
private final int mWindowingMode;
- private final float mScale;
private final int mSystemUiVisibility;
private final boolean mIsTranslucent;
// Must be one of the named color spaces, otherwise, always use SRGB color space.
@@ -2028,9 +2029,9 @@ public class ActivityManager {
public TaskSnapshot(long id,
@NonNull ComponentName topActivityComponent, GraphicBuffer snapshot,
- @NonNull ColorSpace colorSpace, int orientation, int rotation, Rect contentInsets,
- boolean isLowResolution, float scale, boolean isRealSnapshot, int windowingMode,
- int systemUiVisibility, boolean isTranslucent) {
+ @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize,
+ Rect contentInsets, boolean isLowResolution, boolean isRealSnapshot,
+ int windowingMode, int systemUiVisibility, boolean isTranslucent) {
mId = id;
mTopActivityComponent = topActivityComponent;
mSnapshot = snapshot;
@@ -2038,9 +2039,9 @@ public class ActivityManager {
? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace;
mOrientation = orientation;
mRotation = rotation;
+ mTaskSize = new Point(taskSize);
mContentInsets = new Rect(contentInsets);
mIsLowResolution = isLowResolution;
- mScale = scale;
mIsRealSnapshot = isRealSnapshot;
mWindowingMode = windowingMode;
mSystemUiVisibility = systemUiVisibility;
@@ -2057,9 +2058,9 @@ public class ActivityManager {
: ColorSpace.get(ColorSpace.Named.SRGB);
mOrientation = source.readInt();
mRotation = source.readInt();
+ mTaskSize = source.readParcelable(null /* classLoader */);
mContentInsets = source.readParcelable(null /* classLoader */);
mIsLowResolution = source.readBoolean();
- mScale = source.readFloat();
mIsRealSnapshot = source.readBoolean();
mWindowingMode = source.readInt();
mSystemUiVisibility = source.readInt();
@@ -2111,6 +2112,14 @@ public class ActivityManager {
}
/**
+ * @return The size of the task at the point this snapshot was taken.
+ */
+ @UnsupportedAppUsage
+ public Point getTaskSize() {
+ return mTaskSize;
+ }
+
+ /**
* @return The system/content insets on the snapshot. These can be clipped off in order to
* remove any areas behind system bars in the snapshot.
*/
@@ -2159,14 +2168,6 @@ public class ActivityManager {
return mSystemUiVisibility;
}
- /**
- * @return The scale this snapshot was taken in.
- */
- @UnsupportedAppUsage
- public float getScale() {
- return mScale;
- }
-
@Override
public int describeContents() {
return 0;
@@ -2180,9 +2181,9 @@ public class ActivityManager {
dest.writeInt(mColorSpace.getId());
dest.writeInt(mOrientation);
dest.writeInt(mRotation);
+ dest.writeParcelable(mTaskSize, 0);
dest.writeParcelable(mContentInsets, 0);
dest.writeBoolean(mIsLowResolution);
- dest.writeFloat(mScale);
dest.writeBoolean(mIsRealSnapshot);
dest.writeInt(mWindowingMode);
dest.writeInt(mSystemUiVisibility);
@@ -2200,9 +2201,11 @@ public class ActivityManager {
+ " mColorSpace=" + mColorSpace.toString()
+ " mOrientation=" + mOrientation
+ " mRotation=" + mRotation
+ + " mTaskSize=" + mTaskSize.toString()
+ " mContentInsets=" + mContentInsets.toShortString()
- + " mIsLowResolution=" + mIsLowResolution + " mScale=" + mScale
- + " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode
+ + " mIsLowResolution=" + mIsLowResolution
+ + " mIsRealSnapshot=" + mIsRealSnapshot
+ + " mWindowingMode=" + mWindowingMode
+ " mSystemUiVisibility=" + mSystemUiVisibility
+ " mIsTranslucent=" + mIsTranslucent;
}
@@ -2224,9 +2227,8 @@ public class ActivityManager {
private ColorSpace mColorSpace;
private int mOrientation;
private int mRotation;
+ private Point mTaskSize;
private Rect mContentInsets;
- private boolean mIsLowResolution;
- private float mScaleFraction;
private boolean mIsRealSnapshot;
private int mWindowingMode;
private int mSystemUiVisibility;
@@ -2263,25 +2265,16 @@ public class ActivityManager {
return this;
}
- public Builder setContentInsets(Rect contentInsets) {
- mContentInsets = contentInsets;
- return this;
- }
-
/**
- * Set to true if this is a low-resolution snapshot stored in *_reduced.jpg.
+ * Sets the original size of the task
*/
- public Builder setIsLowResolution(boolean isLowResolution) {
- mIsLowResolution = isLowResolution;
+ public Builder setTaskSize(Point size) {
+ mTaskSize = size;
return this;
}
- public float getScaleFraction() {
- return mScaleFraction;
- }
-
- public Builder setScaleFraction(float scaleFraction) {
- mScaleFraction = scaleFraction;
+ public Builder setContentInsets(Rect contentInsets) {
+ mContentInsets = contentInsets;
return this;
}
@@ -2322,9 +2315,12 @@ public class ActivityManager {
mColorSpace,
mOrientation,
mRotation,
+ mTaskSize,
mContentInsets,
- mIsLowResolution,
- mScaleFraction,
+ // When building a TaskSnapshot with the Builder class, isLowResolution
+ // is always false. Low-res snapshots are only created when loading from
+ // disk.
+ false /* isLowResolution */,
mIsRealSnapshot,
mWindowingMode,
mSystemUiVisibility,
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 490892ed9310..fb9158fb2e98 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2752,7 +2752,9 @@
<!-- The amount to scale reduced scale snapshots for Overview and snapshot starting windows.
Reduced scale snapshots are loaded before full screen snapshots to improve load times and
- minimize the chance the user will see an empty task card. -->
+ minimize the chance the user will see an empty task card. If set to 0, reduced scale
+ snapshots are disabled, and snapshots will only be stored at config_highResTaskSnapshotScale
+ -->
<item name="config_lowResTaskSnapshotScale" format="float" type="dimen">0.5</item>
<!-- Feature flag to store TaskSnapshot in 16 bit pixel format to save memory. -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 4474a49e55b8..eca6ebf7f8e5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -62,7 +62,9 @@ public class ThumbnailData {
orientation = snapshot.getOrientation();
rotation = snapshot.getRotation();
reducedResolution = snapshot.isLowResolution();
- scale = snapshot.getScale();
+ // TODO(b/149579527): Pass task size instead of computing scale.
+ // Assume width and height were scaled the same; compute scale only for width
+ scale = (float) thumbnail.getWidth() / snapshot.getTaskSize().x;
isRealSnapshot = snapshot.isRealSnapshot();
isTranslucent = snapshot.isTranslucent();
windowingMode = snapshot.getWindowingMode();
diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto
index 789019ce8b75..2006fb3d7bf1 100644
--- a/proto/src/task_snapshot.proto
+++ b/proto/src/task_snapshot.proto
@@ -32,7 +32,12 @@
int32 system_ui_visibility = 8;
bool is_translucent = 9;
string top_activity_component = 10;
- float scale = 11;
+ // deprecated because original width and height are stored now instead of the scale.
+ float legacy_scale = 11 [deprecated=true];
int64 id = 12;
int32 rotation = 13;
+ // The task width when the snapshot was taken
+ int32 task_width = 14;
+ // The task height when the snapshot was taken
+ int32 task_height = 15;
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 5c73f92ee6cd..f83b0522846c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -18,19 +18,18 @@ package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static com.android.server.wm.TaskSnapshotPersister.DISABLE_HIGH_RES_BITMAPS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
@@ -89,14 +88,6 @@ class TaskSnapshotController {
@VisibleForTesting
static final int SNAPSHOT_MODE_NONE = 2;
- /**
- * Constant for <code>scaleFactor</code> when calling {@link #snapshotTask} which is
- * interpreted as using the most appropriate scale ratio for the system.
- * This may yield a smaller ratio on low memory devices.
- */
- @VisibleForTesting
- static final float SNAPSHOT_SCALE_AUTO = -1f;
-
private final WindowManagerService mService;
private final TaskSnapshotCache mCache;
@@ -229,7 +220,7 @@ class TaskSnapshotController {
@Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk,
boolean isLowResolution) {
return mCache.getSnapshot(taskId, userId, restoreFromDisk, isLowResolution
- || DISABLE_HIGH_RES_BITMAPS);
+ && mPersister.enableLowResSnapshots());
}
/**
@@ -273,8 +264,6 @@ class TaskSnapshotController {
* information from the task and populates the builder.
*
* @param task the task to capture
- * @param scaleFraction the scale fraction between 0-1.0, or {@link #SNAPSHOT_SCALE_AUTO}
- * to automatically select
* @param pixelFormat the desired pixel format, or {@link PixelFormat#UNKNOWN} to
* automatically select
* @param builder the snapshot builder to populate
@@ -282,8 +271,7 @@ class TaskSnapshotController {
* @return true if the state of the task is ok to proceed
*/
@VisibleForTesting
- boolean prepareTaskSnapshot(Task task, float scaleFraction, int pixelFormat,
- TaskSnapshot.Builder builder) {
+ boolean prepareTaskSnapshot(Task task, int pixelFormat, TaskSnapshot.Builder builder) {
if (!mService.mPolicy.isScreenOn()) {
if (DEBUG_SCREENSHOT) {
Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
@@ -314,18 +302,6 @@ class TaskSnapshotController {
builder.setId(System.currentTimeMillis());
builder.setContentInsets(getInsets(mainWindow));
- final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
-
- if (scaleFraction == SNAPSHOT_SCALE_AUTO) {
- builder.setScaleFraction(isLowRamDevice
- ? mPersister.getLowResScale()
- : mHighResTaskSnapshotScale);
- builder.setIsLowResolution(isLowRamDevice);
- } else {
- builder.setScaleFraction(scaleFraction);
- builder.setIsLowResolution(scaleFraction < 1.0f);
- }
-
final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0;
@@ -351,13 +327,23 @@ class TaskSnapshotController {
@Nullable
SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
+ TaskSnapshot.Builder builder) {
+ Point taskSize = new Point();
+ final SurfaceControl.ScreenshotGraphicBuffer taskSnapshot = createTaskSnapshot(task,
+ mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize);
+ builder.setTaskSize(taskSize);
+ return taskSnapshot;
+ }
+
+ @Nullable
+ SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
float scaleFraction) {
- return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888);
+ return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888, null);
}
@Nullable
SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
- float scaleFraction, int pixelFormat) {
+ float scaleFraction, int pixelFormat, Point outTaskSize) {
if (task.getSurfaceControl() == null) {
if (DEBUG_SCREENSHOT) {
Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task);
@@ -369,6 +355,10 @@ class TaskSnapshotController {
final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
SurfaceControl.captureLayers(
task.getSurfaceControl(), mTmpRect, scaleFraction, pixelFormat);
+ if (outTaskSize != null) {
+ outTaskSize.x = mTmpRect.width();
+ outTaskSize.y = mTmpRect.height();
+ }
final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer()
: null;
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
@@ -379,21 +369,20 @@ class TaskSnapshotController {
@Nullable
TaskSnapshot snapshotTask(Task task) {
- return snapshotTask(task, SNAPSHOT_SCALE_AUTO, PixelFormat.UNKNOWN);
+ return snapshotTask(task, PixelFormat.UNKNOWN);
}
@Nullable
- TaskSnapshot snapshotTask(Task task, float scaleFraction, int pixelFormat) {
+ TaskSnapshot snapshotTask(Task task, int pixelFormat) {
TaskSnapshot.Builder builder = new TaskSnapshot.Builder();
- if (!prepareTaskSnapshot(task, scaleFraction, pixelFormat, builder)) {
+ if (!prepareTaskSnapshot(task, pixelFormat, builder)) {
// Failed some pre-req. Has been logged.
return null;
}
final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
- createTaskSnapshot(task, builder.getScaleFraction(),
- builder.getPixelFormat());
+ createTaskSnapshot(task, builder);
if (screenshotBuffer == null) {
// Failed to acquire image. Has been logged.
@@ -472,8 +461,10 @@ class TaskSnapshotController {
final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(),
mHighResTaskSnapshotScale, mainWindow.getRequestedInsetsState());
- final int width = (int) (task.getBounds().width() * mHighResTaskSnapshotScale);
- final int height = (int) (task.getBounds().height() * mHighResTaskSnapshotScale);
+ final int taskWidth = task.getBounds().width();
+ final int taskHeight = task.getBounds().height();
+ final int width = (int) (taskWidth * mHighResTaskSnapshotScale);
+ final int height = (int) (taskHeight * mHighResTaskSnapshotScale);
final RenderNode node = RenderNode.create("TaskSnapshotController", null);
node.setLeftTopRightBottom(0, 0, width, height);
@@ -494,9 +485,9 @@ class TaskSnapshotController {
System.currentTimeMillis() /* id */,
topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(),
hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation,
- mainWindow.getWindowConfiguration().getRotation(),
- getInsets(mainWindow), ActivityManager.isLowRamDeviceStatic() /* isLowResolution */,
- mHighResTaskSnapshotScale, false /* isRealSnapshot */, task.getWindowingMode(),
+ mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight),
+ getInsets(mainWindow), false /* isLowResolution */,
+ false /* isRealSnapshot */, task.getWindowingMode(),
getSystemUiVisibility(task), false);
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index 01f3427d78e1..c20ce5f40bc2 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.content.ComponentName;
import android.graphics.Bitmap;
@@ -26,6 +27,7 @@ import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.GraphicBuffer;
+import android.graphics.Point;
import android.graphics.Rect;
import android.util.Slog;
@@ -52,28 +54,110 @@ class TaskSnapshotLoader {
mPersister = persister;
}
+ static class PreRLegacySnapshotConfig {
+ /**
+ * If isPreRLegacy is {@code true}, specifies the scale the snapshot was taken at
+ */
+ final float mScale;
+
+ /**
+ * If {@code true}, always load *_reduced.jpg file, no matter what was requested
+ */
+ final boolean mForceLoadReducedJpeg;
+
+ PreRLegacySnapshotConfig(float scale, boolean forceLoadReducedJpeg) {
+ mScale = scale;
+ mForceLoadReducedJpeg = forceLoadReducedJpeg;
+ }
+ }
+
+ /**
+ * When device is upgraded, we might be loading a legacy snapshot. In those cases,
+ * restore the scale based on how it was configured historically. See history of
+ * TaskSnapshotPersister for more information.
+ *
+ * | low_ram=false | low_ram=true
+ * +------------------------------------------------------------------------------+
+ * O | *.jpg = 100%, *_reduced.jpg = 50% |
+ * | +-----------------------------------------|
+ * P | | *.jpg = NONE, *_reduced.jpg = 60% |
+ * +------------------------------------+-----------------------------------------+
+ * Q | *.jpg = proto.scale, | *.jpg = NONE, |
+ * | *_reduced.jpg = 50% * proto.scale | *_reduced.jpg = proto.scale |
+ * +------------------------------------+-----------------------------------------+
+ *
+ * @return null if Android R, otherwise a PreRLegacySnapshotConfig object
+ */
+ PreRLegacySnapshotConfig getLegacySnapshotConfig(int taskWidth, float legacyScale,
+ boolean highResFileExists, boolean loadLowResolutionBitmap) {
+ float preRLegacyScale = 0;
+ boolean forceLoadReducedJpeg = false;
+ boolean isPreRLegacySnapshot = (taskWidth == 0);
+ if (!isPreRLegacySnapshot) {
+ return null;
+ }
+ final boolean isPreQLegacyProto = isPreRLegacySnapshot
+ && (Float.compare(legacyScale, 0f) == 0);
+
+ if (isPreQLegacyProto) {
+ // Android O or Android P
+ if (ActivityManager.isLowRamDeviceStatic() && !highResFileExists) {
+ // Android P w/ low_ram=true
+ preRLegacyScale = 0.6f;
+ // Force bitmapFile to always be *_reduced.jpg
+ forceLoadReducedJpeg = true;
+ } else {
+ // Android O, OR Android P w/ low_ram=false
+ preRLegacyScale = loadLowResolutionBitmap ? 0.5f : 1.0f;
+ }
+ } else if (isPreRLegacySnapshot) {
+ // If not pre-Q but is pre-R, then it must be Android Q
+ if (ActivityManager.isLowRamDeviceStatic()) {
+ preRLegacyScale = legacyScale;
+ // Force bitmapFile to always be *_reduced.jpg
+ forceLoadReducedJpeg = true;
+ } else {
+ preRLegacyScale =
+ loadLowResolutionBitmap ? 0.5f * legacyScale : legacyScale;
+ }
+ }
+ return new PreRLegacySnapshotConfig(preRLegacyScale, forceLoadReducedJpeg);
+ }
+
/**
* Loads a task from the disk.
* <p>
* Do not hold the window manager lock when calling this method, as we directly read data from
* disk here, which might be slow.
*
- * @param taskId The id of the task to load.
- * @param userId The id of the user the task belonged to.
- * @param isLowResolution Whether to load a reduced resolution version of the snapshot.
+ * @param taskId The id of the task to load.
+ * @param userId The id of the user the task belonged to.
+ * @param loadLowResolutionBitmap Whether to load a low resolution resolution version of the
+ * snapshot.
* @return The loaded {@link TaskSnapshot} or {@code null} if it couldn't be loaded.
*/
- TaskSnapshot loadTask(int taskId, int userId, boolean isLowResolution) {
+ TaskSnapshot loadTask(int taskId, int userId, boolean loadLowResolutionBitmap) {
final File protoFile = mPersister.getProtoFile(taskId, userId);
- final File bitmapFile = isLowResolution
- ? mPersister.getLowResolutionBitmapFile(taskId, userId)
- : mPersister.getHighResolutionBitmapFile(taskId, userId);
- if (bitmapFile == null || !protoFile.exists() || !bitmapFile.exists()) {
+ if (!protoFile.exists()) {
return null;
}
try {
final byte[] bytes = Files.readAllBytes(protoFile.toPath());
final TaskSnapshotProto proto = TaskSnapshotProto.parseFrom(bytes);
+ final File highResBitmap = mPersister.getHighResolutionBitmapFile(taskId, userId);
+
+ PreRLegacySnapshotConfig legacyConfig = getLegacySnapshotConfig(proto.taskWidth,
+ proto.legacyScale, highResBitmap.exists(), loadLowResolutionBitmap);
+
+ boolean forceLoadReducedJpeg =
+ legacyConfig != null && legacyConfig.mForceLoadReducedJpeg;
+ File bitmapFile = (loadLowResolutionBitmap || forceLoadReducedJpeg)
+ ? mPersister.getLowResolutionBitmapFile(taskId, userId) : highResBitmap;
+
+ if (!bitmapFile.exists()) {
+ return null;
+ }
+
final Options options = new Options();
options.inPreferredConfig = mPersister.use16BitFormat() && !proto.isTranslucent
? Config.RGB_565
@@ -99,13 +183,20 @@ class TaskSnapshotLoader {
final ComponentName topActivityComponent = ComponentName.unflattenFromString(
proto.topActivityComponent);
- // For legacy snapshots, restore the scale based on the reduced resolution state
- final float legacyScale = isLowResolution ? mPersister.getLowResScale() : 1f;
- final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale;
- return new TaskSnapshot(proto.id, topActivityComponent, buffer, hwBitmap.getColorSpace(),
- proto.orientation, proto.rotation,
+
+ Point taskSize;
+ if (legacyConfig != null) {
+ int taskWidth = (int) ((float) hwBitmap.getWidth() / legacyConfig.mScale);
+ int taskHeight = (int) ((float) hwBitmap.getHeight() / legacyConfig.mScale);
+ taskSize = new Point(taskWidth, taskHeight);
+ } else {
+ taskSize = new Point(proto.taskWidth, proto.taskHeight);
+ }
+
+ return new TaskSnapshot(proto.id, topActivityComponent, buffer,
+ hwBitmap.getColorSpace(), proto.orientation, proto.rotation, taskSize,
new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
- isLowResolution, scale, proto.isRealSnapshot, proto.windowingMode,
+ loadLowResolutionBitmap, proto.isRealSnapshot, proto.windowingMode,
proto.systemUiVisibility, proto.isTranslucent);
} catch (IOException e) {
Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 31212b8a6bd9..164d3e055e94 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -21,8 +21,8 @@ import static android.graphics.Bitmap.CompressFormat.JPEG;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.NonNull;
import android.annotation.TestApi;
-import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
@@ -52,8 +52,6 @@ class TaskSnapshotPersister {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM;
private static final String SNAPSHOTS_DIRNAME = "snapshots";
private static final String LOW_RES_FILE_POSTFIX = "_reduced";
- private static final float LOW_RAM_REDUCED_SCALE = .8f;
- static final boolean DISABLE_HIGH_RES_BITMAPS = ActivityManager.isLowRamDeviceStatic();
private static final long DELAY_MS = 100;
private static final int QUALITY = 95;
private static final String PROTO_EXTENSION = ".proto";
@@ -71,7 +69,8 @@ class TaskSnapshotPersister {
private boolean mStarted;
private final Object mLock = new Object();
private final DirectoryResolver mDirectoryResolver;
- private final float mLowResScale;
+ private final float mLowResScaleFactor;
+ private boolean mEnableLowResSnapshots;
private final boolean mUse16BitFormat;
/**
@@ -83,13 +82,29 @@ class TaskSnapshotPersister {
TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) {
mDirectoryResolver = resolver;
+ final float highResTaskSnapshotScale = service.mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_highResTaskSnapshotScale);
+ final float lowResTaskSnapshotScale = service.mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_lowResTaskSnapshotScale);
- if (ActivityManager.isLowRamDeviceStatic()) {
- mLowResScale = LOW_RAM_REDUCED_SCALE;
+ if (lowResTaskSnapshotScale < 0 || 1 <= lowResTaskSnapshotScale) {
+ throw new RuntimeException("Low-res scale must be between 0 and 1");
+ }
+ if (highResTaskSnapshotScale <= 0 || 1 < highResTaskSnapshotScale) {
+ throw new RuntimeException("High-res scale must be between 0 and 1");
+ }
+ if (highResTaskSnapshotScale <= lowResTaskSnapshotScale) {
+ throw new RuntimeException("High-res scale must be greater than low-res scale");
+ }
+
+ if (lowResTaskSnapshotScale > 0) {
+ mLowResScaleFactor = lowResTaskSnapshotScale / highResTaskSnapshotScale;
+ setEnableLowResSnapshots(true);
} else {
- mLowResScale = service.mContext.getResources().getFloat(
- com.android.internal.R.dimen.config_lowResTaskSnapshotScale);
+ mLowResScaleFactor = 0;
+ setEnableLowResSnapshots(false);
}
+
mUse16BitFormat = service.mContext.getResources().getBoolean(
com.android.internal.R.bool.config_use16BitTaskSnapshotPixelFormat);
}
@@ -155,13 +170,16 @@ class TaskSnapshotPersister {
}
}
+ boolean enableLowResSnapshots() {
+ return mEnableLowResSnapshots;
+ }
+
/**
- * Gets the scaling the persister uses for low resolution task snapshots.
- *
- * @return the lowResBitmap scale of task snapshots when they are set to be low res
+ * Not to be used. Only here for testing.
*/
- float getLowResScale() {
- return mLowResScale;
+ @VisibleForTesting
+ void setEnableLowResSnapshots(boolean enabled) {
+ mEnableLowResSnapshots = enabled;
}
/**
@@ -213,14 +231,10 @@ class TaskSnapshotPersister {
}
File getHighResolutionBitmapFile(int taskId, int userId) {
- // Full sized bitmaps are disabled on low ram devices
- if (DISABLE_HIGH_RES_BITMAPS) {
- Slog.wtf(TAG, "This device does not support full sized resolution bitmaps.");
- return null;
- }
return new File(getDirectory(userId), taskId + BITMAP_EXTENSION);
}
+ @NonNull
File getLowResolutionBitmapFile(int taskId, int userId) {
return new File(getDirectory(userId), taskId + LOW_RES_FILE_POSTFIX + BITMAP_EXTENSION);
}
@@ -234,11 +248,11 @@ class TaskSnapshotPersister {
final File protoFile = getProtoFile(taskId, userId);
final File bitmapLowResFile = getLowResolutionBitmapFile(taskId, userId);
protoFile.delete();
- bitmapLowResFile.delete();
-
- // Low ram devices do not have a full sized file to delete
- if (!DISABLE_HIGH_RES_BITMAPS) {
- final File bitmapFile = getHighResolutionBitmapFile(taskId, userId);
+ if (bitmapLowResFile.exists()) {
+ bitmapLowResFile.delete();
+ }
+ final File bitmapFile = getHighResolutionBitmapFile(taskId, userId);
+ if (bitmapFile.exists()) {
bitmapFile.delete();
}
}
@@ -343,6 +357,8 @@ class TaskSnapshotPersister {
final TaskSnapshotProto proto = new TaskSnapshotProto();
proto.orientation = mSnapshot.getOrientation();
proto.rotation = mSnapshot.getRotation();
+ proto.taskWidth = mSnapshot.getTaskSize().x;
+ proto.taskHeight = mSnapshot.getTaskSize().y;
proto.insetLeft = mSnapshot.getContentInsets().left;
proto.insetTop = mSnapshot.getContentInsets().top;
proto.insetRight = mSnapshot.getContentInsets().right;
@@ -352,7 +368,6 @@ class TaskSnapshotPersister {
proto.systemUiVisibility = mSnapshot.getSystemUiVisibility();
proto.isTranslucent = mSnapshot.isTranslucent();
proto.topActivityComponent = mSnapshot.getTopActivityComponent().flattenToString();
- proto.scale = mSnapshot.getScale();
proto.id = mSnapshot.getId();
final byte[] bytes = TaskSnapshotProto.toByteArray(proto);
final File file = getProtoFile(mTaskId, mUserId);
@@ -379,39 +394,38 @@ class TaskSnapshotPersister {
}
final Bitmap swBitmap = bitmap.copy(Config.ARGB_8888, false /* isMutable */);
- final Bitmap lowResBitmap = mSnapshot.isLowResolution()
- ? swBitmap
- : Bitmap.createScaledBitmap(swBitmap,
- (int) (bitmap.getWidth() * mLowResScale),
- (int) (bitmap.getHeight() * mLowResScale), true /* filter */);
- final File lowResFile = getLowResolutionBitmapFile(mTaskId, mUserId);
+ final File file = getHighResolutionBitmapFile(mTaskId, mUserId);
try {
- FileOutputStream lowResFos = new FileOutputStream(lowResFile);
- lowResBitmap.compress(JPEG, QUALITY, lowResFos);
- lowResFos.close();
+ FileOutputStream fos = new FileOutputStream(file);
+ swBitmap.compress(JPEG, QUALITY, fos);
+ fos.close();
} catch (IOException e) {
- Slog.e(TAG, "Unable to open " + lowResFile + " for persisting.", e);
+ Slog.e(TAG, "Unable to open " + file + " for persisting.", e);
return false;
}
- lowResBitmap.recycle();
- // For snapshots with lowResBitmap resolution, do not create or save full sized bitmaps
- if (mSnapshot.isLowResolution()) {
+ if (!enableLowResSnapshots()) {
swBitmap.recycle();
return true;
}
- final File file = getHighResolutionBitmapFile(mTaskId, mUserId);
+ final Bitmap lowResBitmap = Bitmap.createScaledBitmap(swBitmap,
+ (int) (bitmap.getWidth() * mLowResScaleFactor),
+ (int) (bitmap.getHeight() * mLowResScaleFactor), true /* filter */);
+ swBitmap.recycle();
+
+ final File lowResFile = getLowResolutionBitmapFile(mTaskId, mUserId);
try {
- FileOutputStream fos = new FileOutputStream(file);
- swBitmap.compress(JPEG, QUALITY, fos);
- fos.close();
+ FileOutputStream lowResFos = new FileOutputStream(lowResFile);
+ lowResBitmap.compress(JPEG, QUALITY, lowResFos);
+ lowResFos.close();
} catch (IOException e) {
- Slog.e(TAG, "Unable to open " + file + " for persisting.", e);
+ Slog.e(TAG, "Unable to open " + lowResFile + " for persisting.", e);
return false;
}
- swBitmap.recycle();
+ lowResBitmap.recycle();
+
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 f4e42455087d..eb005e0f7eda 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+
import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.getColorViewLeftInset;
@@ -53,9 +54,11 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -131,6 +134,8 @@ class TaskSnapshotSurface implements StartingSurface {
private final Rect mContentInsets = new Rect();
private final Rect mFrame = new Rect();
private TaskSnapshot mSnapshot;
+ private final RectF mTmpSnapshotSize = new RectF();
+ private final RectF mTmpDstFrame = new RectF();
private final CharSequence mTitle;
private boolean mHasDrawn;
private long mShownTime;
@@ -141,6 +146,8 @@ class TaskSnapshotSurface implements StartingSurface {
@VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
private final int mOrientationOnCreation;
private final SurfaceControl.Transaction mTransaction;
+ private final Matrix mSnapshotMatrix = new Matrix();
+ private final float[] mTmpFloat9 = new float[9];
static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
TaskSnapshot snapshot) {
@@ -365,13 +372,17 @@ class TaskSnapshotSurface implements StartingSurface {
frame = calculateSnapshotFrame(crop);
mTransaction.setWindowCrop(mChildSurfaceControl, crop);
mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top);
+ mTmpDstFrame.set(frame);
} else {
frame = null;
+ mTmpDstFrame.set(mFrame);
}
// Scale the mismatch dimensions to fill the task bounds
- final float scale = 1 / mSnapshot.getScale();
- mTransaction.setMatrix(mChildSurfaceControl, scale, 0, 0, scale);
+ mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
+ mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
+ mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9);
+
mTransaction.apply();
surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
surface.release();
@@ -395,13 +406,17 @@ class TaskSnapshotSurface implements StartingSurface {
rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
final Rect insets = mSnapshot.getContentInsets();
+ final float scaleX = (float) mSnapshot.getSnapshot().getWidth() / mSnapshot.getTaskSize().x;
+ final float scaleY =
+ (float) mSnapshot.getSnapshot().getHeight() / mSnapshot.getTaskSize().y;
+
// Let's remove all system decorations except the status bar, but only if the task is at the
// very top of the screen.
final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
- rect.inset((int) (insets.left * mSnapshot.getScale()),
- isTop ? 0 : (int) (insets.top * mSnapshot.getScale()),
- (int) (insets.right * mSnapshot.getScale()),
- (int) (insets.bottom * mSnapshot.getScale()));
+ rect.inset((int) (insets.left * scaleX),
+ isTop ? 0 : (int) (insets.top * scaleY),
+ (int) (insets.right * scaleX),
+ (int) (insets.bottom * scaleY));
return rect;
}
@@ -412,14 +427,20 @@ class TaskSnapshotSurface implements StartingSurface {
*/
@VisibleForTesting
Rect calculateSnapshotFrame(Rect crop) {
- final Rect frame = new Rect(crop);
- final float scale = mSnapshot.getScale();
+ final float scaleX = (float) mSnapshot.getSnapshot().getWidth() / mSnapshot.getTaskSize().x;
+ final float scaleY =
+ (float) mSnapshot.getSnapshot().getHeight() / mSnapshot.getTaskSize().y;
// Rescale the frame from snapshot to window coordinate space
- frame.scale(1 / scale);
+ final Rect frame = new Rect(
+ (int) (crop.left / scaleX + 0.5f),
+ (int) (crop.top / scaleY + 0.5f),
+ (int) (crop.right / scaleX + 0.5f),
+ (int) (crop.bottom / scaleY + 0.5f)
+ );
// By default, offset it to to top/left corner
- frame.offsetTo((int) (-crop.left / scale), (int) (-crop.top / scale));
+ frame.offsetTo((int) (-crop.left / scaleX), (int) (-crop.top / scaleY));
// However, we also need to make space for the navigation bar on the left side.
final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index bd8aacb6cb96..20d9aff5f3bf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -25,6 +25,7 @@ import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_APP_THE
import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_REAL;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -36,6 +37,7 @@ import android.content.res.Configuration;
import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
@@ -138,6 +140,7 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
final int orientation = Configuration.ORIENTATION_PORTRAIT;
final float scaleFraction = 0.25f;
final Rect contentInsets = new Rect(1, 2, 3, 4);
+ final Point taskSize = new Point(5, 6);
try {
ActivityManager.TaskSnapshot.Builder builder =
@@ -147,14 +150,13 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
builder.setSystemUiVisibility(systemUiVisibility);
builder.setWindowingMode(windowingMode);
builder.setColorSpace(sRGB);
- builder.setIsLowResolution(true);
builder.setOrientation(orientation);
builder.setContentInsets(contentInsets);
builder.setIsTranslucent(true);
- builder.setScaleFraction(0.25f);
builder.setSnapshot(buffer);
builder.setIsRealSnapshot(true);
builder.setPixelFormat(pixelFormat);
+ builder.setTaskSize(taskSize);
// Not part of TaskSnapshot itself, used in screenshot process
assertEquals(pixelFormat, builder.getPixelFormat());
@@ -165,13 +167,15 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
assertEquals(systemUiVisibility, snapshot.getSystemUiVisibility());
assertEquals(windowingMode, snapshot.getWindowingMode());
assertEquals(sRGB, snapshot.getColorSpace());
- assertTrue(snapshot.isLowResolution());
+ // Snapshots created with the Builder class are always high-res. The only way to get a
+ // low-res snapshot is to load it from the disk in TaskSnapshotLoader.
+ assertFalse(snapshot.isLowResolution());
assertEquals(orientation, snapshot.getOrientation());
assertEquals(contentInsets, snapshot.getContentInsets());
assertTrue(snapshot.isTranslucent());
- assertEquals(scaleFraction, builder.getScaleFraction(), 0.001f);
assertSame(buffer, snapshot.getSnapshot());
assertTrue(snapshot.isRealSnapshot());
+ assertEquals(taskSize, snapshot.getTaskSize());
} finally {
if (buffer != null) {
buffer.destroy();
@@ -188,11 +192,9 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
final ActivityManager.TaskSnapshot.Builder builder =
new ActivityManager.TaskSnapshot.Builder();
- final float scaleFraction = 0.8f;
mWm.mTaskSnapshotController.prepareTaskSnapshot(mAppWindow.mActivityRecord.getTask(),
- scaleFraction, PixelFormat.UNKNOWN, builder);
+ PixelFormat.UNKNOWN, builder);
- assertEquals(scaleFraction, builder.getScaleFraction(), 0 /* delta */);
// The pixel format should be selected automatically.
assertNotEquals(PixelFormat.UNKNOWN, builder.getPixelFormat());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 0b16e5ce8b97..40f15b7e9d39 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -19,12 +19,16 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -36,10 +40,12 @@ import android.view.View;
import androidx.test.filters.MediumTest;
+import com.android.server.wm.TaskSnapshotLoader.PreRLegacySnapshotConfig;
import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
import java.io.File;
import java.util.function.Predicate;
@@ -55,6 +61,8 @@ import java.util.function.Predicate;
@RunWith(WindowTestRunner.class)
public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase {
+ private static final float DELTA = 0.00001f;
+
private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
@Test
@@ -148,29 +156,172 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
}
@Test
- public void testLowResolutionPersistAndLoadSnapshot() {
+ public void testLegacyPLowRamConfig() throws Exception {
+ MockitoSession mockSession = mockitoSession()
+ .initMocks(this)
+ .mockStatic(ActivityManager.class)
+ .startMocking();
+
+ when(ActivityManager.isLowRamDeviceStatic()).thenReturn(true);
+
+ // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+ // for any P low_ram device
+ final int taskWidth = 0;
+ final float legacyScale = 0f;
+ final boolean hasHighResFile = false;
+
+ PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+ assertNotNull(highResConf);
+ assertEquals(highResConf.mScale, 0.6f, DELTA);
+ assertTrue(highResConf.mForceLoadReducedJpeg);
+
+ PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+ assertNotNull(lowResConf);
+ assertEquals(lowResConf.mScale, 0.6f, DELTA);
+ assertTrue(lowResConf.mForceLoadReducedJpeg);
+
+ mockSession.finishMocking();
+ }
+
+ @Test
+ public void testLegacyPNonLowRamConfig() throws Exception {
+ MockitoSession mockSession = mockitoSession()
+ .initMocks(this)
+ .mockStatic(ActivityManager.class)
+ .startMocking();
+
+ when(ActivityManager.isLowRamDeviceStatic()).thenReturn(false);
+
+ // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+ // for any O device, or a P non-low_ram device
+ final int taskWidth = 0;
+ final float legacyScale = 0f;
+ final boolean hasHighResFile = true;
+
+ PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+ assertNotNull(highResConf);
+ assertEquals(highResConf.mScale, 1.0f, DELTA);
+ assertFalse(highResConf.mForceLoadReducedJpeg);
+
+ PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+ assertNotNull(lowResConf);
+ assertEquals(lowResConf.mScale, 0.5f, DELTA);
+ assertFalse(lowResConf.mForceLoadReducedJpeg);
+
+ mockSession.finishMocking();
+ }
+
+ @Test
+ public void testLegacyQLowRamConfig() throws Exception {
+ MockitoSession mockSession = mockitoSession()
+ .initMocks(this)
+ .mockStatic(ActivityManager.class)
+ .startMocking();
+
+ when(ActivityManager.isLowRamDeviceStatic()).thenReturn(true);
+
+ // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+ // for any Q low_ram device
+ final int taskWidth = 0;
+ final float legacyScale = 0.6f;
+ final boolean hasHighResFile = false;
+
+ PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+ assertNotNull(highResConf);
+ assertEquals(highResConf.mScale, legacyScale, DELTA);
+ assertEquals(highResConf.mScale, 0.6f, DELTA);
+ assertTrue(highResConf.mForceLoadReducedJpeg);
+
+ PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+ assertNotNull(lowResConf);
+ assertEquals(lowResConf.mScale, legacyScale, DELTA);
+ assertEquals(lowResConf.mScale, 0.6f, DELTA);
+ assertTrue(lowResConf.mForceLoadReducedJpeg);
+
+ mockSession.finishMocking();
+ }
+
+ @Test
+ public void testLegacyQNonLowRamConfig() throws Exception {
+ MockitoSession mockSession = mockitoSession()
+ .initMocks(this)
+ .mockStatic(ActivityManager.class)
+ .startMocking();
+
+ when(ActivityManager.isLowRamDeviceStatic()).thenReturn(false);
+
+ // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+ // for any Q non-low_ram device
+ final int taskWidth = 0;
+ final float legacyScale = 0.8f;
+ final boolean hasHighResFile = true;
+
+ PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+ assertNotNull(highResConf);
+ assertEquals(highResConf.mScale, legacyScale, DELTA);
+ assertEquals(highResConf.mScale, 0.8f, DELTA);
+ assertFalse(highResConf.mForceLoadReducedJpeg);
+
+ PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+ assertNotNull(lowResConf);
+ assertEquals(lowResConf.mScale, 0.5f * legacyScale, DELTA);
+ assertEquals(lowResConf.mScale, 0.5f * 0.8f, DELTA);
+ assertFalse(lowResConf.mForceLoadReducedJpeg);
+
+ mockSession.finishMocking();
+ }
+
+ @Test
+ public void testNonLegacyRConfig() throws Exception {
+ // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+ // for any R device
+ final int taskWidth = 1440;
+ final float legacyScale = 0f;
+ final boolean hasHighResFile = true;
+
+ PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+ assertNull(highResConf);
+
+ PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+ taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+ assertNull(lowResConf);
+ }
+
+ @Test
+ public void testDisabledLowResolutionPersistAndLoadSnapshot() {
+ mPersister.setEnableLowResSnapshots(false);
+
TaskSnapshot a = new TaskSnapshotBuilder()
- .setScale(0.5f)
+ .setScaleFraction(0.5f)
.setIsLowResolution(true)
.build();
assertTrue(a.isLowResolution());
mPersister.persistSnapshot(1, mTestUserId, a);
mPersister.waitForQueueEmpty();
final File[] files = new File[]{new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
- new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")};
+ new File(FILES_DIR.getPath() + "/snapshots/1.jpg")};
final File[] nonExistsFiles = new File[]{
- new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
+ new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"),
};
assertTrueForFiles(files, File::exists, " must exist");
assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
- final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, true /* isLowResolution */);
+ final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* isLowResolution */);
assertNotNull(snapshot);
assertEquals(TEST_INSETS, snapshot.getContentInsets());
assertNotNull(snapshot.getSnapshot());
assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
final TaskSnapshot snapshotNotExist = mLoader.loadTask(1, mTestUserId,
- false /* isLowResolution */);
+ true /* isLowResolution */);
assertNull(snapshotNotExist);
}
@@ -271,13 +422,11 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
@Test
public void testScalePersistAndLoadSnapshot() {
TaskSnapshot a = new TaskSnapshotBuilder()
- .setScale(0.25f)
+ .setScaleFraction(0.25f)
.build();
TaskSnapshot b = new TaskSnapshotBuilder()
- .setScale(0.75f)
+ .setScaleFraction(0.75f)
.build();
- assertEquals(0.25f, a.getScale(), 1E-5);
- assertEquals(0.75f, b.getScale(), 1E-5);
mPersister.persistSnapshot(1, mTestUserId, a);
mPersister.persistSnapshot(2, mTestUserId, b);
mPersister.waitForQueueEmpty();
@@ -287,8 +436,6 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
false /* isLowResolution */);
assertNotNull(snapshotA);
assertNotNull(snapshotB);
- assertEquals(0.25f, snapshotA.getScale(), 1E-5);
- assertEquals(0.75f, snapshotB.getScale(), 1E-5);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 4612dbab0a59..fa6663c06371 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -30,6 +30,7 @@ import android.graphics.Color;
import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.UserManager;
import android.view.Surface;
@@ -87,8 +88,10 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
* Builds a TaskSnapshot.
*/
static class TaskSnapshotBuilder {
+ private static final int SNAPSHOT_WIDTH = 100;
+ private static final int SNAPSHOT_HEIGHT = 100;
- private float mScale = 1f;
+ private float mScaleFraction = 1f;
private boolean mIsLowResolution = false;
private boolean mIsRealSnapshot = true;
private boolean mIsTranslucent = false;
@@ -96,8 +99,11 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
private int mSystemUiVisibility = 0;
private int mRotation = Surface.ROTATION_0;
- TaskSnapshotBuilder setScale(float scale) {
- mScale = scale;
+ TaskSnapshotBuilder() {
+ }
+
+ TaskSnapshotBuilder setScaleFraction(float scale) {
+ mScaleFraction = scale;
return this;
}
@@ -132,15 +138,20 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
}
TaskSnapshot build() {
- final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
+ // To satisfy existing tests, ensure the graphics buffer is always 100x100, and
+ // compute the ize of the task according to mScaleFraction.
+ Point taskSize = new Point((int) (SNAPSHOT_WIDTH / mScaleFraction),
+ (int) (SNAPSHOT_HEIGHT / mScaleFraction));
+ final GraphicBuffer buffer = GraphicBuffer.create(SNAPSHOT_WIDTH, SNAPSHOT_HEIGHT,
+ PixelFormat.RGBA_8888,
USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
Canvas c = buffer.lockCanvas();
c.drawColor(Color.RED);
buffer.unlockCanvasAndPost(c);
return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""), buffer,
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
- mRotation, TEST_INSETS,
- mIsLowResolution, mScale, mIsRealSnapshot,
+ mRotation, taskSize, TEST_INSETS,
+ mIsLowResolution, mIsRealSnapshot,
mWindowingMode, mSystemUiVisibility, mIsTranslucent);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index bb0e5aec8e2e..2164de9ea191 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -38,6 +38,7 @@ import android.graphics.Color;
import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.Surface;
@@ -67,12 +68,22 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
int windowFlags, Rect taskBounds) {
final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER);
+
+ // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
+ // this behavior set the taskSize to be the same as the taskBounds width and height. The
+ // taskBounds passed here are assumed to be the same task bounds as when the snapshot was
+ // taken. We assume there is no aspect ratio mismatch between the screenshot and the
+ // taskBounds
+ assertEquals(width, taskBounds.width());
+ assertEquals(height, taskBounds.height());
+ Point taskSize = new Point(taskBounds.width(), taskBounds.height());
+
final TaskSnapshot snapshot = new TaskSnapshot(
System.currentTimeMillis(),
new ComponentName("", ""), buffer,
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
- Surface.ROTATION_0, contentInsets, false,
- 1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
+ Surface.ROTATION_0, taskSize, contentInsets, false,
+ true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
0 /* systemUiVisibility */, false /* isTranslucent */);
mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
@@ -152,7 +163,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
@Test
public void testCalculateSnapshotCrop_taskNotOnTop() {
- setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 100));
+ setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 150));
assertEquals(new Rect(0, 10, 100, 90), mSurface.calculateSnapshotCrop());
}