Save and pass last snapshot data with recents task info

- Adds task & snapshot sizing info to RecentTaskInfo so that SysUI can
  stably layout overview when there are tasks of different sizes
- Removing some unused code

Bug: 179466077
Test: atest WmTests:RecentTasksTest
Change-Id: Idf4c27e2d04380328413459fc537ff8bcc111a14
This commit is contained in:
Winson Chung
2021-02-07 15:56:45 -08:00
parent 573555ffa8
commit 71718ad748
7 changed files with 241 additions and 183 deletions

View File

@@ -50,7 +50,9 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.hardware.HardwareBuffer;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
@@ -76,6 +78,7 @@ import android.util.Singleton;
import android.util.Size;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.window.TaskSnapshot;
import com.android.internal.app.LocalePicker;
import com.android.internal.app.procstats.ProcessStats;
@@ -1739,6 +1742,62 @@ public class ActivityManager {
* started or visited.
*/
public static class RecentTaskInfo extends TaskInfo implements Parcelable {
/**
* @hide
*/
public static class PersistedTaskSnapshotData {
/**
* The bounds of the task when the last snapshot was taken, may be null if the task is
* not yet attached to the hierarchy.
* @see {@link android.window.TaskSnapshot#mTaskSize}.
* @hide
*/
public @Nullable Point taskSize;
/**
* The content insets of the task when the task snapshot was taken.
* @see {@link android.window.TaskSnapshot#mContentInsets}.
* @hide
*/
public @Nullable Rect contentInsets;
/**
* The size of the last snapshot taken, may be null if there is no associated snapshot.
* @see {@link android.window.TaskSnapshot#mSnapshot}.
* @hide
*/
public @Nullable Point bufferSize;
/**
* Sets the data from the other data.
* @hide
*/
public void set(PersistedTaskSnapshotData other) {
taskSize = other.taskSize;
contentInsets = other.contentInsets;
bufferSize = other.bufferSize;
}
/**
* Sets the data from the provided {@param snapshot}.
* @hide
*/
public void set(TaskSnapshot snapshot) {
if (snapshot == null) {
taskSize = null;
contentInsets = null;
bufferSize = null;
return;
}
final HardwareBuffer buffer = snapshot.getHardwareBuffer();
taskSize = new Point(snapshot.getTaskSize());
contentInsets = new Rect(snapshot.getContentInsets());
bufferSize = buffer != null
? new Point(buffer.getWidth(), buffer.getHeight())
: null;
}
}
/**
* If this task is currently running, this is the identifier for it.
* If it is not running, this will be -1.
@@ -1782,6 +1841,12 @@ public class ActivityManager {
*/
public ArrayList<RecentTaskInfo> childrenTaskInfos = new ArrayList<>();
/**
* Information about the last snapshot taken for this task.
* @hide
*/
public PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData();
public RecentTaskInfo() {
}
@@ -1798,6 +1863,9 @@ public class ActivityManager {
id = source.readInt();
persistentId = source.readInt();
childrenTaskInfos = source.readArrayList(RecentTaskInfo.class.getClassLoader());
lastSnapshotData.taskSize = source.readTypedObject(Point.CREATOR);
lastSnapshotData.contentInsets = source.readTypedObject(Rect.CREATOR);
lastSnapshotData.bufferSize = source.readTypedObject(Point.CREATOR);
super.readFromParcel(source);
}
@@ -1806,6 +1874,9 @@ public class ActivityManager {
dest.writeInt(id);
dest.writeInt(persistentId);
dest.writeList(childrenTaskInfos);
dest.writeTypedObject(lastSnapshotData.taskSize, flags);
dest.writeTypedObject(lastSnapshotData.contentInsets, flags);
dest.writeTypedObject(lastSnapshotData.bufferSize, flags);
super.writeToParcel(dest, flags);
}
@@ -1825,7 +1896,6 @@ public class ActivityManager {
public void dump(PrintWriter pw, String indent) {
pw.println(); pw.print(" ");
pw.print(" id="); pw.print(persistentId);
pw.print(" stackId="); pw.print(stackId);
pw.print(" userId="); pw.print(userId);
pw.print(" hasTask="); pw.print((id != -1));
pw.print(" lastActiveTime="); pw.println(lastActiveTime);
@@ -1872,6 +1942,12 @@ public class ActivityManager {
pw.print(Integer.toHexString(td.getBackgroundColorFloating()));
pw.println(" }");
}
pw.print(" ");
pw.print(" lastSnapshotData {");
pw.print(" taskSize=" + lastSnapshotData.taskSize);
pw.print(" contentInsets=" + lastSnapshotData.contentInsets);
pw.print(" bufferSize=" + lastSnapshotData.bufferSize);
pw.println(" }");
}
}

View File

@@ -52,13 +52,6 @@ public class TaskInfo {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public int userId;
/**
* The id of the ActivityStack that currently contains this task.
* @hide
*/
@UnsupportedAppUsage
public int stackId;
/**
* The identifier for this task.
*/
@@ -358,7 +351,6 @@ public class TaskInfo {
*/
void readFromParcel(Parcel source) {
userId = source.readInt();
stackId = source.readInt();
taskId = source.readInt();
displayId = source.readInt();
isRunning = source.readBoolean();
@@ -394,7 +386,6 @@ public class TaskInfo {
*/
void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
dest.writeInt(stackId);
dest.writeInt(taskId);
dest.writeInt(displayId);
dest.writeBoolean(isRunning);
@@ -428,7 +419,7 @@ public class TaskInfo {
@Override
public String toString() {
return "TaskInfo{userId=" + userId + " stackId=" + stackId + " taskId=" + taskId
return "TaskInfo{userId=" + userId + " taskId=" + taskId
+ " displayId=" + displayId
+ " isRunning=" + isRunning
+ " baseIntent=" + baseIntent + " baseActivity=" + baseActivity

View File

@@ -17,6 +17,7 @@
package android.graphics;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -95,6 +96,27 @@ public class Point implements Parcelable {
return "Point(" + x + ", " + y + ")";
}
/**
* @return Returns a {@link String} that represents this point which can be parsed with
* {@link #unflattenFromString(String)}.
* @hide
*/
@NonNull
public String flattenToString() {
return x + "x" + y;
}
/**
* @return Returns a {@link Point} from a short string created from {@link #flattenToString()}.
* @hide
*/
@Nullable
public static Point unflattenFromString(String s) throws NumberFormatException {
final int sep_ix = s.indexOf("x");
return new Point(Integer.parseInt(s.substring(0, sep_ix)),
Integer.parseInt(s.substring(sep_ix + 1)));
}
/**
* Parcelable interface methods
*/

View File

@@ -43,17 +43,6 @@ public class Task {
public static final String TAG = "Task";
/* Task callbacks */
@Deprecated
public interface TaskCallbacks {
/* Notifies when a task has been bound */
void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
/* Notifies when a task has been unbound */
void onTaskDataUnloaded();
/* Notifies when a task's windowing mode has changed. */
void onTaskWindowingModeChanged();
}
/**
* The Task Key represents the unique primary key for the task
*/
@@ -208,12 +197,6 @@ public class Task {
@ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
public TaskKey key;
/**
* The temporary sort index in the stack, used when ordering the stack.
*/
@Deprecated
public int temporarySortIndexInStack;
/**
* The icon is the task description icon (if provided), which falls back to the activity icon,
* which can then fall back to the application icon.
@@ -229,45 +212,24 @@ public class Task {
public int colorPrimary;
@ViewDebug.ExportedProperty(category="recents")
public int colorBackground;
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public boolean useLightOnPrimaryColor;
/**
* The task description for this task, only used to reload task icons.
*/
public TaskDescription taskDescription;
/**
* The state isLaunchTarget will be set for the correct task upon launching Recents.
*/
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public boolean isLaunchTarget;
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public boolean isStackTask;
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public boolean isSystemApp;
@ViewDebug.ExportedProperty(category="recents")
public boolean isDockable;
/**
* Resize mode. See {@link ActivityInfo#resizeMode}.
*/
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public int resizeMode;
@ViewDebug.ExportedProperty(category="recents")
public ComponentName topActivity;
@ViewDebug.ExportedProperty(category="recents")
public boolean isLocked;
@Deprecated
private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
// Last snapshot data, only used for recent tasks
public ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
new ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData();
public Task() {
// Do nothing
@@ -289,6 +251,15 @@ public class Task {
this.taskDescription = new TaskDescription();
}
public Task(Task other) {
this(other.key, other.colorPrimary, other.colorBackground, other.isDockable,
other.isLocked, other.taskDescription, other.topActivity);
}
/**
* Use {@link Task#Task(Task)}.
*/
@Deprecated
public Task(TaskKey key, int colorPrimary, int colorBackground,
boolean isDockable, boolean isLocked, TaskDescription taskDescription,
ComponentName topActivity) {
@@ -301,103 +272,6 @@ public class Task {
this.topActivity = topActivity;
}
@Deprecated
public Task(TaskKey key, Drawable icon, ThumbnailData thumbnail, String title,
String titleDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget,
boolean isStackTask, boolean isSystemApp, boolean isDockable,
TaskDescription taskDescription, int resizeMode, ComponentName topActivity,
boolean isLocked) {
this.key = key;
this.icon = icon;
this.thumbnail = thumbnail;
this.title = title;
this.titleDescription = titleDescription;
this.colorPrimary = colorPrimary;
this.colorBackground = colorBackground;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
Color.WHITE) > 3f;
this.taskDescription = taskDescription;
this.isLaunchTarget = isLaunchTarget;
this.isStackTask = isStackTask;
this.isSystemApp = isSystemApp;
this.isDockable = isDockable;
this.resizeMode = resizeMode;
this.topActivity = topActivity;
this.isLocked = isLocked;
}
/**
* Copies the metadata from another task, but retains the current callbacks.
*/
@Deprecated
public void copyFrom(Task o) {
this.key = o.key;
this.icon = o.icon;
this.thumbnail = o.thumbnail;
this.title = o.title;
this.titleDescription = o.titleDescription;
this.colorPrimary = o.colorPrimary;
this.colorBackground = o.colorBackground;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
this.taskDescription = o.taskDescription;
this.isLaunchTarget = o.isLaunchTarget;
this.isStackTask = o.isStackTask;
this.isSystemApp = o.isSystemApp;
this.isDockable = o.isDockable;
this.resizeMode = o.resizeMode;
this.isLocked = o.isLocked;
this.topActivity = o.topActivity;
}
/**
* Add a callback.
*/
@Deprecated
public void addCallback(TaskCallbacks cb) {
if (!mCallbacks.contains(cb)) {
mCallbacks.add(cb);
}
}
/**
* Remove a callback.
*/
@Deprecated
public void removeCallback(TaskCallbacks cb) {
mCallbacks.remove(cb);
}
/** Updates the task's windowing mode. */
@Deprecated
public void setWindowingMode(int windowingMode) {
key.setWindowingMode(windowingMode);
int callbackCount = mCallbacks.size();
for (int i = 0; i < callbackCount; i++) {
mCallbacks.get(i).onTaskWindowingModeChanged();
}
}
/** Notifies the callback listeners that this task has been loaded */
@Deprecated
public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) {
this.icon = applicationIcon;
this.thumbnail = thumbnailData;
int callbackCount = mCallbacks.size();
for (int i = 0; i < callbackCount; i++) {
mCallbacks.get(i).onTaskDataLoaded(this, thumbnailData);
}
}
/** Notifies the callback listeners that this task has been unloaded */
@Deprecated
public void notifyTaskDataUnloaded(Drawable defaultApplicationIcon) {
icon = defaultApplicationIcon;
thumbnail = null;
for (int i = mCallbacks.size() - 1; i >= 0; i--) {
mCallbacks.get(i).onTaskDataUnloaded();
}
}
/**
* Returns the top activity component.
*/
@@ -424,9 +298,6 @@ public class Task {
if (!isDockable) {
writer.print(" dockable=N");
}
if (isLaunchTarget) {
writer.print(" launchTarget=Y");
}
if (isLocked) {
writer.print(" locked=Y");
}

View File

@@ -58,6 +58,8 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
@@ -1886,6 +1888,7 @@ class RecentTasks {
// Fill in some deprecated values.
rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
rti.persistentId = rti.taskId;
rti.lastSnapshotData.set(tr.mLastTaskSnapshotData);
// Fill in organized child task info for the task created by organizer.
if (tr.mCreatedByOrganizer) {

View File

@@ -158,6 +158,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
@@ -293,6 +294,9 @@ class Task extends WindowContainer<WindowContainer> {
private static final String ATTR_MIN_HEIGHT = "min_height";
private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
private static final String ATTR_LAST_SNAPSHOT_TASK_SIZE = "last_snapshot_task_size";
private static final String ATTR_LAST_SNAPSHOT_CONTENT_INSETS = "last_snapshot_content_insets";
private static final String ATTR_LAST_SNAPSHOT_BUFFER_SIZE = "last_snapshot_buffer_size";
// Set to false to disable the preview that is shown while a new activity
// is being started.
@@ -540,6 +544,10 @@ class Task extends WindowContainer<WindowContainer> {
// NOTE: This value needs to be persisted with each task
private TaskDescription mTaskDescription;
// Information about the last snapshot that should be persisted with the task to allow SystemUI
// to layout without loading all the task snapshots
final PersistedTaskSnapshotData mLastTaskSnapshotData;
// If set to true, the task will report that it is not in the floating
// state regardless of it's root task affiliation. As the floating state drives
// production of content insets this can be used to preserve them across
@@ -613,8 +621,6 @@ class Task extends WindowContainer<WindowContainer> {
SurfaceControl.Transaction mMainWindowSizeChangeTransaction;
Task mMainWindowSizeChangeTask;
Rect mPreAnimationBounds = new Rect();
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
new AnimatingActivityRegistry();
@@ -839,13 +845,13 @@ class Task extends WindowContainer<WindowContainer> {
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid,
String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity,
TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
int nextTaskId, int callingUid, String callingPackage,
@Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture,
boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight,
ActivityInfo info, IVoiceInteractionSession _voiceSession,
IVoiceInteractor _voiceInteractor, boolean _createdByOrganizer,
IBinder _launchCookie, boolean _deferTaskAppear) {
TaskDescription _lastTaskDescription, PersistedTaskSnapshotData _lastSnapshotData,
int taskAffiliation, int prevTaskId, int nextTaskId, int callingUid,
String callingPackage, @Nullable String callingFeatureId, int resizeMode,
boolean supportsPictureInPicture, boolean _realActivitySuspended,
boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear) {
super(atmService.mWindowManager);
mAtmService = atmService;
@@ -855,7 +861,12 @@ class Task extends WindowContainer<WindowContainer> {
mUserId = _userId;
mResizeMode = resizeMode;
mSupportsPictureInPicture = supportsPictureInPicture;
mTaskDescription = _lastTaskDescription;
mTaskDescription = _lastTaskDescription != null
? _lastTaskDescription
: new TaskDescription();
mLastTaskSnapshotData = _lastSnapshotData != null
? _lastSnapshotData
: new PersistedTaskSnapshotData();
// Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
setOrientation(SCREEN_ORIENTATION_UNSET);
mRemoteToken = new RemoteToken(this);
@@ -3899,6 +3910,7 @@ class Task extends WindowContainer<WindowContainer> {
}
void onSnapshotChanged(TaskSnapshot snapshot) {
mLastTaskSnapshotData.set(snapshot);
mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
mTaskId, snapshot);
}
@@ -4157,7 +4169,6 @@ class Task extends WindowContainer<WindowContainer> {
void fillTaskInfo(TaskInfo info, boolean stripExtras) {
getNumRunningActivities(mReuseActivitiesReport);
info.userId = isLeafTask() ? mUserId : mCurrentUser;
info.stackId = getRootTaskId();
info.taskId = mTaskId;
info.displayId = getDisplayId();
info.isRunning = getTopNonFinishingActivity() != null;
@@ -4707,6 +4718,19 @@ class Task extends WindowContainer<WindowContainer> {
out.attributeInt(null, ATTR_MIN_HEIGHT, mMinHeight);
out.attributeInt(null, ATTR_PERSIST_TASK_VERSION, PERSIST_TASK_VERSION);
if (mLastTaskSnapshotData.taskSize != null) {
out.attribute(null, ATTR_LAST_SNAPSHOT_TASK_SIZE,
mLastTaskSnapshotData.taskSize.flattenToString());
}
if (mLastTaskSnapshotData.contentInsets != null) {
out.attribute(null, ATTR_LAST_SNAPSHOT_CONTENT_INSETS,
mLastTaskSnapshotData.contentInsets.flattenToString());
}
if (mLastTaskSnapshotData.bufferSize != null) {
out.attribute(null, ATTR_LAST_SNAPSHOT_BUFFER_SIZE,
mLastTaskSnapshotData.bufferSize.flattenToString());
}
if (affinityIntent != null) {
out.startTag(null, TAG_AFFINITYINTENT);
affinityIntent.saveToXml(out);
@@ -4774,6 +4798,7 @@ class Task extends WindowContainer<WindowContainer> {
int taskId = INVALID_TASK_ID;
final int outerDepth = in.getDepth();
TaskDescription taskDescription = new TaskDescription();
PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData();
int taskAffiliation = INVALID_TASK_ID;
int prevTaskId = INVALID_TASK_ID;
int nextTaskId = INVALID_TASK_ID;
@@ -4883,6 +4908,15 @@ class Task extends WindowContainer<WindowContainer> {
case ATTR_PERSIST_TASK_VERSION:
persistTaskVersion = Integer.parseInt(attrValue);
break;
case ATTR_LAST_SNAPSHOT_TASK_SIZE:
lastSnapshotData.taskSize = Point.unflattenFromString(attrValue);
break;
case ATTR_LAST_SNAPSHOT_CONTENT_INSETS:
lastSnapshotData.contentInsets = Rect.unflattenFromString(attrValue);
break;
case ATTR_LAST_SNAPSHOT_BUFFER_SIZE:
lastSnapshotData.bufferSize = Point.unflattenFromString(attrValue);
break;
default:
if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
Slog.w(TAG, "Task: Unknown attribute=" + attrName);
@@ -4977,6 +5011,7 @@ class Task extends WindowContainer<WindowContainer> {
.setLastTimeMoved(lastTimeOnTop)
.setNeverRelinquishIdentity(neverRelinquishIdentity)
.setLastTaskDescription(taskDescription)
.setLastSnapshotData(lastSnapshotData)
.setTaskAffiliation(taskAffiliation)
.setPrevAffiliateTaskId(prevTaskId)
.setNextAffiliateTaskId(nextTaskId)
@@ -7904,6 +7939,7 @@ class Task extends WindowContainer<WindowContainer> {
private long mLastTimeMoved;
private boolean mNeverRelinquishIdentity;
private TaskDescription mLastTaskDescription;
private PersistedTaskSnapshotData mLastSnapshotData;
private int mTaskAffiliation;
private int mPrevAffiliateTaskId = INVALID_TASK_ID;
private int mNextAffiliateTaskId = INVALID_TASK_ID;
@@ -8104,6 +8140,11 @@ class Task extends WindowContainer<WindowContainer> {
return this;
}
private Builder setLastSnapshotData(PersistedTaskSnapshotData lastSnapshotData) {
mLastSnapshotData = lastSnapshotData;
return this;
}
private Builder setOrigActivity(ComponentName origActivity) {
mOrigActivity = origActivity;
return this;
@@ -8217,9 +8258,6 @@ class Task extends WindowContainer<WindowContainer> {
mCallingPackage = mActivityInfo.packageName;
mResizeMode = mActivityInfo.resizeMode;
mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture();
if (mLastTaskDescription == null) {
mLastTaskDescription = new TaskDescription();
}
final Task task = buildInner();
task.mHasBeenVisible = mHasBeenVisible;
@@ -8253,9 +8291,9 @@ class Task extends WindowContainer<WindowContainer> {
return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity,
mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents,
mAskedCompatMode, mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,
mNeverRelinquishIdentity, mLastTaskDescription, mTaskAffiliation,
mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid, mCallingPackage,
mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
mNeverRelinquishIdentity, mLastTaskDescription, mLastSnapshotData,
mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid,
mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer,
mLaunchCookie, mDeferTaskAppear);

View File

@@ -29,6 +29,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -59,6 +60,10 @@ import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.graphics.ColorSpace;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -66,6 +71,8 @@ import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
import android.util.SparseBooleanArray;
import android.view.Surface;
import android.window.TaskSnapshot;
import androidx.test.filters.MediumTest;
@@ -446,12 +453,8 @@ public class RecentTasksTest extends WindowTestsBase {
doReturn(false).when(child2).isOrganized();
mRecentTasks.add(root);
doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
final List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
true /* getTasksAllowed */, TEST_USER_0_ID, 0 /* callingUid */).getList();
// Make sure only organized child will be appended.
final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
final List<RecentTaskInfo> childrenTaskInfos = infos.get(0).childrenTaskInfos;
assertEquals(childrenTaskInfos.size(), 1);
assertEquals(childrenTaskInfos.get(0).taskId, child1.mTaskId);
@@ -1051,9 +1054,6 @@ public class RecentTasksTest extends WindowTestsBase {
@Test
public void testTaskInfo_expectNoExtras() {
doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
final Bundle data = new Bundle();
data.putInt("key", 100);
final Task task1 = createTaskBuilder(".Task").build();
@@ -1063,8 +1063,7 @@ public class RecentTasksTest extends WindowTestsBase {
.build();
mRecentTasks.add(r1.getTask());
final List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList();
final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
assertTrue(infos.size() == 1);
for (int i = 0; i < infos.size(); i++) {
final Bundle extras = infos.get(i).baseIntent.getExtras();
@@ -1072,6 +1071,60 @@ public class RecentTasksTest extends WindowTestsBase {
}
}
@Test
public void testLastSnapshotData_snapshotSaved() {
final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), new Point(80, 80));
final Task task1 = createTaskBuilder(".Task").build();
task1.onSnapshotChanged(snapshot);
mRecentTasks.add(task1);
final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
infos.get(0).lastSnapshotData;
assertTrue(lastSnapshotData.taskSize.equals(100, 100));
assertTrue(lastSnapshotData.bufferSize.equals(80, 80));
}
@Test
public void testLastSnapshotData_noBuffer() {
final Task task1 = createTaskBuilder(".Task").build();
final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), null);
task1.onSnapshotChanged(snapshot);
mRecentTasks.add(task1);
final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
infos.get(0).lastSnapshotData;
assertTrue(lastSnapshotData.taskSize.equals(100, 100));
assertNull(lastSnapshotData.bufferSize);
}
@Test
public void testLastSnapshotData_notSet() {
final Task task1 = createTaskBuilder(".Task").build();
mRecentTasks.add(task1);
final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
infos.get(0).lastSnapshotData;
assertNull(lastSnapshotData.taskSize);
assertNull(lastSnapshotData.bufferSize);
}
private TaskSnapshot createSnapshot(Point taskSize, Point bufferSize) {
HardwareBuffer buffer = null;
if (bufferSize != null) {
buffer = mock(HardwareBuffer.class);
doReturn(bufferSize.x).when(buffer).getWidth();
doReturn(bufferSize.y).when(buffer).getHeight();
}
return new TaskSnapshot(1, new ComponentName("", ""), buffer,
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
Surface.ROTATION_0, taskSize, new Rect() /* insets */, false /* isLowResolution */,
true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* mSystemUiVisibility */,
false /* isTranslucent */, false /* hasImeSurface */);
}
/**
* Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks
* should be ordered from least to most recent.
@@ -1084,15 +1137,19 @@ public class RecentTasksTest extends WindowTestsBase {
}
}
private List<RecentTaskInfo> getRecentTasks(int flags) {
doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
return mRecentTasks.getRecentTasks(MAX_VALUE, flags, true /* getTasksAllowed */,
TEST_USER_0_ID, 0 /* callingUid */).getList();
}
/**
* Ensures that the recent tasks list is in the provided order. Note that the expected tasks
* should be ordered from least to most recent.
*/
private void assertGetRecentTasksOrder(int getRecentTaskFlags, Task... expectedTasks) {
doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, getRecentTaskFlags,
true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList();
List<RecentTaskInfo> infos = getRecentTasks(getRecentTaskFlags);
assertTrue(expectedTasks.length == infos.size());
for (int i = 0; i < infos.size(); i++) {
assertTrue(expectedTasks[i].mTaskId == infos.get(i).taskId);