diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 701ab1d809dcd..5f3ed61fee204 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -5066,7 +5066,7 @@ public class Activity extends ContextThemeWrapper public void setTaskDescription(ActivityManager.TaskDescription taskDescription) { ActivityManager.TaskDescription td; // Scale the icon down to something reasonable if it is provided - if (taskDescription.getIcon() != null) { + if (taskDescription.getIconFilename() == null && taskDescription.getIcon() != null) { final int size = ActivityManager.getLauncherLargeIconSizeInner(this); final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size, true); td = new ActivityManager.TaskDescription(taskDescription.getLabel(), icon, diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 9486a72f91d48..85d4839d0c6e9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -56,9 +56,11 @@ import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Size; import android.util.Slog; +import org.xmlpull.v1.XmlSerializer; import java.io.FileDescriptor; import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -508,8 +510,18 @@ public class ActivityManager { * Information you can set and retrieve about the current activity within the recent task list. */ public static class TaskDescription implements Parcelable { + /** @hide */ + public static final String ATTR_TASKDESCRIPTION_PREFIX = "task_description_"; + private static final String ATTR_TASKDESCRIPTIONLABEL = + ATTR_TASKDESCRIPTION_PREFIX + "label"; + private static final String ATTR_TASKDESCRIPTIONCOLOR = + ATTR_TASKDESCRIPTION_PREFIX + "color"; + private static final String ATTR_TASKDESCRIPTIONICONFILENAME = + ATTR_TASKDESCRIPTION_PREFIX + "icon_filename"; + private String mLabel; private Bitmap mIcon; + private String mIconFilename; private int mColorPrimary; /** @@ -529,6 +541,12 @@ public class ActivityManager { mColorPrimary = colorPrimary; } + /** @hide */ + public TaskDescription(String label, int colorPrimary, String iconFilename) { + this(label, null, colorPrimary); + mIconFilename = iconFilename; + } + /** * Creates the TaskDescription to the specified values. * @@ -559,7 +577,10 @@ public class ActivityManager { * Creates a copy of another TaskDescription. */ public TaskDescription(TaskDescription td) { - this(td.getLabel(), td.getIcon(), td.getPrimaryColor()); + mLabel = td.mLabel; + mIcon = td.mIcon; + setPrimaryColor(td.mColorPrimary); + mIconFilename = td.mIconFilename; } private TaskDescription(Parcel source) { @@ -579,7 +600,7 @@ public class ActivityManager { * @hide */ public void setPrimaryColor(int primaryColor) { - mColorPrimary = primaryColor; + mColorPrimary = 0xFF000000 | primaryColor; } /** @@ -590,6 +611,16 @@ public class ActivityManager { mIcon = icon; } + /** + * Moves the icon bitmap reference from an actual Bitmap to a file containing the + * bitmap. + * @hide + */ + public void setIconFilename(String iconFilename) { + mIconFilename = iconFilename; + mIcon = null; + } + /** * @return The label and description of the current state of this task. */ @@ -601,7 +632,22 @@ public class ActivityManager { * @return The icon that represents the current state of this task. */ public Bitmap getIcon() { - return mIcon; + if (mIcon != null) { + return mIcon; + } + if (mIconFilename != null) { + try { + return ActivityManagerNative.getDefault(). + getTaskDescriptionIcon(mIconFilename); + } catch (RemoteException e) { + } + } + return null; + } + + /** @hide */ + public String getIconFilename() { + return mIconFilename; } /** @@ -611,6 +657,30 @@ public class ActivityManager { return mColorPrimary; } + /** @hide */ + public void saveToXml(XmlSerializer out) throws IOException { + if (mLabel != null) { + out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, mLabel); + } + if (mColorPrimary != 0) { + out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(mColorPrimary)); + } + if (mIconFilename != null) { + out.attribute(null, ATTR_TASKDESCRIPTIONICONFILENAME, mIconFilename); + } + } + + /** @hide */ + public void restoreFromXml(String attrName, String attrValue) { + if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) { + setLabel(attrValue); + } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) { + setPrimaryColor((int) Long.parseLong(attrValue, 16)); + } else if (ATTR_TASKDESCRIPTIONICONFILENAME.equals(attrName)) { + setIconFilename(attrValue); + } + } + @Override public int describeContents() { return 0; @@ -631,12 +701,19 @@ public class ActivityManager { mIcon.writeToParcel(dest, 0); } dest.writeInt(mColorPrimary); + if (mIconFilename == null) { + dest.writeInt(0); + } else { + dest.writeInt(1); + dest.writeString(mIconFilename); + } } public void readFromParcel(Parcel source) { mLabel = source.readInt() > 0 ? source.readString() : null; mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null; mColorPrimary = source.readInt(); + mIconFilename = source.readInt() > 0 ? source.readString() : null; } public static final Creator CREATOR diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 677fcef8d01a9..11470e336b65d 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2253,6 +2253,20 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case GET_TASK_DESCRIPTION_ICON_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String filename = data.readString(); + Bitmap icon = getTaskDescriptionIcon(filename); + reply.writeNoException(); + if (icon == null) { + reply.writeInt(0); + } else { + reply.writeInt(1); + icon.writeToParcel(reply, 0); + } + return true; + } + case REQUEST_VISIBLE_BEHIND_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); @@ -5240,6 +5254,20 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + @Override + public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(filename); + mRemote.transact(GET_TASK_DESCRIPTION_ICON_TRANSACTION, data, reply, 0); + reply.readException(); + final Bitmap icon = reply.readInt() == 0 ? null : Bitmap.CREATOR.createFromParcel(reply); + data.recycle(); + reply.recycle(); + return icon; + } + @Override public boolean requestVisibleBehind(IBinder token, boolean visible) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 8fa1fd5399736..aa5fea0a9e1ea 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -451,6 +451,7 @@ public interface IActivityManager extends IInterface { public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values) throws RemoteException; + public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException; public boolean requestVisibleBehind(IBinder token, boolean visible) throws RemoteException; public boolean isBackgroundVisibleBehind(IBinder token) throws RemoteException; @@ -775,4 +776,5 @@ public interface IActivityManager extends IInterface { int RELEASE_ACTIVITY_INSTANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+235; int RELEASE_SOME_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+236; int BOOT_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+237; + int GET_TASK_DESCRIPTION_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+238; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6d8e10574fe57..741cffe8685ad 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8375,12 +8375,17 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r != null) { - r.taskDescription = td; + r.setTaskDescription(td); r.task.updateTaskDescription(); } } } + @Override + public Bitmap getTaskDescriptionIcon(String filename) { + return mTaskPersister.getTaskDescriptionIcon(filename); + } + private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) { mRecentTasks.remove(tr); tr.removedFromRecents(mTaskPersister); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index adea27108f677..2db7cec611399 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -205,14 +205,18 @@ final class ActivityRecord { pw.print(" resultWho="); pw.print(resultWho); pw.print(" resultCode="); pw.println(requestCode); } - if (taskDescription.getIcon() != null || taskDescription.getLabel() != null || + final String iconFilename = taskDescription.getIconFilename(); + if (iconFilename != null || taskDescription.getLabel() != null || taskDescription.getPrimaryColor() != 0) { pw.print(prefix); pw.print("taskDescription:"); - pw.print(" icon="); pw.print(taskDescription.getIcon()); + pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename()); pw.print(" label=\""); pw.print(taskDescription.getLabel()); pw.print("\""); pw.print(" color="); pw.println(Integer.toHexString(taskDescription.getPrimaryColor())); } + if (iconFilename == null && taskDescription.getIcon() != null) { + pw.print(prefix); pw.println("taskDescription contains Bitmap"); + } if (results != null) { pw.print(prefix); pw.print("results="); pw.println(results); } @@ -1093,6 +1097,17 @@ final class ActivityRecord { TaskPersister.IMAGE_EXTENSION; } + void setTaskDescription(TaskDescription _taskDescription) { + Bitmap icon; + if (_taskDescription.getIconFilename() == null && + (icon = _taskDescription.getIcon()) != null) { + final String iconFilename = createImageFilename(createTime, task.taskId); + mStackSupervisor.mService.mTaskPersister.saveImage(icon, iconFilename); + _taskDescription.setIconFilename(iconFilename); + } + taskDescription = _taskDescription; + } + void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { out.attribute(null, ATTR_ID, String.valueOf(createTime)); out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid)); @@ -1106,8 +1121,7 @@ final class ActivityRecord { out.attribute(null, ATTR_USERID, String.valueOf(userId)); if (taskDescription != null) { - task.saveTaskDescription(taskDescription, createImageFilename(createTime, task.taskId), - out); + taskDescription.saveToXml(out); } out.startTag(null, TAG_INTENT); @@ -1151,9 +1165,8 @@ final class ActivityRecord { componentSpecified = Boolean.valueOf(attrValue); } else if (ATTR_USERID.equals(attrName)) { userId = Integer.valueOf(attrValue); - } else if (TaskRecord.readTaskDescriptionAttribute(taskDescription, attrName, - attrValue)) { - // Completed in TaskRecord.readTaskDescriptionAttribute() + } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { + taskDescription.restoreFromXml(attrName, attrValue); } else { Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName); } @@ -1197,11 +1210,6 @@ final class ActivityRecord { null, null, 0, componentSpecified, stackSupervisor, null, null); r.persistentState = persistentState; - - if (createTime >= 0) { - taskDescription.setIcon(TaskPersister.restoreImage(createImageFilename(createTime, - taskId))); - } r.taskDescription = taskDescription; r.createTime = createTime; diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index df1772a56550e..1c0564f03b166 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -218,7 +218,16 @@ public class TaskPersister { yieldIfQueueTooDeep(); } - Bitmap getThumbnail(String filename) { + Bitmap getTaskDescriptionIcon(String filename) { + // See if it is in the write queue + final Bitmap icon = getImageFromWriteQueue(filename); + if (icon != null) { + return icon; + } + return restoreImage(filename); + } + + Bitmap getImageFromWriteQueue(String filename) { synchronized (this) { for (int queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) { final WriteQueueItem item = mWriteQueue.get(queueNdx); diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index f74b795f63148..4a0d6549feb18 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -25,6 +25,7 @@ import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.TaskThumbnail; +import android.app.ActivityManager.TaskDescription; import android.app.ActivityOptions; import android.app.AppGlobals; import android.content.ComponentName; @@ -70,15 +71,12 @@ final class TaskRecord { private static final String ATTR_LASTDESCRIPTION = "last_description"; private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; - private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label"; - private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color"; private static final String ATTR_TASK_AFFILIATION = "task_affiliation"; private static final String ATTR_PREV_AFFILIATION = "prev_affiliation"; private static final String ATTR_NEXT_AFFILIATION = "next_affiliation"; private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color"; private static final String ATTR_CALLING_UID = "calling_uid"; private static final String ATTR_CALLING_PACKAGE = "calling_package"; - private static final String LAST_ACTIVITY_ICON_SUFFIX = "_last_activity_icon_"; private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail"; @@ -113,8 +111,7 @@ final class TaskRecord { // This represents the last resolved activity values for this task // NOTE: This value needs to be persisted with each task - ActivityManager.TaskDescription lastTaskDescription = - new ActivityManager.TaskDescription(); + TaskDescription lastTaskDescription = new TaskDescription(); /** List of all activities in the task arranged in history order */ final ArrayList mActivities; @@ -180,7 +177,7 @@ final class TaskRecord { } TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, - ActivityManager.TaskDescription _taskDescription) { + TaskDescription _taskDescription) { mService = service; mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + TaskPersister.IMAGE_EXTENSION; @@ -215,7 +212,7 @@ final class TaskRecord { boolean _askedCompatMode, int _taskType, int _userId, int _effectiveUid, String _lastDescription, ArrayList activities, long _firstActiveTime, long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity, - ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation, + TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage) { mService = service; @@ -441,7 +438,7 @@ final class TaskRecord { thumbs.mainThumbnail = mLastThumbnail; thumbs.thumbnailFileDescriptor = null; if (mLastThumbnail == null) { - thumbs.mainThumbnail = mService.mTaskPersister.getThumbnail(mFilename); + thumbs.mainThumbnail = mService.mTaskPersister.getImageFromWriteQueue(mFilename); } // Only load the thumbnail file if we don't have a thumbnail if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) { @@ -759,7 +756,7 @@ final class TaskRecord { // recent activity values, then we do not fall back to the last set // values in the TaskRecord. String label = null; - Bitmap icon = null; + String iconFilename = null; int colorPrimary = 0; for (--activityNdx; activityNdx >= 0; --activityNdx) { final ActivityRecord r = mActivities.get(activityNdx); @@ -767,15 +764,15 @@ final class TaskRecord { if (label == null) { label = r.taskDescription.getLabel(); } - if (icon == null) { - icon = r.taskDescription.getIcon(); + if (iconFilename == null) { + iconFilename = r.taskDescription.getIconFilename(); } if (colorPrimary == 0) { colorPrimary = r.taskDescription.getPrimaryColor(); } } } - lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary); + lastTaskDescription = new TaskDescription(label, colorPrimary, iconFilename); // Update the task affiliation color if we are the parent of the group if (taskId == mAffiliatedTaskId) { mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor(); @@ -804,41 +801,6 @@ final class TaskRecord { setIntent(r); } - void saveTaskDescription(ActivityManager.TaskDescription taskDescription, - String iconFilename, XmlSerializer out) throws IOException { - if (taskDescription != null) { - final String label = taskDescription.getLabel(); - if (label != null) { - out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label); - } - final int colorPrimary = taskDescription.getPrimaryColor(); - if (colorPrimary != 0) { - out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary)); - } - final Bitmap icon = taskDescription.getIcon(); - if (icon != null) { - mService.mTaskPersister.saveImage(icon, iconFilename); - } - } - } - - static boolean readTaskDescriptionAttribute(ActivityManager.TaskDescription taskDescription, - String attrName, String attrValue) { - if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) { - taskDescription.setLabel(attrValue); - } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) { - taskDescription.setPrimaryColor((int) Long.parseLong(attrValue, 16)); - } else { - return false; - } - return true; - } - - private static String createLastTaskDescriptionIconFilename(int taskId, long lastActiveTime) { - return String.valueOf(taskId) + LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime + - TaskPersister.IMAGE_EXTENSION; - } - void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { if (ActivityManagerService.DEBUG_RECENTS) Slog.i(TAG, "Saving task=" + this); @@ -875,8 +837,7 @@ final class TaskRecord { out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); } if (lastTaskDescription != null) { - saveTaskDescription(lastTaskDescription, createLastTaskDescriptionIconFilename(taskId, - lastActiveTime), out); + lastTaskDescription.saveToXml(out); } out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); @@ -934,7 +895,7 @@ final class TaskRecord { boolean neverRelinquishIdentity = true; int taskId = -1; final int outerDepth = in.getDepth(); - ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription(); + TaskDescription taskDescription = new TaskDescription(); int taskAffiliation = -1; int taskAffiliationColor = 0; int prevTaskId = -1; @@ -980,8 +941,8 @@ final class TaskRecord { lastTimeOnTop = Long.valueOf(attrValue); } else if (ATTR_NEVERRELINQUISH.equals(attrName)) { neverRelinquishIdentity = Boolean.valueOf(attrValue); - } else if (readTaskDescriptionAttribute(taskDescription, attrName, attrValue)) { - // Completed in TaskPersister.readTaskDescriptionAttribute() + } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { + taskDescription.restoreFromXml(attrName, attrValue); } else if (ATTR_TASK_AFFILIATION.equals(attrName)) { taskAffiliation = Integer.valueOf(attrValue); } else if (ATTR_PREV_AFFILIATION.equals(attrName)) { @@ -1025,11 +986,6 @@ final class TaskRecord { } } - if (lastActiveTime >= 0) { - taskDescription.setIcon(TaskPersister.restoreImage( - createLastTaskDescriptionIconFilename(taskId, lastActiveTime))); - } - if (!hasRootAffinity) { rootAffinity = affinity; } else if ("@".equals(rootAffinity)) {