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
This commit is contained in:
Peter Kalauskas
2020-02-25 18:29:50 +00:00
committed by Android (Google) Code Review
12 changed files with 474 additions and 181 deletions

View File

@@ -2012,15 +2012,16 @@ public class ActivityManager {
/** See {@link android.view.Surface.Rotation} */ /** See {@link android.view.Surface.Rotation} */
@Surface.Rotation @Surface.Rotation
private int mRotation; private int mRotation;
/** The size of the snapshot before scaling */
private final Point mTaskSize;
private final Rect mContentInsets; private final Rect mContentInsets;
// Whether this snapshot is a down-sampled version of the full resolution, used mainly for // Whether this snapshot is a down-sampled version of the high resolution snapshot, used
// low-ram devices // mainly for loading snapshots quickly from disk when user is flinging fast
private final boolean mIsLowResolution; private final boolean mIsLowResolution;
// Whether or not the snapshot is a real snapshot or an app-theme generated snapshot due to // 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 // the task having a secure window or having previews disabled
private final boolean mIsRealSnapshot; private final boolean mIsRealSnapshot;
private final int mWindowingMode; private final int mWindowingMode;
private final float mScale;
private final int mSystemUiVisibility; private final int mSystemUiVisibility;
private final boolean mIsTranslucent; private final boolean mIsTranslucent;
// Must be one of the named color spaces, otherwise, always use SRGB color space. // 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, public TaskSnapshot(long id,
@NonNull ComponentName topActivityComponent, GraphicBuffer snapshot, @NonNull ComponentName topActivityComponent, GraphicBuffer snapshot,
@NonNull ColorSpace colorSpace, int orientation, int rotation, Rect contentInsets, @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize,
boolean isLowResolution, float scale, boolean isRealSnapshot, int windowingMode, Rect contentInsets, boolean isLowResolution, boolean isRealSnapshot,
int systemUiVisibility, boolean isTranslucent) { int windowingMode, int systemUiVisibility, boolean isTranslucent) {
mId = id; mId = id;
mTopActivityComponent = topActivityComponent; mTopActivityComponent = topActivityComponent;
mSnapshot = snapshot; mSnapshot = snapshot;
@@ -2038,9 +2039,9 @@ public class ActivityManager {
? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace; ? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace;
mOrientation = orientation; mOrientation = orientation;
mRotation = rotation; mRotation = rotation;
mTaskSize = new Point(taskSize);
mContentInsets = new Rect(contentInsets); mContentInsets = new Rect(contentInsets);
mIsLowResolution = isLowResolution; mIsLowResolution = isLowResolution;
mScale = scale;
mIsRealSnapshot = isRealSnapshot; mIsRealSnapshot = isRealSnapshot;
mWindowingMode = windowingMode; mWindowingMode = windowingMode;
mSystemUiVisibility = systemUiVisibility; mSystemUiVisibility = systemUiVisibility;
@@ -2057,9 +2058,9 @@ public class ActivityManager {
: ColorSpace.get(ColorSpace.Named.SRGB); : ColorSpace.get(ColorSpace.Named.SRGB);
mOrientation = source.readInt(); mOrientation = source.readInt();
mRotation = source.readInt(); mRotation = source.readInt();
mTaskSize = source.readParcelable(null /* classLoader */);
mContentInsets = source.readParcelable(null /* classLoader */); mContentInsets = source.readParcelable(null /* classLoader */);
mIsLowResolution = source.readBoolean(); mIsLowResolution = source.readBoolean();
mScale = source.readFloat();
mIsRealSnapshot = source.readBoolean(); mIsRealSnapshot = source.readBoolean();
mWindowingMode = source.readInt(); mWindowingMode = source.readInt();
mSystemUiVisibility = source.readInt(); mSystemUiVisibility = source.readInt();
@@ -2110,6 +2111,14 @@ public class ActivityManager {
return mRotation; return mRotation;
} }
/**
* @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 * @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. * remove any areas behind system bars in the snapshot.
@@ -2159,14 +2168,6 @@ public class ActivityManager {
return mSystemUiVisibility; return mSystemUiVisibility;
} }
/**
* @return The scale this snapshot was taken in.
*/
@UnsupportedAppUsage
public float getScale() {
return mScale;
}
@Override @Override
public int describeContents() { public int describeContents() {
return 0; return 0;
@@ -2180,9 +2181,9 @@ public class ActivityManager {
dest.writeInt(mColorSpace.getId()); dest.writeInt(mColorSpace.getId());
dest.writeInt(mOrientation); dest.writeInt(mOrientation);
dest.writeInt(mRotation); dest.writeInt(mRotation);
dest.writeParcelable(mTaskSize, 0);
dest.writeParcelable(mContentInsets, 0); dest.writeParcelable(mContentInsets, 0);
dest.writeBoolean(mIsLowResolution); dest.writeBoolean(mIsLowResolution);
dest.writeFloat(mScale);
dest.writeBoolean(mIsRealSnapshot); dest.writeBoolean(mIsRealSnapshot);
dest.writeInt(mWindowingMode); dest.writeInt(mWindowingMode);
dest.writeInt(mSystemUiVisibility); dest.writeInt(mSystemUiVisibility);
@@ -2200,9 +2201,11 @@ public class ActivityManager {
+ " mColorSpace=" + mColorSpace.toString() + " mColorSpace=" + mColorSpace.toString()
+ " mOrientation=" + mOrientation + " mOrientation=" + mOrientation
+ " mRotation=" + mRotation + " mRotation=" + mRotation
+ " mTaskSize=" + mTaskSize.toString()
+ " mContentInsets=" + mContentInsets.toShortString() + " mContentInsets=" + mContentInsets.toShortString()
+ " mIsLowResolution=" + mIsLowResolution + " mScale=" + mScale + " mIsLowResolution=" + mIsLowResolution
+ " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode + " mIsRealSnapshot=" + mIsRealSnapshot
+ " mWindowingMode=" + mWindowingMode
+ " mSystemUiVisibility=" + mSystemUiVisibility + " mSystemUiVisibility=" + mSystemUiVisibility
+ " mIsTranslucent=" + mIsTranslucent; + " mIsTranslucent=" + mIsTranslucent;
} }
@@ -2224,9 +2227,8 @@ public class ActivityManager {
private ColorSpace mColorSpace; private ColorSpace mColorSpace;
private int mOrientation; private int mOrientation;
private int mRotation; private int mRotation;
private Point mTaskSize;
private Rect mContentInsets; private Rect mContentInsets;
private boolean mIsLowResolution;
private float mScaleFraction;
private boolean mIsRealSnapshot; private boolean mIsRealSnapshot;
private int mWindowingMode; private int mWindowingMode;
private int mSystemUiVisibility; private int mSystemUiVisibility;
@@ -2263,28 +2265,19 @@ public class ActivityManager {
return this; return this;
} }
/**
* Sets the original size of the task
*/
public Builder setTaskSize(Point size) {
mTaskSize = size;
return this;
}
public Builder setContentInsets(Rect contentInsets) { public Builder setContentInsets(Rect contentInsets) {
mContentInsets = contentInsets; mContentInsets = contentInsets;
return this; return this;
} }
/**
* Set to true if this is a low-resolution snapshot stored in *_reduced.jpg.
*/
public Builder setIsLowResolution(boolean isLowResolution) {
mIsLowResolution = isLowResolution;
return this;
}
public float getScaleFraction() {
return mScaleFraction;
}
public Builder setScaleFraction(float scaleFraction) {
mScaleFraction = scaleFraction;
return this;
}
public Builder setIsRealSnapshot(boolean realSnapshot) { public Builder setIsRealSnapshot(boolean realSnapshot) {
mIsRealSnapshot = realSnapshot; mIsRealSnapshot = realSnapshot;
return this; return this;
@@ -2322,9 +2315,12 @@ public class ActivityManager {
mColorSpace, mColorSpace,
mOrientation, mOrientation,
mRotation, mRotation,
mTaskSize,
mContentInsets, mContentInsets,
mIsLowResolution, // When building a TaskSnapshot with the Builder class, isLowResolution
mScaleFraction, // is always false. Low-res snapshots are only created when loading from
// disk.
false /* isLowResolution */,
mIsRealSnapshot, mIsRealSnapshot,
mWindowingMode, mWindowingMode,
mSystemUiVisibility, mSystemUiVisibility,

View File

@@ -2752,7 +2752,9 @@
<!-- The amount to scale reduced scale snapshots for Overview and snapshot starting windows. <!-- 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 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> <item name="config_lowResTaskSnapshotScale" format="float" type="dimen">0.5</item>
<!-- Feature flag to store TaskSnapshot in 16 bit pixel format to save memory. --> <!-- Feature flag to store TaskSnapshot in 16 bit pixel format to save memory. -->

View File

@@ -62,7 +62,9 @@ public class ThumbnailData {
orientation = snapshot.getOrientation(); orientation = snapshot.getOrientation();
rotation = snapshot.getRotation(); rotation = snapshot.getRotation();
reducedResolution = snapshot.isLowResolution(); 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(); isRealSnapshot = snapshot.isRealSnapshot();
isTranslucent = snapshot.isTranslucent(); isTranslucent = snapshot.isTranslucent();
windowingMode = snapshot.getWindowingMode(); windowingMode = snapshot.getWindowingMode();

View File

@@ -32,7 +32,12 @@
int32 system_ui_visibility = 8; int32 system_ui_visibility = 8;
bool is_translucent = 9; bool is_translucent = 9;
string top_activity_component = 10; 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; int64 id = 12;
int32 rotation = 13; 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;
} }

View File

@@ -18,19 +18,18 @@ package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 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.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManager.TaskSnapshot;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.GraphicBuffer; import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.RecordingCanvas; import android.graphics.RecordingCanvas;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RenderNode; import android.graphics.RenderNode;
@@ -89,14 +88,6 @@ class TaskSnapshotController {
@VisibleForTesting @VisibleForTesting
static final int SNAPSHOT_MODE_NONE = 2; 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 WindowManagerService mService;
private final TaskSnapshotCache mCache; private final TaskSnapshotCache mCache;
@@ -229,7 +220,7 @@ class TaskSnapshotController {
@Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk, @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk,
boolean isLowResolution) { boolean isLowResolution) {
return mCache.getSnapshot(taskId, userId, restoreFromDisk, 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. * information from the task and populates the builder.
* *
* @param task the task to capture * @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 * @param pixelFormat the desired pixel format, or {@link PixelFormat#UNKNOWN} to
* automatically select * automatically select
* @param builder the snapshot builder to populate * @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 * @return true if the state of the task is ok to proceed
*/ */
@VisibleForTesting @VisibleForTesting
boolean prepareTaskSnapshot(Task task, float scaleFraction, int pixelFormat, boolean prepareTaskSnapshot(Task task, int pixelFormat, TaskSnapshot.Builder builder) {
TaskSnapshot.Builder builder) {
if (!mService.mPolicy.isScreenOn()) { if (!mService.mPolicy.isScreenOn()) {
if (DEBUG_SCREENSHOT) { if (DEBUG_SCREENSHOT) {
Slog.i(TAG_WM, "Attempted to take screenshot while display was off."); Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
@@ -314,18 +302,6 @@ class TaskSnapshotController {
builder.setId(System.currentTimeMillis()); builder.setId(System.currentTimeMillis());
builder.setContentInsets(getInsets(mainWindow)); 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 isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0; final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0;
@@ -351,13 +327,23 @@ class TaskSnapshotController {
@Nullable @Nullable
SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task, SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
float scaleFraction) { TaskSnapshot.Builder builder) {
return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888); Point taskSize = new Point();
final SurfaceControl.ScreenshotGraphicBuffer taskSnapshot = createTaskSnapshot(task,
mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize);
builder.setTaskSize(taskSize);
return taskSnapshot;
} }
@Nullable @Nullable
SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task, SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
float scaleFraction, int pixelFormat) { float scaleFraction) {
return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888, null);
}
@Nullable
SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
float scaleFraction, int pixelFormat, Point outTaskSize) {
if (task.getSurfaceControl() == null) { if (task.getSurfaceControl() == null) {
if (DEBUG_SCREENSHOT) { if (DEBUG_SCREENSHOT) {
Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task); Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task);
@@ -369,6 +355,10 @@ class TaskSnapshotController {
final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer = final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
SurfaceControl.captureLayers( SurfaceControl.captureLayers(
task.getSurfaceControl(), mTmpRect, scaleFraction, pixelFormat); task.getSurfaceControl(), mTmpRect, scaleFraction, pixelFormat);
if (outTaskSize != null) {
outTaskSize.x = mTmpRect.width();
outTaskSize.y = mTmpRect.height();
}
final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer() final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer()
: null; : null;
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) { if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
@@ -379,21 +369,20 @@ class TaskSnapshotController {
@Nullable @Nullable
TaskSnapshot snapshotTask(Task task) { TaskSnapshot snapshotTask(Task task) {
return snapshotTask(task, SNAPSHOT_SCALE_AUTO, PixelFormat.UNKNOWN); return snapshotTask(task, PixelFormat.UNKNOWN);
} }
@Nullable @Nullable
TaskSnapshot snapshotTask(Task task, float scaleFraction, int pixelFormat) { TaskSnapshot snapshotTask(Task task, int pixelFormat) {
TaskSnapshot.Builder builder = new TaskSnapshot.Builder(); TaskSnapshot.Builder builder = new TaskSnapshot.Builder();
if (!prepareTaskSnapshot(task, scaleFraction, pixelFormat, builder)) { if (!prepareTaskSnapshot(task, pixelFormat, builder)) {
// Failed some pre-req. Has been logged. // Failed some pre-req. Has been logged.
return null; return null;
} }
final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer = final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
createTaskSnapshot(task, builder.getScaleFraction(), createTaskSnapshot(task, builder);
builder.getPixelFormat());
if (screenshotBuffer == null) { if (screenshotBuffer == null) {
// Failed to acquire image. Has been logged. // Failed to acquire image. Has been logged.
@@ -472,8 +461,10 @@ class TaskSnapshotController {
final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags, final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(), attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(),
mHighResTaskSnapshotScale, mainWindow.getRequestedInsetsState()); mHighResTaskSnapshotScale, mainWindow.getRequestedInsetsState());
final int width = (int) (task.getBounds().width() * mHighResTaskSnapshotScale); final int taskWidth = task.getBounds().width();
final int height = (int) (task.getBounds().height() * mHighResTaskSnapshotScale); 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); final RenderNode node = RenderNode.create("TaskSnapshotController", null);
node.setLeftTopRightBottom(0, 0, width, height); node.setLeftTopRightBottom(0, 0, width, height);
@@ -494,9 +485,9 @@ class TaskSnapshotController {
System.currentTimeMillis() /* id */, System.currentTimeMillis() /* id */,
topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(), topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(),
hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation, hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation,
mainWindow.getWindowConfiguration().getRotation(), mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight),
getInsets(mainWindow), ActivityManager.isLowRamDeviceStatic() /* isLowResolution */, getInsets(mainWindow), false /* isLowResolution */,
mHighResTaskSnapshotScale, false /* isRealSnapshot */, task.getWindowingMode(), false /* isRealSnapshot */, task.getWindowingMode(),
getSystemUiVisibility(task), false); getSystemUiVisibility(task), false);
} }

View File

@@ -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_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManager.TaskSnapshot;
import android.content.ComponentName; import android.content.ComponentName;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@@ -26,6 +27,7 @@ import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options; import android.graphics.BitmapFactory.Options;
import android.graphics.GraphicBuffer; import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.util.Slog; import android.util.Slog;
@@ -52,6 +54,76 @@ class TaskSnapshotLoader {
mPersister = persister; 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. * Loads a task from the disk.
* <p> * <p>
@@ -60,20 +132,32 @@ class TaskSnapshotLoader {
* *
* @param taskId The id of the task to load. * @param taskId The id of the task to load.
* @param userId The id of the user the task belonged to. * @param userId The id of the user the task belonged to.
* @param isLowResolution Whether to load a reduced resolution version of the snapshot. * @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. * @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 protoFile = mPersister.getProtoFile(taskId, userId);
final File bitmapFile = isLowResolution if (!protoFile.exists()) {
? mPersister.getLowResolutionBitmapFile(taskId, userId)
: mPersister.getHighResolutionBitmapFile(taskId, userId);
if (bitmapFile == null || !protoFile.exists() || !bitmapFile.exists()) {
return null; return null;
} }
try { try {
final byte[] bytes = Files.readAllBytes(protoFile.toPath()); final byte[] bytes = Files.readAllBytes(protoFile.toPath());
final TaskSnapshotProto proto = TaskSnapshotProto.parseFrom(bytes); 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(); final Options options = new Options();
options.inPreferredConfig = mPersister.use16BitFormat() && !proto.isTranslucent options.inPreferredConfig = mPersister.use16BitFormat() && !proto.isTranslucent
? Config.RGB_565 ? Config.RGB_565
@@ -99,13 +183,20 @@ class TaskSnapshotLoader {
final ComponentName topActivityComponent = ComponentName.unflattenFromString( final ComponentName topActivityComponent = ComponentName.unflattenFromString(
proto.topActivityComponent); proto.topActivityComponent);
// For legacy snapshots, restore the scale based on the reduced resolution state
final float legacyScale = isLowResolution ? mPersister.getLowResScale() : 1f; Point taskSize;
final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale; if (legacyConfig != null) {
return new TaskSnapshot(proto.id, topActivityComponent, buffer, hwBitmap.getColorSpace(), int taskWidth = (int) ((float) hwBitmap.getWidth() / legacyConfig.mScale);
proto.orientation, proto.rotation, 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), 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); proto.systemUiVisibility, proto.isTranslucent);
} catch (IOException e) { } catch (IOException e) {
Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId); Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);

View File

@@ -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_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.annotation.TestApi; import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManager.TaskSnapshot;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Bitmap.Config; 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 TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM;
private static final String SNAPSHOTS_DIRNAME = "snapshots"; private static final String SNAPSHOTS_DIRNAME = "snapshots";
private static final String LOW_RES_FILE_POSTFIX = "_reduced"; 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 long DELAY_MS = 100;
private static final int QUALITY = 95; private static final int QUALITY = 95;
private static final String PROTO_EXTENSION = ".proto"; private static final String PROTO_EXTENSION = ".proto";
@@ -71,7 +69,8 @@ class TaskSnapshotPersister {
private boolean mStarted; private boolean mStarted;
private final Object mLock = new Object(); private final Object mLock = new Object();
private final DirectoryResolver mDirectoryResolver; private final DirectoryResolver mDirectoryResolver;
private final float mLowResScale; private final float mLowResScaleFactor;
private boolean mEnableLowResSnapshots;
private final boolean mUse16BitFormat; private final boolean mUse16BitFormat;
/** /**
@@ -83,13 +82,29 @@ class TaskSnapshotPersister {
TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) { TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) {
mDirectoryResolver = resolver; mDirectoryResolver = resolver;
final float highResTaskSnapshotScale = service.mContext.getResources().getFloat(
if (ActivityManager.isLowRamDeviceStatic()) { com.android.internal.R.dimen.config_highResTaskSnapshotScale);
mLowResScale = LOW_RAM_REDUCED_SCALE; final float lowResTaskSnapshotScale = service.mContext.getResources().getFloat(
} else {
mLowResScale = service.mContext.getResources().getFloat(
com.android.internal.R.dimen.config_lowResTaskSnapshotScale); com.android.internal.R.dimen.config_lowResTaskSnapshotScale);
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 {
mLowResScaleFactor = 0;
setEnableLowResSnapshots(false);
}
mUse16BitFormat = service.mContext.getResources().getBoolean( mUse16BitFormat = service.mContext.getResources().getBoolean(
com.android.internal.R.bool.config_use16BitTaskSnapshotPixelFormat); 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. * Not to be used. Only here for testing.
*
* @return the lowResBitmap scale of task snapshots when they are set to be low res
*/ */
float getLowResScale() { @VisibleForTesting
return mLowResScale; void setEnableLowResSnapshots(boolean enabled) {
mEnableLowResSnapshots = enabled;
} }
/** /**
@@ -213,14 +231,10 @@ class TaskSnapshotPersister {
} }
File getHighResolutionBitmapFile(int taskId, int userId) { 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); return new File(getDirectory(userId), taskId + BITMAP_EXTENSION);
} }
@NonNull
File getLowResolutionBitmapFile(int taskId, int userId) { File getLowResolutionBitmapFile(int taskId, int userId) {
return new File(getDirectory(userId), taskId + LOW_RES_FILE_POSTFIX + BITMAP_EXTENSION); 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 protoFile = getProtoFile(taskId, userId);
final File bitmapLowResFile = getLowResolutionBitmapFile(taskId, userId); final File bitmapLowResFile = getLowResolutionBitmapFile(taskId, userId);
protoFile.delete(); protoFile.delete();
if (bitmapLowResFile.exists()) {
bitmapLowResFile.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); final File bitmapFile = getHighResolutionBitmapFile(taskId, userId);
if (bitmapFile.exists()) {
bitmapFile.delete(); bitmapFile.delete();
} }
} }
@@ -343,6 +357,8 @@ class TaskSnapshotPersister {
final TaskSnapshotProto proto = new TaskSnapshotProto(); final TaskSnapshotProto proto = new TaskSnapshotProto();
proto.orientation = mSnapshot.getOrientation(); proto.orientation = mSnapshot.getOrientation();
proto.rotation = mSnapshot.getRotation(); proto.rotation = mSnapshot.getRotation();
proto.taskWidth = mSnapshot.getTaskSize().x;
proto.taskHeight = mSnapshot.getTaskSize().y;
proto.insetLeft = mSnapshot.getContentInsets().left; proto.insetLeft = mSnapshot.getContentInsets().left;
proto.insetTop = mSnapshot.getContentInsets().top; proto.insetTop = mSnapshot.getContentInsets().top;
proto.insetRight = mSnapshot.getContentInsets().right; proto.insetRight = mSnapshot.getContentInsets().right;
@@ -352,7 +368,6 @@ class TaskSnapshotPersister {
proto.systemUiVisibility = mSnapshot.getSystemUiVisibility(); proto.systemUiVisibility = mSnapshot.getSystemUiVisibility();
proto.isTranslucent = mSnapshot.isTranslucent(); proto.isTranslucent = mSnapshot.isTranslucent();
proto.topActivityComponent = mSnapshot.getTopActivityComponent().flattenToString(); proto.topActivityComponent = mSnapshot.getTopActivityComponent().flattenToString();
proto.scale = mSnapshot.getScale();
proto.id = mSnapshot.getId(); proto.id = mSnapshot.getId();
final byte[] bytes = TaskSnapshotProto.toByteArray(proto); final byte[] bytes = TaskSnapshotProto.toByteArray(proto);
final File file = getProtoFile(mTaskId, mUserId); final File file = getProtoFile(mTaskId, mUserId);
@@ -379,11 +394,26 @@ class TaskSnapshotPersister {
} }
final Bitmap swBitmap = bitmap.copy(Config.ARGB_8888, false /* isMutable */); final Bitmap swBitmap = bitmap.copy(Config.ARGB_8888, false /* isMutable */);
final Bitmap lowResBitmap = mSnapshot.isLowResolution()
? swBitmap final File file = getHighResolutionBitmapFile(mTaskId, mUserId);
: Bitmap.createScaledBitmap(swBitmap, try {
(int) (bitmap.getWidth() * mLowResScale), FileOutputStream fos = new FileOutputStream(file);
(int) (bitmap.getHeight() * mLowResScale), true /* filter */); swBitmap.compress(JPEG, QUALITY, fos);
fos.close();
} catch (IOException e) {
Slog.e(TAG, "Unable to open " + file + " for persisting.", e);
return false;
}
if (!enableLowResSnapshots()) {
swBitmap.recycle();
return true;
}
final Bitmap lowResBitmap = Bitmap.createScaledBitmap(swBitmap,
(int) (bitmap.getWidth() * mLowResScaleFactor),
(int) (bitmap.getHeight() * mLowResScaleFactor), true /* filter */);
swBitmap.recycle();
final File lowResFile = getLowResolutionBitmapFile(mTaskId, mUserId); final File lowResFile = getLowResolutionBitmapFile(mTaskId, mUserId);
try { try {
@@ -396,22 +426,6 @@ class TaskSnapshotPersister {
} }
lowResBitmap.recycle(); lowResBitmap.recycle();
// For snapshots with lowResBitmap resolution, do not create or save full sized bitmaps
if (mSnapshot.isLowResolution()) {
swBitmap.recycle();
return true;
}
final File file = getHighResolutionBitmapFile(mTaskId, mUserId);
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;
}
swBitmap.recycle();
return true; return true;
} }
} }

View File

@@ -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.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 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.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.getColorViewLeftInset; import static com.android.internal.policy.DecorView.getColorViewLeftInset;
@@ -53,9 +54,11 @@ import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.GraphicBuffer; import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
@@ -131,6 +134,8 @@ class TaskSnapshotSurface implements StartingSurface {
private final Rect mContentInsets = new Rect(); private final Rect mContentInsets = new Rect();
private final Rect mFrame = new Rect(); private final Rect mFrame = new Rect();
private TaskSnapshot mSnapshot; private TaskSnapshot mSnapshot;
private final RectF mTmpSnapshotSize = new RectF();
private final RectF mTmpDstFrame = new RectF();
private final CharSequence mTitle; private final CharSequence mTitle;
private boolean mHasDrawn; private boolean mHasDrawn;
private long mShownTime; private long mShownTime;
@@ -141,6 +146,8 @@ class TaskSnapshotSurface implements StartingSurface {
@VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter; @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
private final int mOrientationOnCreation; private final int mOrientationOnCreation;
private final SurfaceControl.Transaction mTransaction; 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, static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
TaskSnapshot snapshot) { TaskSnapshot snapshot) {
@@ -365,13 +372,17 @@ class TaskSnapshotSurface implements StartingSurface {
frame = calculateSnapshotFrame(crop); frame = calculateSnapshotFrame(crop);
mTransaction.setWindowCrop(mChildSurfaceControl, crop); mTransaction.setWindowCrop(mChildSurfaceControl, crop);
mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top); mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top);
mTmpDstFrame.set(frame);
} else { } else {
frame = null; frame = null;
mTmpDstFrame.set(mFrame);
} }
// Scale the mismatch dimensions to fill the task bounds // Scale the mismatch dimensions to fill the task bounds
final float scale = 1 / mSnapshot.getScale(); mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
mTransaction.setMatrix(mChildSurfaceControl, scale, 0, 0, scale); mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9);
mTransaction.apply(); mTransaction.apply();
surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace()); surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
surface.release(); surface.release();
@@ -395,13 +406,17 @@ class TaskSnapshotSurface implements StartingSurface {
rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight()); rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
final Rect insets = mSnapshot.getContentInsets(); 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 // Let's remove all system decorations except the status bar, but only if the task is at the
// very top of the screen. // very top of the screen.
final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0; final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
rect.inset((int) (insets.left * mSnapshot.getScale()), rect.inset((int) (insets.left * scaleX),
isTop ? 0 : (int) (insets.top * mSnapshot.getScale()), isTop ? 0 : (int) (insets.top * scaleY),
(int) (insets.right * mSnapshot.getScale()), (int) (insets.right * scaleX),
(int) (insets.bottom * mSnapshot.getScale())); (int) (insets.bottom * scaleY));
return rect; return rect;
} }
@@ -412,14 +427,20 @@ class TaskSnapshotSurface implements StartingSurface {
*/ */
@VisibleForTesting @VisibleForTesting
Rect calculateSnapshotFrame(Rect crop) { Rect calculateSnapshotFrame(Rect crop) {
final Rect frame = new Rect(crop); final float scaleX = (float) mSnapshot.getSnapshot().getWidth() / mSnapshot.getTaskSize().x;
final float scale = mSnapshot.getScale(); final float scaleY =
(float) mSnapshot.getSnapshot().getHeight() / mSnapshot.getTaskSize().y;
// Rescale the frame from snapshot to window coordinate space // 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 // 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. // However, we also need to make space for the navigation bar on the left side.
final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left, final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,

View File

@@ -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 com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_REAL;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -36,6 +37,7 @@ import android.content.res.Configuration;
import android.graphics.ColorSpace; import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer; import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit;
import android.util.ArraySet; import android.util.ArraySet;
@@ -138,6 +140,7 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
final int orientation = Configuration.ORIENTATION_PORTRAIT; final int orientation = Configuration.ORIENTATION_PORTRAIT;
final float scaleFraction = 0.25f; final float scaleFraction = 0.25f;
final Rect contentInsets = new Rect(1, 2, 3, 4); final Rect contentInsets = new Rect(1, 2, 3, 4);
final Point taskSize = new Point(5, 6);
try { try {
ActivityManager.TaskSnapshot.Builder builder = ActivityManager.TaskSnapshot.Builder builder =
@@ -147,14 +150,13 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
builder.setSystemUiVisibility(systemUiVisibility); builder.setSystemUiVisibility(systemUiVisibility);
builder.setWindowingMode(windowingMode); builder.setWindowingMode(windowingMode);
builder.setColorSpace(sRGB); builder.setColorSpace(sRGB);
builder.setIsLowResolution(true);
builder.setOrientation(orientation); builder.setOrientation(orientation);
builder.setContentInsets(contentInsets); builder.setContentInsets(contentInsets);
builder.setIsTranslucent(true); builder.setIsTranslucent(true);
builder.setScaleFraction(0.25f);
builder.setSnapshot(buffer); builder.setSnapshot(buffer);
builder.setIsRealSnapshot(true); builder.setIsRealSnapshot(true);
builder.setPixelFormat(pixelFormat); builder.setPixelFormat(pixelFormat);
builder.setTaskSize(taskSize);
// Not part of TaskSnapshot itself, used in screenshot process // Not part of TaskSnapshot itself, used in screenshot process
assertEquals(pixelFormat, builder.getPixelFormat()); assertEquals(pixelFormat, builder.getPixelFormat());
@@ -165,13 +167,15 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
assertEquals(systemUiVisibility, snapshot.getSystemUiVisibility()); assertEquals(systemUiVisibility, snapshot.getSystemUiVisibility());
assertEquals(windowingMode, snapshot.getWindowingMode()); assertEquals(windowingMode, snapshot.getWindowingMode());
assertEquals(sRGB, snapshot.getColorSpace()); 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(orientation, snapshot.getOrientation());
assertEquals(contentInsets, snapshot.getContentInsets()); assertEquals(contentInsets, snapshot.getContentInsets());
assertTrue(snapshot.isTranslucent()); assertTrue(snapshot.isTranslucent());
assertEquals(scaleFraction, builder.getScaleFraction(), 0.001f);
assertSame(buffer, snapshot.getSnapshot()); assertSame(buffer, snapshot.getSnapshot());
assertTrue(snapshot.isRealSnapshot()); assertTrue(snapshot.isRealSnapshot());
assertEquals(taskSize, snapshot.getTaskSize());
} finally { } finally {
if (buffer != null) { if (buffer != null) {
buffer.destroy(); buffer.destroy();
@@ -188,11 +192,9 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
final ActivityManager.TaskSnapshot.Builder builder = final ActivityManager.TaskSnapshot.Builder builder =
new ActivityManager.TaskSnapshot.Builder(); new ActivityManager.TaskSnapshot.Builder();
final float scaleFraction = 0.8f;
mWm.mTaskSnapshotController.prepareTaskSnapshot(mAppWindow.mActivityRecord.getTask(), 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. // The pixel format should be selected automatically.
assertNotEquals(PixelFormat.UNKNOWN, builder.getPixelFormat()); assertNotEquals(PixelFormat.UNKNOWN, builder.getPixelFormat());
} }

View File

@@ -19,12 +19,16 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 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.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManager.TaskSnapshot;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Rect; import android.graphics.Rect;
@@ -36,10 +40,12 @@ import android.view.View;
import androidx.test.filters.MediumTest; import androidx.test.filters.MediumTest;
import com.android.server.wm.TaskSnapshotLoader.PreRLegacySnapshotConfig;
import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem; import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.MockitoSession;
import java.io.File; import java.io.File;
import java.util.function.Predicate; import java.util.function.Predicate;
@@ -55,6 +61,8 @@ import java.util.function.Predicate;
@RunWith(WindowTestRunner.class) @RunWith(WindowTestRunner.class)
public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase { public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase {
private static final float DELTA = 0.00001f;
private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40); private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
@Test @Test
@@ -148,29 +156,172 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
} }
@Test @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() TaskSnapshot a = new TaskSnapshotBuilder()
.setScale(0.5f) .setScaleFraction(0.5f)
.setIsLowResolution(true) .setIsLowResolution(true)
.build(); .build();
assertTrue(a.isLowResolution()); assertTrue(a.isLowResolution());
mPersister.persistSnapshot(1, mTestUserId, a); mPersister.persistSnapshot(1, mTestUserId, a);
mPersister.waitForQueueEmpty(); mPersister.waitForQueueEmpty();
final File[] files = new File[]{new File(FILES_DIR.getPath() + "/snapshots/1.proto"), 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[]{ 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(files, File::exists, " must exist");
assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not 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); assertNotNull(snapshot);
assertEquals(TEST_INSETS, snapshot.getContentInsets()); assertEquals(TEST_INSETS, snapshot.getContentInsets());
assertNotNull(snapshot.getSnapshot()); assertNotNull(snapshot.getSnapshot());
assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation()); assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
final TaskSnapshot snapshotNotExist = mLoader.loadTask(1, mTestUserId, final TaskSnapshot snapshotNotExist = mLoader.loadTask(1, mTestUserId,
false /* isLowResolution */); true /* isLowResolution */);
assertNull(snapshotNotExist); assertNull(snapshotNotExist);
} }
@@ -271,13 +422,11 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
@Test @Test
public void testScalePersistAndLoadSnapshot() { public void testScalePersistAndLoadSnapshot() {
TaskSnapshot a = new TaskSnapshotBuilder() TaskSnapshot a = new TaskSnapshotBuilder()
.setScale(0.25f) .setScaleFraction(0.25f)
.build(); .build();
TaskSnapshot b = new TaskSnapshotBuilder() TaskSnapshot b = new TaskSnapshotBuilder()
.setScale(0.75f) .setScaleFraction(0.75f)
.build(); .build();
assertEquals(0.25f, a.getScale(), 1E-5);
assertEquals(0.75f, b.getScale(), 1E-5);
mPersister.persistSnapshot(1, mTestUserId, a); mPersister.persistSnapshot(1, mTestUserId, a);
mPersister.persistSnapshot(2, mTestUserId, b); mPersister.persistSnapshot(2, mTestUserId, b);
mPersister.waitForQueueEmpty(); mPersister.waitForQueueEmpty();
@@ -287,8 +436,6 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
false /* isLowResolution */); false /* isLowResolution */);
assertNotNull(snapshotA); assertNotNull(snapshotA);
assertNotNull(snapshotB); assertNotNull(snapshotB);
assertEquals(0.25f, snapshotA.getScale(), 1E-5);
assertEquals(0.75f, snapshotB.getScale(), 1E-5);
} }
@Test @Test

View File

@@ -30,6 +30,7 @@ import android.graphics.Color;
import android.graphics.ColorSpace; import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer; import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.UserManager; import android.os.UserManager;
import android.view.Surface; import android.view.Surface;
@@ -87,8 +88,10 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
* Builds a TaskSnapshot. * Builds a TaskSnapshot.
*/ */
static class TaskSnapshotBuilder { 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 mIsLowResolution = false;
private boolean mIsRealSnapshot = true; private boolean mIsRealSnapshot = true;
private boolean mIsTranslucent = false; private boolean mIsTranslucent = false;
@@ -96,8 +99,11 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
private int mSystemUiVisibility = 0; private int mSystemUiVisibility = 0;
private int mRotation = Surface.ROTATION_0; private int mRotation = Surface.ROTATION_0;
TaskSnapshotBuilder setScale(float scale) { TaskSnapshotBuilder() {
mScale = scale; }
TaskSnapshotBuilder setScaleFraction(float scale) {
mScaleFraction = scale;
return this; return this;
} }
@@ -132,15 +138,20 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
} }
TaskSnapshot build() { 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); USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
Canvas c = buffer.lockCanvas(); Canvas c = buffer.lockCanvas();
c.drawColor(Color.RED); c.drawColor(Color.RED);
buffer.unlockCanvasAndPost(c); buffer.unlockCanvasAndPost(c);
return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""), buffer, return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""), buffer,
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
mRotation, TEST_INSETS, mRotation, taskSize, TEST_INSETS,
mIsLowResolution, mScale, mIsRealSnapshot, mIsLowResolution, mIsRealSnapshot,
mWindowingMode, mSystemUiVisibility, mIsTranslucent); mWindowingMode, mSystemUiVisibility, mIsTranslucent);
} }
} }

View File

@@ -38,6 +38,7 @@ import android.graphics.Color;
import android.graphics.ColorSpace; import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer; import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit;
import android.view.Surface; import android.view.Surface;
@@ -67,12 +68,22 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
int windowFlags, Rect taskBounds) { int windowFlags, Rect taskBounds) {
final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888, final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER); 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( final TaskSnapshot snapshot = new TaskSnapshot(
System.currentTimeMillis(), System.currentTimeMillis(),
new ComponentName("", ""), buffer, new ComponentName("", ""), buffer,
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
Surface.ROTATION_0, contentInsets, false, Surface.ROTATION_0, taskSize, contentInsets, false,
1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
0 /* systemUiVisibility */, false /* isTranslucent */); 0 /* systemUiVisibility */, false /* isTranslucent */);
mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test", mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0, createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
@@ -152,7 +163,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
@Test @Test
public void testCalculateSnapshotCrop_taskNotOnTop() { 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()); assertEquals(new Rect(0, 10, 100, 90), mSurface.calculateSnapshotCrop());
} }