From 15491c6a728131e322c45bc440500a8a78e4a410 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 19 Sep 2012 10:59:14 -0700 Subject: [PATCH] Switch to showing top-most thumbnail of recent apps. The way it should have been, and with the new recents enter animation the way it must be. Added a new method to retrieve this thumbnail, since it would be less efficient to use the existing API (which always returns the "base" thumbnail). Probably at some point that existing API should be tweaked to always return the top thumbnail instead, but that is for a later time. Also removed code that would clear the thumbnail associated with an activity when it is resumed. I don't think there should ever be a reason to clear a thumbnail -- it's much better to have *something* for the task, even if it is a little out of date. Change-Id: I83e6ca6403eb2df5e4de3009dfe8c210e8cf8d5b --- core/java/android/app/ActivityManager.java | 12 ++++- .../android/app/ActivityManagerNative.java | 33 ++++++++++++- core/java/android/app/IActivityManager.java | 3 +- .../systemui/recent/RecentTasksLoader.java | 8 ++-- .../server/am/ActivityManagerService.java | 13 ++++++ .../com/android/server/am/ActivityRecord.java | 18 ++++---- .../com/android/server/am/ActivityStack.java | 46 ++++++++++++------- .../com/android/server/am/TaskAccessInfo.java | 3 +- 8 files changed, 102 insertions(+), 34 deletions(-) diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 06f79e719f70b..0eda6b4e090f3 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -864,7 +864,17 @@ public class ActivityManager { return null; } } - + + /** @hide */ + public Bitmap getTaskTopThumbnail(int id) throws SecurityException { + try { + return ActivityManagerNative.getDefault().getTaskTopThumbnail(id); + } catch (RemoteException e) { + // System dead, we will be dead too soon! + return null; + } + } + /** * Flag for {@link #moveTaskToFront(int, int)}: also move the "home" * activity along with the task, so it is positioned immediately behind diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 773f73cbd1dea..8436b2c0b560a 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -498,7 +498,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeTypedList(list); return true; } - + case GET_TASK_THUMBNAILS_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int id = data.readInt(); @@ -512,7 +512,21 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM } 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); + } else { + reply.writeInt(0); + } + return true; + } + case GET_SERVICES_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int maxNum = data.readInt(); @@ -2307,6 +2321,21 @@ class ActivityManagerProxy implements IActivityManager 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; + } public List getServices(int maxNum, 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 2fb17b64e6735..d6ebc9b4ffba8 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -104,6 +104,7 @@ public interface IActivityManager extends IInterface { public List 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 List getServices(int maxNum, int flags) throws RemoteException; public List getProcessesInErrorState() throws RemoteException; @@ -548,7 +549,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 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; diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java index 6d8435098635a..7260844840751 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java @@ -193,14 +193,14 @@ public class RecentTasksLoader implements View.OnTouchListener { final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); final PackageManager pm = mContext.getPackageManager(); - ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(td.persistentTaskId); + Bitmap thumbnail = am.getTaskTopThumbnail(td.persistentTaskId); Drawable icon = getFullResIcon(td.resolveInfo, pm); if (DEBUG) Log.v(TAG, "Loaded bitmap for task " - + td + ": " + thumbs.mainThumbnail); + + td + ": " + thumbnail); synchronized (td) { - if (thumbs != null && thumbs.mainThumbnail != null) { - td.setThumbnail(thumbs.mainThumbnail); + if (thumbnail != null) { + td.setThumbnail(thumbnail); } else { td.setThumbnail(mDefaultThumbnailBackground); } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index ce5424b424f06..110ab50b70f04 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -168,6 +168,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean localLOGV = DEBUG; static final boolean DEBUG_SWITCH = localLOGV || false; static final boolean DEBUG_TASKS = localLOGV || false; + static final boolean DEBUG_THUMBNAILS = localLOGV || false; static final boolean DEBUG_PAUSE = localLOGV || false; static final boolean DEBUG_OOM_ADJ = localLOGV || false; static final boolean DEBUG_TRANSITION = localLOGV || false; @@ -5846,6 +5847,18 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } + public Bitmap getTaskTopThumbnail(int id) { + synchronized (this) { + enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, + "getTaskTopThumbnail()"); + TaskRecord tr = taskForIdLocked(id); + if (tr != null) { + return mMainStack.getTaskTopThumbnailLocked(tr); + } + } + return null; + } + public boolean removeSubTask(int taskId, int subTaskIndex) { synchronized (this) { enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 009fb5dd6dcc7..7ff574838df0f 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -219,7 +219,13 @@ final class ActivityRecord { pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy); pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded); pw.print(" forceNewConfig="); pw.println(forceNewConfig); - pw.print(prefix); pw.print("thumbHolder="); pw.println(thumbHolder); + 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 (launchTime != 0 || startTime != 0) { pw.print(prefix); pw.print("launchTime="); if (launchTime == 0) pw.print("0"); @@ -674,19 +680,15 @@ final class ActivityRecord { } 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; } thumbHolder.lastDescription = description; } } - void clearThumbnail() { - if (thumbHolder != null) { - thumbHolder.lastThumbnail = null; - thumbHolder.lastDescription = null; - } - } - void startLaunchTickingLocked() { if (ActivityManagerService.IS_USER_BUILD) { return; diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 29ee0bcfe5a9a..df50d898dee7b 100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -1203,8 +1203,7 @@ final class ActivityStack { if (mMainStack) { mService.reportResumedActivityLocked(next); } - - next.clearThumbnail(); + if (mMainStack) { mService.setFocusedActivityLocked(next); } @@ -4328,18 +4327,33 @@ final class ActivityStack { finishTaskMoveLocked(task); return true; } - + public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) { TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true); ActivityRecord resumed = mResumedActivity; if (resumed != null && resumed.thumbHolder == tr) { info.mainThumbnail = resumed.stack.screenshotActivities(resumed); - } else { - info.mainThumbnail = tr.lastThumbnail; } return info; } + public Bitmap getTaskTopThumbnailLocked(TaskRecord tr) { + ActivityRecord resumed = mResumedActivity; + if (resumed != null && resumed.task == tr) { + // This task is the current resumed task, we just need to take + // a screenshot of it and return that. + return resumed.stack.screenshotActivities(resumed); + } + // Return the information about the task, to figure out the top + // thumbnail to return. + TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true); + if (info.numSubThumbbails <= 0) { + return info.mainThumbnail; + } else { + return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail; + } + } + public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex, boolean taskRequired) { TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false); @@ -4370,7 +4384,6 @@ final class ActivityStack { } public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) { - ActivityRecord resumed = mResumedActivity; final TaskAccessInfo thumbs = new TaskAccessInfo(); // How many different sub-thumbnails? final int NA = mHistory.size(); @@ -4380,6 +4393,10 @@ final class ActivityStack { ActivityRecord ar = mHistory.get(j); if (!ar.finishing && ar.task.taskId == taskId) { holder = ar.thumbHolder; + if (holder != null) { + thumbs.mainThumbnail = holder.lastThumbnail; + } + j++; break; } j++; @@ -4394,7 +4411,6 @@ final class ActivityStack { ArrayList subtasks = new ArrayList(); thumbs.subtasks = subtasks; - ActivityRecord lastActivity = null; while (j < NA) { ActivityRecord ar = mHistory.get(j); j++; @@ -4404,30 +4420,28 @@ final class ActivityStack { if (ar.task.taskId != taskId) { break; } - lastActivity = ar; if (ar.thumbHolder != holder && holder != null) { thumbs.numSubThumbbails++; holder = ar.thumbHolder; TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask(); - sub.thumbnail = holder.lastThumbnail; + sub.holder = holder; sub.activity = ar; sub.index = j-1; subtasks.add(sub); } } - if (lastActivity != null && subtasks.size() > 0) { - if (resumed == lastActivity) { - TaskAccessInfo.SubTask sub = subtasks.get(subtasks.size()-1); - sub.thumbnail = lastActivity.stack.screenshotActivities(lastActivity); - } - } if (thumbs.numSubThumbbails > 0) { thumbs.retriever = new IThumbnailRetriever.Stub() { public Bitmap getThumbnail(int index) { if (index < 0 || index >= thumbs.subtasks.size()) { return null; } - return thumbs.subtasks.get(index).thumbnail; + TaskAccessInfo.SubTask sub = thumbs.subtasks.get(index); + ActivityRecord resumed = mResumedActivity; + if (resumed != null && resumed.thumbHolder == sub.holder) { + return resumed.stack.screenshotActivities(resumed); + } + return sub.holder.lastThumbnail; } }; } diff --git a/services/java/com/android/server/am/TaskAccessInfo.java b/services/java/com/android/server/am/TaskAccessInfo.java index 5618c1aace684..50aeec1172ca8 100644 --- a/services/java/com/android/server/am/TaskAccessInfo.java +++ b/services/java/com/android/server/am/TaskAccessInfo.java @@ -19,11 +19,10 @@ package com.android.server.am; import java.util.ArrayList; import android.app.ActivityManager.TaskThumbnails; -import android.graphics.Bitmap; final class TaskAccessInfo extends TaskThumbnails { final static class SubTask { - Bitmap thumbnail; + ThumbnailHolder holder; ActivityRecord activity; int index; }