summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCraig Mautner <cmautner@google.com>2014-07-01 12:38:52 -0700
committerCraig Mautner <cmautner@google.com>2014-07-02 16:31:46 -0700
commitc0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1d (patch)
treed35f14610cdd43912a963295aa6719ae596a1669
parent51cb97096814352127aed69e5ac97013e9172038 (diff)
downloadframeworks_base-c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1d.zip
frameworks_base-c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1d.tar.gz
frameworks_base-c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1d.tar.bz2
Use cached thumbnails in Recent tasks.
The thumbnail returned from ActivityManager.getTaskThumbnail() now contains either a Bitmap or a ParcelFileDescriptor that points to a file containing a compressed Bitmap. The Recent tasks list is now responsible for all thumbnail Bitmap caching as the activity manager keeps only the most recent 5. This also permits low memory devices to have many more tasks in the Recent tasks list. As part of this CL the concept of subtasks is removed eliminating code supporting the TaskAccessInfo and IThumbnailRetriever classes. Fixes bug 15828934. Change-Id: I0fd0320a1a04e3c78d79357899b83a2fff97abf2
-rw-r--r--Android.mk1
-rw-r--r--CleanSpec.mk1
-rw-r--r--core/java/android/app/ActivityManager.java85
-rw-r--r--core/java/android/app/ActivityManagerNative.java72
-rw-r--r--core/java/android/app/IActivityManager.java11
-rw-r--r--core/java/android/app/IThumbnailRetriever.aidl25
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Utilities.java22
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java47
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityRecord.java54
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityStack.java14
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java11
-rw-r--r--services/core/java/com/android/server/am/TaskAccessInfo.java34
-rw-r--r--services/core/java/com/android/server/am/TaskPersister.java100
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java224
-rw-r--r--services/core/java/com/android/server/am/ThumbnailHolder.java29
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java18
18 files changed, 245 insertions, 508 deletions
diff --git a/Android.mk b/Android.mk
index a6271d2..5ffafc0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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));