diff options
18 files changed, 245 insertions, 508 deletions
@@ -80,7 +80,6 @@ LOCAL_SRC_FILES += \ core/java/android/app/job/IJobCallback.aidl \ core/java/android/app/job/IJobScheduler.aidl \ core/java/android/app/job/IJobService.aidl \ - core/java/android/app/IThumbnailRetriever.aidl \ core/java/android/app/ITransientNotification.aidl \ core/java/android/app/IUiAutomationConnection.aidl \ core/java/android/app/IUiModeManager.aidl \ diff --git a/CleanSpec.mk b/CleanSpec.mk index 73f370d..909fdb6 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -205,6 +205,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/androi $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app) # ****************************************************************** # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 87140a3..6e45868 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -18,6 +18,7 @@ package android.app; import android.os.BatteryStats; import android.os.IBinder; +import android.os.ParcelFileDescriptor; import com.android.internal.app.IUsageStats; import com.android.internal.app.ProcessStats; import com.android.internal.os.TransferPipe; @@ -1018,28 +1019,6 @@ public class ActivityManager { } /** - * Remove some end of a task's activity stack that is not part of - * the main application. The selected activities will be finished, so - * they are no longer part of the main task. - * - * @param taskId The identifier of the task. - * @param subTaskIndex The number of the sub-task; this corresponds - * to the index of the thumbnail returned by {@link #getTaskThumbnails(int)}. - * @return Returns true if the sub-task was found and was removed. - * - * @hide - */ - public boolean removeSubTask(int taskId, int subTaskIndex) - throws SecurityException { - try { - return ActivityManagerNative.getDefault().removeSubTask(taskId, subTaskIndex); - } catch (RemoteException e) { - // System dead, we will be dead too soon! - return false; - } - } - - /** * If set, the process of the root activity of the task will be killed * as part of removing the task. * @hide @@ -1067,26 +1046,17 @@ public class ActivityManager { } /** @hide */ - public static class TaskThumbnails implements Parcelable { + public static class TaskThumbnail implements Parcelable { public Bitmap mainThumbnail; + public ParcelFileDescriptor thumbnailFileDescriptor; - public int numSubThumbbails; - - /** @hide */ - public IThumbnailRetriever retriever; - - public TaskThumbnails() { - } - - public Bitmap getSubThumbnail(int index) { - try { - return retriever.getThumbnail(index); - } catch (RemoteException e) { - return null; - } + public TaskThumbnail() { } public int describeContents() { + if (thumbnailFileDescriptor != null) { + return thumbnailFileDescriptor.describeContents(); + } return 0; } @@ -1097,8 +1067,12 @@ public class ActivityManager { } else { dest.writeInt(0); } - dest.writeInt(numSubThumbbails); - dest.writeStrongInterface(retriever); + if (thumbnailFileDescriptor != null) { + dest.writeInt(1); + thumbnailFileDescriptor.writeToParcel(dest, 0); + } else { + dest.writeInt(0); + } } public void readFromParcel(Parcel source) { @@ -1107,38 +1081,31 @@ public class ActivityManager { } else { mainThumbnail = null; } - numSubThumbbails = source.readInt(); - retriever = IThumbnailRetriever.Stub.asInterface(source.readStrongBinder()); + if (source.readInt() != 0) { + thumbnailFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(source); + } else { + thumbnailFileDescriptor = null; + } } - public static final Creator<TaskThumbnails> CREATOR = new Creator<TaskThumbnails>() { - public TaskThumbnails createFromParcel(Parcel source) { - return new TaskThumbnails(source); + public static final Creator<TaskThumbnail> CREATOR = new Creator<TaskThumbnail>() { + public TaskThumbnail createFromParcel(Parcel source) { + return new TaskThumbnail(source); } - public TaskThumbnails[] newArray(int size) { - return new TaskThumbnails[size]; + public TaskThumbnail[] newArray(int size) { + return new TaskThumbnail[size]; } }; - private TaskThumbnails(Parcel source) { + private TaskThumbnail(Parcel source) { readFromParcel(source); } } /** @hide */ - public TaskThumbnails getTaskThumbnails(int id) throws SecurityException { - try { - return ActivityManagerNative.getDefault().getTaskThumbnails(id); - } catch (RemoteException e) { - // System dead, we will be dead too soon! - return null; - } - } - - /** @hide */ - public Bitmap getTaskTopThumbnail(int id) throws SecurityException { + public TaskThumbnail getTaskThumbnail(int id) throws SecurityException { try { - return ActivityManagerNative.getDefault().getTaskTopThumbnail(id); + return ActivityManagerNative.getDefault().getTaskThumbnail(id); } catch (RemoteException e) { // System dead, we will be dead too soon! return null; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 572d389..9e10e3d 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -548,28 +548,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case GET_TASK_THUMBNAILS_TRANSACTION: { + case GET_TASK_THUMBNAIL_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int id = data.readInt(); - ActivityManager.TaskThumbnails bm = getTaskThumbnails(id); + ActivityManager.TaskThumbnail taskThumbnail = getTaskThumbnail(id); reply.writeNoException(); - if (bm != null) { + if (taskThumbnail != null) { reply.writeInt(1); - bm.writeToParcel(reply, 0); - } else { - reply.writeInt(0); - } - return true; - } - - case GET_TASK_TOP_THUMBNAIL_TRANSACTION: { - data.enforceInterface(IActivityManager.descriptor); - int id = data.readInt(); - Bitmap bm = getTaskTopThumbnail(id); - reply.writeNoException(); - if (bm != null) { - reply.writeInt(1); - bm.writeToParcel(reply, 0); + taskThumbnail.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } @@ -1799,17 +1785,6 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case REMOVE_SUB_TASK_TRANSACTION: - { - data.enforceInterface(IActivityManager.descriptor); - int taskId = data.readInt(); - int subTaskIndex = data.readInt(); - boolean result = removeSubTask(taskId, subTaskIndex); - reply.writeNoException(); - reply.writeInt(result ? 1 : 0); - return true; - } - case REMOVE_TASK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); @@ -2773,35 +2748,20 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return list; } - public ActivityManager.TaskThumbnails getTaskThumbnails(int id) throws RemoteException { + public ActivityManager.TaskThumbnail getTaskThumbnail(int id) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(id); - mRemote.transact(GET_TASK_THUMBNAILS_TRANSACTION, data, reply, 0); + mRemote.transact(GET_TASK_THUMBNAIL_TRANSACTION, data, reply, 0); reply.readException(); - ActivityManager.TaskThumbnails bm = null; + ActivityManager.TaskThumbnail taskThumbnail = null; if (reply.readInt() != 0) { - bm = ActivityManager.TaskThumbnails.CREATOR.createFromParcel(reply); + taskThumbnail = ActivityManager.TaskThumbnail.CREATOR.createFromParcel(reply); } data.recycle(); reply.recycle(); - return bm; - } - public Bitmap getTaskTopThumbnail(int id) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IActivityManager.descriptor); - data.writeInt(id); - mRemote.transact(GET_TASK_TOP_THUMBNAIL_TRANSACTION, data, reply, 0); - reply.readException(); - Bitmap bm = null; - if (reply.readInt() != 0) { - bm = Bitmap.CREATOR.createFromParcel(reply); - } - data.recycle(); - reply.recycle(); - return bm; + return taskThumbnail; } public List getServices(int maxNum, int flags) throws RemoteException { Parcel data = Parcel.obtain(); @@ -4516,20 +4476,6 @@ class ActivityManagerProxy implements IActivityManager return result; } - public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IActivityManager.descriptor); - data.writeInt(taskId); - data.writeInt(subTaskIndex); - mRemote.transact(REMOVE_SUB_TASK_TRANSACTION, data, reply, 0); - reply.readException(); - boolean result = reply.readInt() != 0; - reply.recycle(); - data.recycle(); - return result; - } - public boolean removeTask(int taskId, int flags) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index b630278..01977fe 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -116,8 +116,7 @@ public interface IActivityManager extends IInterface { public List<RunningTaskInfo> getTasks(int maxNum, int flags) throws RemoteException; public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags, int userId) throws RemoteException; - public ActivityManager.TaskThumbnails getTaskThumbnails(int taskId) throws RemoteException; - public Bitmap getTaskTopThumbnail(int taskId) throws RemoteException; + public ActivityManager.TaskThumbnail getTaskThumbnail(int taskId) throws RemoteException; public List<RunningServiceInfo> getServices(int maxNum, int flags) throws RemoteException; public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() throws RemoteException; @@ -360,8 +359,6 @@ public interface IActivityManager extends IInterface { public boolean isUserRunning(int userid, boolean orStopping) throws RemoteException; public int[] getRunningUserIds() throws RemoteException; - public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException; - public boolean removeTask(int taskId, int flags) throws RemoteException; public void registerProcessObserver(IProcessObserver observer) throws RemoteException; @@ -631,7 +628,7 @@ public interface IActivityManager extends IInterface { int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78; int KILL_PIDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79; int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80; - int GET_TASK_THUMBNAILS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81; + int GET_TASK_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81; int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82; int GET_DEVICE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+83; int PEEK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+84; @@ -644,7 +641,7 @@ public interface IActivityManager extends IInterface { int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91; int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92; int HANDLE_INCOMING_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93; - int GET_TASK_TOP_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94; + int ___AVAILABLE_2___ = IBinder.FIRST_CALL_TRANSACTION+94; int KILL_APPLICATION_WITH_APPID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95; int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96; int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97; @@ -680,7 +677,7 @@ public interface IActivityManager extends IInterface { int GET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+127; int SET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+128; int SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+129; - int REMOVE_SUB_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+130; + int ___AVAILABLE_1___ = IBinder.FIRST_CALL_TRANSACTION+130; int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+131; int REGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+132; int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+133; diff --git a/core/java/android/app/IThumbnailRetriever.aidl b/core/java/android/app/IThumbnailRetriever.aidl deleted file mode 100644 index 410cc20..0000000 --- a/core/java/android/app/IThumbnailRetriever.aidl +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright 2011, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ -package android.app; - -import android.graphics.Bitmap; - -/** - * System private API for retrieving thumbnails - * {@hide} - */ -interface IThumbnailRetriever { - Bitmap getThumbnail(int index); -} diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java index aa4e69a..1b215c9 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java @@ -40,6 +40,7 @@ import android.view.MotionEvent; import android.view.View; import com.android.systemui.R; +import com.android.systemui.recents.Utilities; import com.android.systemui.statusbar.phone.PhoneStatusBar; import java.util.ArrayList; @@ -199,7 +200,7 @@ public class RecentTasksLoader implements View.OnTouchListener { final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); final PackageManager pm = mContext.getPackageManager(); - Bitmap thumbnail = am.getTaskTopThumbnail(td.persistentTaskId); + final Bitmap thumbnail = Utilities.getThumbnail(am, td.persistentTaskId); Drawable icon = getFullResIcon(td.resolveInfo, pm); if (td.userId != UserHandle.myUserId()) { // Need to badge the icon diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java index f7f86c4..3765d1c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java @@ -208,7 +208,7 @@ public class SystemServicesProxy { return thumbnail; } - Bitmap thumbnail = mAm.getTaskTopThumbnail(taskId); + Bitmap thumbnail = Utilities.getThumbnail(mAm, taskId); if (thumbnail != null) { // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top // left pixel, then assume the whole thumbnail is transparent. Generally, proper diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java index 6d6376f..6a7cfcc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java @@ -16,10 +16,15 @@ package com.android.systemui.recents; +import android.app.ActivityManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.ParcelFileDescriptor; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -90,4 +95,21 @@ public class Utilities { throws IllegalAccessException, InvocationTargetException { sPropertyMethod.invoke(null, property, value); } + + /** Retrieves a task thumbnail from the activity manager */ + public static Bitmap getThumbnail(ActivityManager activityManager, int taskId) { + ActivityManager.TaskThumbnail taskThumbnail = activityManager.getTaskThumbnail(taskId); + Bitmap thumbnail = taskThumbnail.mainThumbnail; + final ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor; + if (thumbnail == null && descriptor != null) { + thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor()); + } + if (descriptor != null) { + try { + descriptor.close(); + } catch (IOException e) { + } + } + return thumbnail; + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 45367a8..56be936 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -270,7 +270,10 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); // Maximum number of recent tasks that we can remember. - static final int MAX_RECENT_TASKS = ActivityManager.isLowRamDeviceStatic() ? 10 : 200; + static final int MAX_RECENT_TASKS = ActivityManager.isLowRamDeviceStatic() ? 100 : 200; + + // Maximum number recent bitmaps to keep in memory. + static final int MAX_RECENT_BITMAPS = 5; // Amount of time after a call to stopAppSwitches() during which we will // prevent further untrusted switches from happening. @@ -3601,6 +3604,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (task.userId != tr.userId) { continue; } + if (i > MAX_RECENT_BITMAPS) { + tr.freeLastThumbnail(); + } final Intent trIntent = tr.intent; if ((task.affinity == null || !task.affinity.equals(tr.affinity)) && (intent == null || !intent.filterEquals(trIntent))) { @@ -7348,26 +7354,13 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public ActivityManager.TaskThumbnails getTaskThumbnails(int id) { + public ActivityManager.TaskThumbnail getTaskThumbnail(int id) { synchronized (this) { enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, - "getTaskThumbnails()"); + "getTaskThumbnail()"); TaskRecord tr = recentTaskForIdLocked(id); if (tr != null) { - return tr.getTaskThumbnailsLocked(); - } - } - return null; - } - - @Override - public Bitmap getTaskTopThumbnail(int id) { - synchronized (this) { - enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, - "getTaskTopThumbnail()"); - TaskRecord tr = recentTaskForIdLocked(id); - if (tr != null) { - return tr.getTaskTopThumbnailLocked(); + return tr.getTaskThumbnailLocked(); } } return null; @@ -7384,24 +7377,6 @@ public final class ActivityManagerService extends ActivityManagerNative } } - @Override - public boolean removeSubTask(int taskId, int subTaskIndex) { - synchronized (this) { - enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, - "removeSubTask()"); - long ident = Binder.clearCallingIdentity(); - try { - TaskRecord tr = recentTaskForIdLocked(taskId); - if (tr != null) { - return tr.removeTaskActivitiesLocked(subTaskIndex, true) != null; - } - return false; - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - private void killUnneededProcessLocked(ProcessRecord pr, String reason) { if (!pr.killedByAm) { Slog.i(TAG, "Killing " + pr.toShortString() + " (adj " + pr.setAdj + "): " + reason); @@ -7473,7 +7448,7 @@ public final class ActivityManagerService extends ActivityManagerNative private boolean removeTaskByIdLocked(int taskId, int flags) { TaskRecord tr = recentTaskForIdLocked(taskId); if (tr != null) { - tr.removeTaskActivitiesLocked(-1, false); + tr.removeTaskActivitiesLocked(); cleanUpRemovedTaskLocked(tr, flags); if (tr.isPersistable) { notifyTaskPersisterLocked(tr, true); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 287ad00..fd2a0b1 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; import android.os.PersistableBundle; import android.os.Trace; @@ -113,7 +114,6 @@ final class ActivityRecord { int realTheme; // actual theme resource we will use, never 0. int windowFlags; // custom window flags for preview window. TaskRecord task; // the task this is in. - ThumbnailHolder thumbHolder; // where our thumbnails should go. long createTime = System.currentTimeMillis(); long displayStartTime; // when we started launching this activity long fullyDrawnStartTime; // when we started launching this activity @@ -262,13 +262,6 @@ final class ActivityRecord { pw.print(" forceNewConfig="); pw.println(forceNewConfig); pw.print(prefix); pw.print("mActivityType="); pw.println(activityTypeToString(mActivityType)); - pw.print(prefix); pw.print("thumbHolder: "); - pw.print(Integer.toHexString(System.identityHashCode(thumbHolder))); - if (thumbHolder != null) { - pw.print(" bm="); pw.print(thumbHolder.lastThumbnail); - pw.print(" desc="); pw.print(thumbHolder.lastDescription); - } - pw.println(); if (displayStartTime != 0 || startTime != 0) { pw.print(prefix); pw.print("displayStartTime="); if (displayStartTime == 0) pw.print("0"); @@ -497,7 +490,7 @@ final class ActivityRecord { } } - void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) { + void setTask(TaskRecord newTask, boolean isRoot) { if (task != null && task.removeActivity(this)) { if (task != newTask) { task.stack.removeTask(task); @@ -506,18 +499,7 @@ final class ActivityRecord { (newTask == null ? null : newTask.stack)); } } - if (newThumbHolder == null) { - newThumbHolder = newTask; - } task = newTask; - if (!isRoot && (intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { - // This is the start of a new sub-task. - if (thumbHolder == null) { - thumbHolder = new ThumbnailHolder(); - } - } else { - thumbHolder = newThumbHolder; - } } boolean changeWindowTranslucency(boolean toOpaque) { @@ -764,18 +746,15 @@ final class ActivityRecord { } void updateThumbnail(Bitmap newThumbnail, CharSequence description) { - if (thumbHolder != null) { - if (newThumbnail != null) { - if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG, - "Setting thumbnail of " + this + " holder " + thumbHolder - + " to " + newThumbnail); - thumbHolder.lastThumbnail = newThumbnail; - if (isPersistable()) { - mStackSupervisor.mService.notifyTaskPersisterLocked(task, false); - } + if (newThumbnail != null) { + if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG, + "Setting thumbnail of " + this + " to " + newThumbnail); + task.setLastThumbnail(newThumbnail); + if (isPersistable()) { + mStackSupervisor.mService.notifyTaskPersisterLocked(task, false); } - thumbHolder.lastDescription = description; } + task.lastDescription = description; } void startLaunchTickingLocked() { @@ -1051,6 +1030,11 @@ final class ActivityRecord { return null; } + private static String createImageFilename(ActivityRecord r) { + return String.valueOf(r.task.taskId) + ACTIVITY_ICON_SUFFIX + r.createTime + + TaskPersister.IMAGE_EXTENSION; + } + void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { out.attribute(null, ATTR_ID, String.valueOf(createTime)); out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid)); @@ -1064,8 +1048,7 @@ final class ActivityRecord { out.attribute(null, ATTR_USERID, String.valueOf(userId)); if (taskDescription != null) { - TaskPersister.saveTaskDescription(taskDescription, String.valueOf(task.taskId) + - ACTIVITY_ICON_SUFFIX + createTime, out); + task.saveTaskDescription(taskDescription, createImageFilename(this), out); } out.startTag(null, TAG_INTENT); @@ -1109,9 +1092,9 @@ final class ActivityRecord { componentSpecified = Boolean.valueOf(attrValue); } else if (ATTR_USERID.equals(attrName)) { userId = Integer.valueOf(attrValue); - } else if (TaskPersister.readTaskDescriptionAttribute(taskDescription, attrName, + } else if (TaskRecord.readTaskDescriptionAttribute(taskDescription, attrName, attrValue)) { - // Completed in TaskPersister.readTaskDescriptionAttribute() + // Completed in TaskRecord.readTaskDescriptionAttribute() } else { Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName); } @@ -1157,8 +1140,7 @@ final class ActivityRecord { r.persistentState = persistentState; if (createTime >= 0) { - taskDescription.setIcon(TaskPersister.restoreImage(String.valueOf(taskId) + - ACTIVITY_ICON_SUFFIX + createTime)); + taskDescription.setIcon(TaskPersister.restoreImage(createImageFilename(r))); } r.taskDescription = taskDescription; r.createTime = createTime; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 1ecb43c..f2922c3 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2063,7 +2063,6 @@ final class ActivityStack { // bottom of the activity stack. This also keeps it // correctly ordered with any activities we previously // moved. - final ThumbnailHolder newThumbHolder; final TaskRecord targetTask; final ActivityRecord bottom = !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ? @@ -2074,20 +2073,16 @@ final class ActivityStack { // same task affinity as the one we are moving, // then merge it into the same task. targetTask = bottom.task; - newThumbHolder = bottom.thumbHolder == null ? targetTask : bottom.thumbHolder; if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target + " out to bottom task " + bottom.task); } else { targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info, null, null, null, false); - newThumbHolder = targetTask; targetTask.affinityIntent = target.intent; if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target + " out to new task " + target.task); } - target.thumbHolder = newThumbHolder; - final int targetTaskId = targetTask.taskId; mWindowManager.setAppGroupId(target.appToken, targetTaskId); @@ -2099,7 +2094,6 @@ final class ActivityStack { continue; } - ThumbnailHolder curThumbHolder = p.thumbHolder; canMoveOptions = false; if (noOptions && topOptions == null) { topOptions = p.takeOptionsLocked(); @@ -2112,7 +2106,7 @@ final class ActivityStack { + " Callers=" + Debug.getCallers(4)); if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p + " out to target's task " + target.task); - p.setTask(targetTask, curThumbHolder, false); + p.setTask(targetTask, false); targetTask.addActivityAtBottom(p); mWindowManager.setAppGroupId(p.appToken, targetTaskId); @@ -2243,7 +2237,7 @@ final class ActivityStack { + start + "-" + i + " to task=" + task + ":" + taskInsertionPoint); for (int srcPos = start; srcPos >= i; --srcPos) { final ActivityRecord p = activities.get(srcPos); - p.setTask(task, null, false); + p.setTask(task, false); task.addActivityAtIndex(taskInsertionPoint, p); if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + p @@ -3626,8 +3620,8 @@ final class ActivityStack { ci.topActivity = top.intent.getComponent(); ci.lastActiveTime = task.lastActiveTime; - if (top.thumbHolder != null) { - ci.description = top.thumbHolder.lastDescription; + if (top.task != null) { + ci.description = top.task.lastDescription; } ci.numActivities = numActivities; ci.numRunning = numRunning; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index e7f5720..dbd3638 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1894,11 +1894,11 @@ public final class ActivityStackSupervisor implements DisplayListener { r.setTask(targetStack.createTaskRecord(getNextTaskId(), newTaskInfo != null ? newTaskInfo : r.info, newTaskIntent != null ? newTaskIntent : intent, - voiceSession, voiceInteractor, true), null, true); + voiceSession, voiceInteractor, true), true); if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " + r.task); } else { - r.setTask(reuseTask, reuseTask, true); + r.setTask(reuseTask, true); } if (!movedHome) { if ((launchFlags & @@ -1959,7 +1959,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // An existing activity is starting this new activity, so we want // to keep the new one in the same task as the one that is starting // it. - r.setTask(sourceTask, sourceRecord.thumbHolder, false); + r.setTask(sourceTask, false); if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in existing task " + r.task + " from source " + sourceRecord); @@ -1970,9 +1970,8 @@ public final class ActivityStackSupervisor implements DisplayListener { targetStack = adjustStackFocus(r, newTask); targetStack.moveToFront(); ActivityRecord prev = targetStack.topActivity(); - r.setTask(prev != null ? prev.task - : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, null, null, true), - null, true); + r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(), + r.info, intent, null, null, true), true); mWindowManager.moveTaskToTop(r.task.taskId); if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new guessed " + r.task); diff --git a/services/core/java/com/android/server/am/TaskAccessInfo.java b/services/core/java/com/android/server/am/TaskAccessInfo.java deleted file mode 100644 index 50aeec1..0000000 --- a/services/core/java/com/android/server/am/TaskAccessInfo.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.am; - -import java.util.ArrayList; - -import android.app.ActivityManager.TaskThumbnails; - -final class TaskAccessInfo extends TaskThumbnails { - final static class SubTask { - ThumbnailHolder holder; - ActivityRecord activity; - int index; - } - - public ActivityRecord root; - public int rootIndex; - - public ArrayList<SubTask> subtasks; -} diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index eee7e9e..1982d7e 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -40,6 +40,7 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.LinkedList; public class TaskPersister { static final String TAG = "TaskPersister"; @@ -53,15 +54,12 @@ public class TaskPersister { private static final String TASKS_DIRNAME = "recent_tasks"; private static final String TASK_EXTENSION = ".xml"; private static final String IMAGES_DIRNAME = "recent_images"; - private static final String IMAGE_EXTENSION = ".png"; + static final String IMAGE_EXTENSION = ".png"; private static final String TAG_TASK = "task"; - private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label"; - private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color"; - - private static File sImagesDir; - private static File sTasksDir; + static File sImagesDir; + static File sTasksDir; private final ActivityManagerService mService; private final ActivityStackSupervisor mStackSupervisor; @@ -132,49 +130,8 @@ public class TaskPersister { return stringWriter; } - static void saveImage(Bitmap image, String filename) throws IOException { - if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename); - FileOutputStream imageFile = null; - try { - imageFile = new FileOutputStream(new File(sImagesDir, filename + IMAGE_EXTENSION)); - image.compress(Bitmap.CompressFormat.PNG, 100, imageFile); - } catch (Exception e) { - Slog.e(TAG, "saveImage: unable to save " + filename, e); - } finally { - if (imageFile != null) { - imageFile.close(); - } - } - } - - static 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) { - saveImage(icon, iconFilename); - } - } - } - - static boolean readTaskDescriptionAttribute(ActivityManager.TaskDescription taskDescription, - String attrName, String attrValue) { - if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) { - taskDescription.setLabel(attrValue); - return true; - } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) { - taskDescription.setPrimaryColor((int) Long.parseLong(attrValue, 16)); - return true; - } - return false; + void saveImage(Bitmap image, String filename) { + mLazyTaskWriterThread.saveImage(image, filename); } private String fileToString(File file) { @@ -314,16 +271,33 @@ public class TaskPersister { static Bitmap restoreImage(String filename) { if (DEBUG) Slog.d(TAG, "restoreImage: restoring " + filename); - return BitmapFactory.decodeFile(sImagesDir + File.separator + filename + IMAGE_EXTENSION); + return BitmapFactory.decodeFile(sImagesDir + File.separator + filename); } private class LazyTaskWriterThread extends Thread { boolean mSlow = true; + LinkedList<BitmapQueueEntry> mSaveImagesQueue = new LinkedList<BitmapQueueEntry>(); LazyTaskWriterThread(String name) { super(name); } + class BitmapQueueEntry { + final Bitmap mImage; + final String mFilename; + BitmapQueueEntry(Bitmap image, String filename) { + mImage = image; + mFilename = filename; + } + } + + void saveImage(Bitmap image, String filename) { + synchronized (mSaveImagesQueue) { + mSaveImagesQueue.add(new BitmapQueueEntry(image, filename)); + } + TaskPersister.this.notify(null, false); + } + @Override public void run() { ArraySet<Integer> persistentTaskIds = new ArraySet<Integer>(); @@ -344,6 +318,32 @@ public class TaskPersister { } } + // Write out one bitmap that needs saving each time through. + BitmapQueueEntry entry; + synchronized (mSaveImagesQueue) { + entry = mSaveImagesQueue.poll(); + // Are there any more after this one? + mRecentsChanged |= !mSaveImagesQueue.isEmpty(); + } + if (entry != null) { + final String filename = entry.mFilename; + if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename); + FileOutputStream imageFile = null; + try { + imageFile = new FileOutputStream(new File(sImagesDir, filename)); + entry.mImage.compress(Bitmap.CompressFormat.PNG, 100, imageFile); + } catch (Exception e) { + Slog.e(TAG, "saveImage: unable to save " + filename, e); + } finally { + if (imageFile != null) { + try { + imageFile.close(); + } catch (IOException e) { + } + } + } + } + StringWriter stringWriter = null; TaskRecord task = null; synchronized(mService) { diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 3ef9494..d221f96 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -24,12 +24,13 @@ 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.ActivityOptions; -import android.app.IThumbnailRetriever; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; +import android.os.ParcelFileDescriptor; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.util.Slog; @@ -39,12 +40,12 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; -final class TaskRecord extends ThumbnailHolder { - private static final String TAG_TASK = "task"; +final class TaskRecord { private static final String ATTR_TASKID = "task_id"; private static final String TAG_INTENT = "intent"; private static final String TAG_AFFINITYINTENT = "affinity_intent"; @@ -60,6 +61,8 @@ final class TaskRecord extends ThumbnailHolder { 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 LAST_ACTIVITY_ICON_SUFFIX = "_last_activity_icon_"; private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail"; @@ -72,7 +75,6 @@ final class TaskRecord extends ThumbnailHolder { Intent affinityIntent; // Intent of affinity-moved activity that started this task. ComponentName origActivity; // The non-alias activity component of the intent. ComponentName realActivity; // The actual activity component that started the task. - int numActivities; // Current number of activities in this task. long lastActiveTime; // Last time this task was active, including sleep. boolean rootWasReset; // True if the intent at the root of the task had // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. @@ -123,11 +125,18 @@ final class TaskRecord extends ThumbnailHolder { // do not want to delete the stack when the task goes empty. boolean mReuseTask = false; + private Bitmap mLastThumbnail; // Last thumbnail captured for this item. + private final File mLastThumbnailFile; // File containing last thubmnail. + private final String mFilename; + CharSequence lastDescription; // Last description captured for this item. + final ActivityManagerService mService; TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) { mService = service; + mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + TaskPersister.IMAGE_EXTENSION; + mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename); taskId = _taskId; voiceSession = _voiceSession; voiceInteractor = _voiceInteractor; @@ -142,6 +151,8 @@ final class TaskRecord extends ThumbnailHolder { long lastTimeMoved, boolean neverRelinquishIdentity, ActivityManager.TaskDescription _lastTaskDescription) { mService = service; + mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + TaskPersister.IMAGE_EXTENSION; + mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename); taskId = _taskId; intent = _intent; affinityIntent = _affinityIntent; @@ -240,16 +251,38 @@ final class TaskRecord extends ThumbnailHolder { return mTaskToReturnTo; } - void disposeThumbnail() { - super.disposeThumbnail(); - for (int i=mActivities.size()-1; i>=0; i--) { - ThumbnailHolder thumb = mActivities.get(i).thumbHolder; - if (thumb != this) { - thumb.disposeThumbnail(); + void setLastThumbnail(Bitmap thumbnail) { + mLastThumbnail = thumbnail; + if (thumbnail == null) { + if (mLastThumbnailFile != null) { + mLastThumbnailFile.delete(); + } + } else { + mService.mTaskPersister.saveImage(thumbnail, mFilename); + } + } + + void getLastThumbnail(TaskThumbnail thumbs) { + thumbs.mainThumbnail = mLastThumbnail; + thumbs.thumbnailFileDescriptor = null; + if (mLastThumbnailFile.exists()) { + try { + thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile, + ParcelFileDescriptor.MODE_READ_ONLY); + } catch (IOException e) { } } } + void freeLastThumbnail() { + mLastThumbnail = null; + } + + void disposeThumbnail() { + mLastThumbnail = null; + lastDescription = null; + } + /** Returns the intent for the root activity for this task */ Intent getBaseIntent() { return intent != null ? intent : affinityIntent; @@ -470,63 +503,22 @@ final class TaskRecord extends ThumbnailHolder { return null; } - public ActivityManager.TaskThumbnails getTaskThumbnailsLocked() { - TaskAccessInfo info = getTaskAccessInfoLocked(); - final ActivityRecord resumedActivity = stack.mResumedActivity; - if (resumedActivity != null && resumedActivity.thumbHolder == this) { - info.mainThumbnail = stack.screenshotActivities(resumedActivity); - } - if (info.mainThumbnail == null) { - info.mainThumbnail = lastThumbnail; - } - return info; - } - - public Bitmap getTaskTopThumbnailLocked() { + public TaskThumbnail getTaskThumbnailLocked() { if (stack != null) { final ActivityRecord resumedActivity = stack.mResumedActivity; if (resumedActivity != null && resumedActivity.task == this) { - // This task is the current resumed task, we just need to take - // a screenshot of it and return that. - return stack.screenshotActivities(resumedActivity); + final Bitmap thumbnail = stack.screenshotActivities(resumedActivity); + setLastThumbnail(thumbnail); } } - // Return the information about the task, to figure out the top - // thumbnail to return. - TaskAccessInfo info = getTaskAccessInfoLocked(); - if (info.numSubThumbbails <= 0) { - return info.mainThumbnail != null ? info.mainThumbnail : lastThumbnail; - } - return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail; + final TaskThumbnail taskThumbnail = new TaskThumbnail(); + getLastThumbnail(taskThumbnail); + return taskThumbnail; } - public ActivityRecord removeTaskActivitiesLocked(int subTaskIndex, - boolean taskRequired) { - TaskAccessInfo info = getTaskAccessInfoLocked(); - if (info.root == null) { - if (taskRequired) { - Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId); - } - return null; - } - - if (subTaskIndex < 0) { - // Just remove the entire task. - performClearTaskAtIndexLocked(info.rootIndex); - return info.root; - } - - if (subTaskIndex >= info.subtasks.size()) { - if (taskRequired) { - Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex); - } - return null; - } - - // Remove all of this task's activities starting at the sub task. - TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex); - performClearTaskAtIndexLocked(subtask.index); - return subtask.activity; + public void removeTaskActivitiesLocked() { + // Just remove the entire task. + performClearTaskAtIndexLocked(0); } boolean isHomeTask() { @@ -541,68 +533,6 @@ final class TaskRecord extends ThumbnailHolder { return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE; } - public TaskAccessInfo getTaskAccessInfoLocked() { - final TaskAccessInfo thumbs = new TaskAccessInfo(); - // How many different sub-thumbnails? - final int NA = mActivities.size(); - int j = 0; - ThumbnailHolder holder = null; - while (j < NA) { - ActivityRecord ar = mActivities.get(j); - if (!ar.finishing) { - thumbs.root = ar; - thumbs.rootIndex = j; - holder = ar.thumbHolder; - if (holder != null) { - thumbs.mainThumbnail = holder.lastThumbnail; - } - j++; - break; - } - j++; - } - - if (j >= NA) { - return thumbs; - } - - ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>(); - thumbs.subtasks = subtasks; - while (j < NA) { - ActivityRecord ar = mActivities.get(j); - j++; - if (ar.finishing) { - continue; - } - if (ar.thumbHolder != holder && holder != null) { - thumbs.numSubThumbbails++; - holder = ar.thumbHolder; - TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask(); - sub.holder = holder; - sub.activity = ar; - sub.index = j-1; - subtasks.add(sub); - } - } - if (thumbs.numSubThumbbails > 0) { - thumbs.retriever = new IThumbnailRetriever.Stub() { - @Override - public Bitmap getThumbnail(int index) { - if (index < 0 || index >= thumbs.subtasks.size()) { - return null; - } - TaskAccessInfo.SubTask sub = thumbs.subtasks.get(index); - ActivityRecord resumedActivity = stack.mResumedActivity; - if (resumedActivity != null && resumedActivity.thumbHolder == sub.holder) { - return stack.screenshotActivities(resumedActivity); - } - return sub.holder.lastThumbnail; - } - }; - } - return thumbs; - } - /** * Find the activity in the history stack within the given task. Returns * the index within the history at which it's found, or < 0 if not found. @@ -691,6 +621,36 @@ final class TaskRecord extends ThumbnailHolder { setIntent(r.intent, r.info); } + 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; + } + void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { Slog.i(TAG, "Saving task=" + this); @@ -716,7 +676,7 @@ final class TaskRecord extends ThumbnailHolder { } if (lastTaskDescription != null) { - TaskPersister.saveTaskDescription(lastTaskDescription, String.valueOf(taskId) + + saveTaskDescription(lastTaskDescription, String.valueOf(taskId) + LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime, out); } @@ -744,11 +704,6 @@ final class TaskRecord extends ThumbnailHolder { r.saveToXml(out); out.endTag(null, TAG_ACTIVITY); } - - final Bitmap thumbnail = getTaskTopThumbnailLocked(); - if (thumbnail != null) { - TaskPersister.saveImage(thumbnail, String.valueOf(taskId) + TASK_THUMBNAIL_SUFFIX); - } } static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) @@ -800,8 +755,7 @@ final class TaskRecord extends ThumbnailHolder { lastTimeOnTop = Long.valueOf(attrValue); } else if (ATTR_NEVERRELINQUISH.equals(attrName)) { neverRelinquishIdentity = Boolean.valueOf(attrValue); - } else if (TaskPersister.readTaskDescriptionAttribute(taskDescription, attrName, - attrValue)) { + } else if (readTaskDescriptionAttribute(taskDescription, attrName, attrValue)) { // Completed in TaskPersister.readTaskDescriptionAttribute() } else { Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); @@ -836,7 +790,7 @@ final class TaskRecord extends ThumbnailHolder { if (lastActiveTime >= 0) { taskDescription.setIcon(TaskPersister.restoreImage(String.valueOf(taskId) + - LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime)); + LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime + TaskPersister.IMAGE_EXTENSION)); } final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, @@ -845,12 +799,9 @@ final class TaskRecord extends ThumbnailHolder { lastTimeOnTop, neverRelinquishIdentity, taskDescription); for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { - final ActivityRecord r = activities.get(activityNdx); - r.thumbHolder = r.task = task; + activities.get(activityNdx).task = task; } - task.lastThumbnail = TaskPersister.restoreImage(taskId + TASK_THUMBNAIL_SUFFIX); - Slog.i(TAG, "Restored task=" + task); return task; } @@ -898,7 +849,8 @@ final class TaskRecord extends ThumbnailHolder { if (!askedCompatMode) { pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode); } - pw.print(prefix); pw.print("lastThumbnail="); pw.print(lastThumbnail); + pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail); + pw.print(" lastThumbnailFile="); pw.print(mLastThumbnailFile); pw.print(" lastDescription="); pw.println(lastDescription); pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible); pw.print(" lastActiveTime="); pw.print(lastActiveTime); diff --git a/services/core/java/com/android/server/am/ThumbnailHolder.java b/services/core/java/com/android/server/am/ThumbnailHolder.java deleted file mode 100644 index a6974f5..0000000 --- a/services/core/java/com/android/server/am/ThumbnailHolder.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.am; - -import android.graphics.Bitmap; - -public class ThumbnailHolder { - Bitmap lastThumbnail; // Last thumbnail captured for this item. - CharSequence lastDescription; // Last description captured for this item. - - void disposeThumbnail() { - lastThumbnail = null; - lastDescription = null; - } -} diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java index d7a6c1d..0e063d6 100644 --- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java +++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java @@ -72,7 +72,7 @@ public class ActivityTestMain extends Activity { private void addThumbnail(LinearLayout container, Bitmap bm, final ActivityManager.RecentTaskInfo task, - final ActivityManager.TaskThumbnails thumbs, final int subIndex) { + final ActivityManager.TaskThumbnail thumbs) { ImageView iv = new ImageView(this); if (bm != null) { iv.setImageBitmap(bm); @@ -86,9 +86,6 @@ public class ActivityTestMain extends Activity { @Override public void onClick(View v) { if (task.id >= 0 && thumbs != null) { - if (subIndex < (thumbs.numSubThumbbails-1)) { - mAm.removeSubTask(task.id, subIndex+1); - } mAm.moveTaskToFront(task.id, ActivityManager.MOVE_TASK_WITH_HOME); } else { try { @@ -104,11 +101,7 @@ public class ActivityTestMain extends Activity { @Override public boolean onLongClick(View v) { if (task.id >= 0 && thumbs != null) { - if (subIndex < 0) { - mAm.removeTask(task.id, ActivityManager.REMOVE_TASK_KILL_PROCESS); - } else { - mAm.removeSubTask(task.id, subIndex); - } + mAm.removeTask(task.id, ActivityManager.REMOVE_TASK_KILL_PROCESS); buildUi(); return true; } @@ -333,7 +326,7 @@ public class ActivityTestMain extends Activity { if (recents != null) { for (int i=0; i<recents.size(); i++) { ActivityManager.RecentTaskInfo r = recents.get(i); - ActivityManager.TaskThumbnails tt = mAm.getTaskThumbnails(r.persistentId); + ActivityManager.TaskThumbnail tt = mAm.getTaskThumbnail(r.persistentId); TextView tv = new TextView(this); tv.setText(r.baseIntent.getComponent().flattenToShortString()); top.addView(tv, new LinearLayout.LayoutParams( @@ -341,10 +334,7 @@ public class ActivityTestMain extends Activity { LinearLayout.LayoutParams.WRAP_CONTENT)); LinearLayout item = new LinearLayout(this); item.setOrientation(LinearLayout.HORIZONTAL); - addThumbnail(item, tt != null ? tt.mainThumbnail : null, r, tt, -1); - for (int j=0; j<tt.numSubThumbbails; j++) { - addThumbnail(item, tt.getSubThumbnail(j), r, tt, j); - } + addThumbnail(item, tt != null ? tt.mainThumbnail : null, r, tt); top.addView(item, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); |