diff options
7 files changed, 165 insertions, 29 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index ac54960b61f9..351064a2fd0d 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1531,14 +1531,90 @@ public class ActivityManager { } } + /** + * Metadata related to the {@link TaskThumbnail}. + * + * @hide + */ + public static class TaskThumbnailInfo implements Parcelable { + /** @hide */ + public static final String ATTR_TASK_THUMBNAILINFO_PREFIX = "task_thumbnailinfo_"; + private static final String ATTR_TASK_WIDTH = + ATTR_TASK_THUMBNAILINFO_PREFIX + "task_width"; + private static final String ATTR_TASK_HEIGHT = + ATTR_TASK_THUMBNAILINFO_PREFIX + "task_height"; + private static final String ATTR_SCREEN_ORIENTATION = + ATTR_TASK_THUMBNAILINFO_PREFIX + "screen_orientation"; + + public int taskWidth; + public int taskHeight; + public int screenOrientation; + + public TaskThumbnailInfo() { + // Do nothing + } + + private TaskThumbnailInfo(Parcel source) { + readFromParcel(source); + } + + /** @hide */ + public void saveToXml(XmlSerializer out) throws IOException { + out.attribute(null, ATTR_TASK_WIDTH, Integer.toString(taskWidth)); + out.attribute(null, ATTR_TASK_HEIGHT, Integer.toString(taskHeight)); + out.attribute(null, ATTR_SCREEN_ORIENTATION, Integer.toString(screenOrientation)); + } + + /** @hide */ + public void restoreFromXml(String attrName, String attrValue) { + if (ATTR_TASK_WIDTH.equals(attrName)) { + taskWidth = Integer.parseInt(attrValue); + } else if (ATTR_TASK_HEIGHT.equals(attrName)) { + taskHeight = Integer.parseInt(attrValue); + } else if (ATTR_SCREEN_ORIENTATION.equals(attrName)) { + screenOrientation = Integer.parseInt(attrValue); + } + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(taskWidth); + dest.writeInt(taskHeight); + dest.writeInt(screenOrientation); + } + + public void readFromParcel(Parcel source) { + taskWidth = source.readInt(); + taskHeight = source.readInt(); + screenOrientation = source.readInt(); + } + + public static final Creator<TaskThumbnailInfo> CREATOR = new Creator<TaskThumbnailInfo>() { + public TaskThumbnailInfo createFromParcel(Parcel source) { + return new TaskThumbnailInfo(source); + } + public TaskThumbnailInfo[] newArray(int size) { + return new TaskThumbnailInfo[size]; + } + }; + } + /** @hide */ public static class TaskThumbnail implements Parcelable { public Bitmap mainThumbnail; public ParcelFileDescriptor thumbnailFileDescriptor; + public TaskThumbnailInfo thumbnailInfo; public TaskThumbnail() { } + private TaskThumbnail(Parcel source) { + readFromParcel(source); + } + public int describeContents() { if (thumbnailFileDescriptor != null) { return thumbnailFileDescriptor.describeContents(); @@ -1559,6 +1635,12 @@ public class ActivityManager { } else { dest.writeInt(0); } + if (thumbnailInfo != null) { + dest.writeInt(1); + thumbnailInfo.writeToParcel(dest, flags); + } else { + dest.writeInt(0); + } } public void readFromParcel(Parcel source) { @@ -1572,6 +1654,11 @@ public class ActivityManager { } else { thumbnailFileDescriptor = null; } + if (source.readInt() != 0) { + thumbnailInfo = TaskThumbnailInfo.CREATOR.createFromParcel(source); + } else { + thumbnailInfo = null; + } } public static final Creator<TaskThumbnail> CREATOR = new Creator<TaskThumbnail>() { @@ -1582,10 +1669,6 @@ public class ActivityManager { return new TaskThumbnail[size]; } }; - - private TaskThumbnail(Parcel source) { - readFromParcel(source); - } } /** @hide */ diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 99e30f3370d5..0cf58b1e95e5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -114,6 +114,7 @@ import com.android.server.SystemService; import com.android.server.SystemServiceManager; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.ActivityStackSupervisor.ActivityDisplay; import com.android.server.firewall.IntentFirewall; import com.android.server.pm.Installer; import com.android.server.pm.UserManagerService; @@ -134,6 +135,7 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; +import android.app.ActivityManager.TaskThumbnailInfo; import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal.SleepToken; import android.app.ActivityManagerNative; @@ -8577,8 +8579,16 @@ public final class ActivityManagerService extends ActivityManagerNative } } + // Use the full screen as the context for the task thumbnail + final Point displaySize = new Point(); + final TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo(); + r.task.stack.getDisplaySize(displaySize); + thumbnailInfo.taskWidth = displaySize.x; + thumbnailInfo.taskHeight = displaySize.y; + thumbnailInfo.screenOrientation = mConfiguration.orientation; + TaskRecord task = new TaskRecord(this, mStackSupervisor.getNextTaskId(), ainfo, - intent, description); + intent, description, thumbnailInfo); int trimIdx = mRecentTasks.trimForTaskLocked(task, false); if (trimIdx >= 0) { @@ -8597,7 +8607,7 @@ public final class ActivityManagerService extends ActivityManagerNative mRecentTasks.add(task); r.task.stack.addTask(task, false, false); - task.setLastThumbnail(thumbnail); + task.setLastThumbnailLocked(thumbnail); task.freeLastThumbnail(); return task.taskId; diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 9278a9074c6b..aa04bd70c714 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -932,7 +932,7 @@ final class ActivityRecord { if (newThumbnail != null) { if (DEBUG_THUMBNAILS) Slog.i(TAG_THUMBNAILS, "Setting thumbnail of " + this + " to " + newThumbnail); - boolean thumbnailUpdated = task.setLastThumbnail(newThumbnail); + boolean thumbnailUpdated = task.setLastThumbnailLocked(newThumbnail); if (thumbnailUpdated && isPersistable()) { mStackSupervisor.mService.notifyTaskPersisterLocked(task, false); } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index ea0db6b44a40..400ebc68026d 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -31,6 +31,7 @@ import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; import static com.android.server.am.ActivityStackSupervisor.MOVING; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import android.graphics.Point; import android.graphics.Rect; import android.util.ArraySet; @@ -388,6 +389,10 @@ final class ActivityStack { mWindowManager.detachStack(mStackId); } + public void getDisplaySize(Point out) { + mActivityContainer.mActivityDisplay.mDisplay.getSize(out); + } + void setBounds(Rect bounds) { mBounds = mFullscreen ? null : new Rect(bounds); if (mTaskPositioner != null) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index f62442470dd8..6acaa773b2bd 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -3681,7 +3681,7 @@ public final class ActivityStackSupervisor implements DisplayListener { void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) { r.mLaunchTaskBehind = false; final TaskRecord task = r.task; - task.setLastThumbnail(task.stack.screenshotActivities(r)); + task.setLastThumbnailLocked(task.stack.screenshotActivities(r)); mRecentTasks.addLocked(task); mService.notifyTaskStackChangedLocked(); mWindowManager.setAppVisibility(r.appToken, false); diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index 871331b770e2..150baf0e89d5 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -16,22 +16,14 @@ package com.android.server.am; -import android.app.ActivityManager; -import android.app.AppGlobals; -import android.content.ComponentName; import android.content.pm.IPackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Debug; -import android.os.RemoteException; import android.os.SystemClock; -import android.os.UserHandle; -import android.text.format.DateUtils; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Slog; -import android.util.SparseArray; import android.util.Xml; import android.os.Process; @@ -51,14 +43,10 @@ import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; -import java.util.List; import libcore.io.IoUtils; -import static com.android.server.am.TaskRecord.INVALID_TASK_ID; - public class TaskPersister { static final String TAG = "TaskPersister"; static final boolean DEBUG = false; @@ -104,6 +92,7 @@ public class TaskPersister { private static class WriteQueueItem {} private static class TaskWriteQueueItem extends WriteQueueItem { final TaskRecord mTask; + TaskWriteQueueItem(TaskRecord task) { mTask = task; } @@ -111,6 +100,7 @@ public class TaskPersister { private static class ImageWriteQueueItem extends WriteQueueItem { final String mFilename; Bitmap mImage; + ImageWriteQueueItem(String filename, Bitmap image) { mFilename = filename; mImage = image; diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 803a273652d6..22c30252bcee 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -37,6 +37,8 @@ import android.app.ActivityManager; import android.app.ActivityManager.StackId; import android.app.ActivityManager.TaskThumbnail; import android.app.ActivityManager.TaskDescription; +import android.app.ActivityManager.TaskThumbnail; +import android.app.ActivityManager.TaskThumbnailInfo; import android.app.ActivityOptions; import android.app.AppGlobals; import android.content.ComponentName; @@ -47,6 +49,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.Point; import android.graphics.Rect; import android.os.Debug; import android.os.ParcelFileDescriptor; @@ -194,6 +197,7 @@ final class TaskRecord { private Bitmap mLastThumbnail; // Last thumbnail captured for this item. private final File mLastThumbnailFile; // File containing last thumbnail. private final String mFilename; + private TaskThumbnailInfo mLastThumbnailInfo; CharSequence lastDescription; // Last description captured for this item. int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent. @@ -234,6 +238,7 @@ final class TaskRecord { mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + TaskPersister.IMAGE_EXTENSION; mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename); + mLastThumbnailInfo = new TaskThumbnailInfo(); taskId = _taskId; mAffiliatedTaskId = _taskId; voiceSession = _voiceSession; @@ -247,11 +252,12 @@ final class TaskRecord { } TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, - TaskDescription _taskDescription) { + TaskDescription _taskDescription, TaskThumbnailInfo thumbnailInfo) { mService = service; mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + TaskPersister.IMAGE_EXTENSION; mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename); + mLastThumbnailInfo = thumbnailInfo; taskId = _taskId; mAffiliatedTaskId = _taskId; voiceSession = null; @@ -282,12 +288,14 @@ final class TaskRecord { int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, long _firstActiveTime, long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, - int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, - int callingUid, String callingPackage, boolean resizeable, boolean privileged) { + TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId, + int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, + boolean resizeable, boolean privileged) { mService = service; mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + TaskPersister.IMAGE_EXTENSION; mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename); + mLastThumbnailInfo = lastThumbnailInfo; taskId = _taskId; intent = _intent; affinityIntent = _affinityIntent; @@ -490,12 +498,40 @@ final class TaskRecord { } /** - * Sets the last thumbnail. + * Sets the last thumbnail with the current task bounds and the system orientation. * @return whether the thumbnail was set */ - boolean setLastThumbnail(Bitmap thumbnail) { + boolean setLastThumbnailLocked(Bitmap thumbnail) { + final Configuration serviceConfig = mService.mConfiguration; + int taskWidth = 0; + int taskHeight = 0; + if (mBounds != null) { + // Non-fullscreen tasks + taskWidth = mBounds.width(); + taskHeight = mBounds.height(); + } else if (stack != null) { + // Fullscreen tasks + final Point displaySize = new Point(); + stack.getDisplaySize(displaySize); + taskWidth = displaySize.x; + taskHeight = displaySize.y; + } else { + Slog.e(TAG, "setLastThumbnailLocked() called on Task without stack"); + } + return setLastThumbnailLocked(thumbnail, taskWidth, taskHeight, serviceConfig.orientation); + } + + /** + * Sets the last thumbnail with the current task bounds. + * @return whether the thumbnail was set + */ + private boolean setLastThumbnailLocked(Bitmap thumbnail, int taskWidth, int taskHeight, + int screenOrientation) { if (mLastThumbnail != thumbnail) { mLastThumbnail = thumbnail; + mLastThumbnailInfo.taskWidth = taskWidth; + mLastThumbnailInfo.taskHeight = taskHeight; + mLastThumbnailInfo.screenOrientation = screenOrientation; if (thumbnail == null) { if (mLastThumbnailFile != null) { mLastThumbnailFile.delete(); @@ -510,6 +546,7 @@ final class TaskRecord { void getLastThumbnail(TaskThumbnail thumbs) { thumbs.mainThumbnail = mLastThumbnail; + thumbs.thumbnailInfo = mLastThumbnailInfo; thumbs.thumbnailFileDescriptor = null; if (mLastThumbnail == null) { thumbs.mainThumbnail = mService.mTaskPersister.getImageFromWriteQueue(mFilename); @@ -524,12 +561,19 @@ final class TaskRecord { } } + /** + * Removes in-memory thumbnail data when the max number of in-memory task thumbnails is reached. + */ void freeLastThumbnail() { mLastThumbnail = null; } + /** + * Removes all associated thumbnail data when a task is removed or pruned from recents. + */ void disposeThumbnail() { mLastThumbnail = null; + mLastThumbnailInfo = null; lastDescription = null; } @@ -779,7 +823,7 @@ final class TaskRecord { final ActivityRecord resumedActivity = stack.mResumedActivity; if (resumedActivity != null && resumedActivity.task == this) { final Bitmap thumbnail = stack.screenshotActivities(resumedActivity); - setLastThumbnail(thumbnail); + setLastThumbnailLocked(thumbnail); } } final TaskThumbnail taskThumbnail = new TaskThumbnail(); @@ -991,6 +1035,7 @@ final class TaskRecord { if (lastTaskDescription != null) { lastTaskDescription.saveToXml(out); } + mLastThumbnailInfo.saveToXml(out); out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); @@ -1035,7 +1080,7 @@ final class TaskRecord { throws IOException, XmlPullParserException { Intent intent = null; Intent affinityIntent = null; - ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); + ArrayList<ActivityRecord> activities = new ArrayList<>(); ComponentName realActivity = null; ComponentName origActivity = null; String affinity = null; @@ -1055,6 +1100,7 @@ final class TaskRecord { int taskId = INVALID_TASK_ID; final int outerDepth = in.getDepth(); TaskDescription taskDescription = new TaskDescription(); + TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo(); int taskAffiliation = INVALID_TASK_ID; int taskAffiliationColor = 0; int prevTaskId = INVALID_TASK_ID; @@ -1103,6 +1149,8 @@ final class TaskRecord { lastTimeOnTop = Long.valueOf(attrValue); } else if (ATTR_NEVERRELINQUISH.equals(attrName)) { neverRelinquishIdentity = Boolean.valueOf(attrValue); + } else if (attrName.startsWith(TaskThumbnailInfo.ATTR_TASK_THUMBNAILINFO_PREFIX)) { + thumbnailInfo.restoreFromXml(attrName, attrValue); } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { taskDescription.restoreFromXml(attrName, attrValue); } else if (ATTR_TASK_AFFILIATION.equals(attrName)) { @@ -1181,8 +1229,8 @@ final class TaskRecord { affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription, activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, - taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, - callingUid, callingPackage, resizeable, privileged); + taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId, + taskAffiliationColor, callingUid, callingPackage, resizeable, privileged); task.updateOverrideConfiguration(bounds); for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { |