blob: 845a5b05d4d0b0f505e379232c908e81e88b9cbd [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
Craig Mautnerde4ef022013-04-07 19:01:33 -070019import static com.android.server.am.ActivityManagerService.TAG;
Craig Mautner84984fa2014-06-19 11:19:20 -070020import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
21import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
22import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
Craig Mautner0eea92c2013-05-16 13:35:39 -070023import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
Craig Mautnerde4ef022013-04-07 19:01:33 -070024
Craig Mautnerb0f7dc72013-04-01 16:34:45 -070025import android.app.Activity;
Craig Mautner9db9a0b2013-04-29 17:05:56 -070026import android.app.ActivityManager;
Craig Mautnerc0ffce52014-07-01 12:38:52 -070027import android.app.ActivityManager.TaskThumbnail;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -070028import android.app.ActivityOptions;
Dianne Hackborn885fbe52014-08-23 15:23:58 -070029import android.app.AppGlobals;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.content.ComponentName;
31import android.content.Intent;
32import android.content.pm.ActivityInfo;
Dianne Hackborn885fbe52014-08-23 15:23:58 -070033import android.content.pm.ApplicationInfo;
34import android.content.pm.IPackageManager;
35import android.content.pm.PackageManager;
Craig Mautner9db9a0b2013-04-29 17:05:56 -070036import android.graphics.Bitmap;
Craig Mautnerc0ffce52014-07-01 12:38:52 -070037import android.os.ParcelFileDescriptor;
Dianne Hackborn885fbe52014-08-23 15:23:58 -070038import android.os.RemoteException;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070039import android.os.UserHandle;
Dianne Hackborn91097de2014-04-04 18:02:06 -070040import android.service.voice.IVoiceInteractionSession;
Dianne Hackborn7f96b792012-05-29 18:46:45 -070041import android.util.Slog;
Dianne Hackborn91097de2014-04-04 18:02:06 -070042import com.android.internal.app.IVoiceInteractor;
Craig Mautner21d24a22014-04-23 11:45:37 -070043import com.android.internal.util.XmlUtils;
44import org.xmlpull.v1.XmlPullParser;
45import org.xmlpull.v1.XmlPullParserException;
46import org.xmlpull.v1.XmlSerializer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047
Craig Mautnerc0ffce52014-07-01 12:38:52 -070048import java.io.File;
Craig Mautner21d24a22014-04-23 11:45:37 -070049import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import java.io.PrintWriter;
Craig Mautner5d9c7be2013-02-15 14:02:56 -080051import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
Craig Mautnerc0ffce52014-07-01 12:38:52 -070053final class TaskRecord {
Craig Mautner21d24a22014-04-23 11:45:37 -070054 private static final String ATTR_TASKID = "task_id";
55 private static final String TAG_INTENT = "intent";
56 private static final String TAG_AFFINITYINTENT = "affinity_intent";
57 private static final String ATTR_REALACTIVITY = "real_activity";
58 private static final String ATTR_ORIGACTIVITY = "orig_activity";
59 private static final String TAG_ACTIVITY = "activity";
60 private static final String ATTR_AFFINITY = "affinity";
61 private static final String ATTR_ROOTHASRESET = "root_has_reset";
Dianne Hackborn13420f22014-07-18 15:43:56 -070062 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
Craig Mautner21d24a22014-04-23 11:45:37 -070063 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
64 private static final String ATTR_USERID = "user_id";
Dianne Hackborn885fbe52014-08-23 15:23:58 -070065 private static final String ATTR_EFFECTIVE_UID = "effective_uid";
Craig Mautner21d24a22014-04-23 11:45:37 -070066 private static final String ATTR_TASKTYPE = "task_type";
Winson Chungffa2ec62014-07-03 15:54:42 -070067 private static final String ATTR_FIRSTACTIVETIME = "first_active_time";
Winson Chungf1fbd772014-06-24 18:06:58 -070068 private static final String ATTR_LASTACTIVETIME = "last_active_time";
Craig Mautner21d24a22014-04-23 11:45:37 -070069 private static final String ATTR_LASTDESCRIPTION = "last_description";
70 private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
Craig Mautner9d4e9bc2014-06-18 18:34:56 -070071 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
Craig Mautnerc0ffce52014-07-01 12:38:52 -070072 private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label";
73 private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color";
Craig Mautnera228ae92014-07-09 05:44:55 -070074 private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
75 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
76 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
Winson Chungec396d62014-08-06 17:08:00 -070077 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
Craig Mautnerdc00cbe2014-07-20 17:48:47 -070078 private static final String ATTR_CALLING_UID = "calling_uid";
79 private static final String ATTR_CALLING_PACKAGE = "calling_package";
Winson Chung2cb86c72014-06-25 12:03:30 -070080 private static final String LAST_ACTIVITY_ICON_SUFFIX = "_last_activity_icon_";
Craig Mautner21d24a22014-04-23 11:45:37 -070081
82 private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
83
Craig Mautner0b633fc2014-07-23 10:42:18 -070084 static final boolean IGNORE_RETURN_TO_RECENTS = true;
85
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 final int taskId; // Unique identifier for this task.
Craig Mautner9d4e9bc2014-06-18 18:34:56 -070087 String affinity; // The affinity name for this task, or null.
Dianne Hackborn91097de2014-04-04 18:02:06 -070088 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
89 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 Intent intent; // The original intent that started the task.
91 Intent affinityIntent; // Intent of affinity-moved activity that started this task.
Dianne Hackborn885fbe52014-08-23 15:23:58 -070092 int effectiveUid; // The current effective uid of the identity of this task.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 ComponentName origActivity; // The non-alias activity component of the intent.
94 ComponentName realActivity; // The actual activity component that started the task.
Winson Chungffa2ec62014-07-03 15:54:42 -070095 long firstActiveTime; // First time this task was active.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 long lastActiveTime; // Last time this task was active, including sleep.
97 boolean rootWasReset; // True if the intent at the root of the task had
98 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
Dianne Hackborn13420f22014-07-18 15:43:56 -070099 boolean autoRemoveRecents; // If true, we should automatically remove the task from
100 // recents when activity finishes
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700101 boolean askedCompatMode;// Have asked the user about compat mode for this task.
Dianne Hackbornd38aed82014-06-10 21:36:35 -0700102 boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700104 String stringName; // caching of toString() result.
Dianne Hackborn9da2d402012-03-15 13:43:08 -0700105 int userId; // user for which this task was created
Dianne Hackborn09233282014-04-30 11:33:59 -0700106 int creatorUid; // The app uid that originally created the task
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800107
108 int numFullscreen; // Number of fullscreen activities.
109
Winson Chung03a9bae2014-05-02 09:56:12 -0700110 // This represents the last resolved activity values for this task
111 // NOTE: This value needs to be persisted with each task
Winson Chunga449dc02014-05-16 11:15:04 -0700112 ActivityManager.TaskDescription lastTaskDescription =
113 new ActivityManager.TaskDescription();
Winson Chung03a9bae2014-05-02 09:56:12 -0700114
Craig Mautnerd2328952013-03-05 12:46:26 -0800115 /** List of all activities in the task arranged in history order */
Craig Mautner21d24a22014-04-23 11:45:37 -0700116 final ArrayList<ActivityRecord> mActivities;
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800117
Craig Mautnerd2328952013-03-05 12:46:26 -0800118 /** Current stack */
119 ActivityStack stack;
120
Craig Mautner2c1faed2013-07-23 12:56:02 -0700121 /** Takes on same set of values as ActivityRecord.mActivityType */
Craig Mautner21d24a22014-04-23 11:45:37 -0700122 int taskType;
Craig Mautner1602ec22013-05-12 10:24:27 -0700123
Craig Mautner21d24a22014-04-23 11:45:37 -0700124 /** Takes on same value as first root activity */
125 boolean isPersistable = false;
Craig Mautnerffcfcaa2014-06-05 09:54:38 -0700126 int maxRecents;
Craig Mautner21d24a22014-04-23 11:45:37 -0700127
128 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
129 * determining the order when restoring. Sign indicates whether last task movement was to front
130 * (positive) or back (negative). Absolute value indicates time. */
131 long mLastTimeMoved = System.currentTimeMillis();
132
Craig Mautner84984fa2014-06-19 11:19:20 -0700133 /** Indication of what to run next when task exits. Use ActivityRecord types.
134 * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
135 * task stack. */
136 private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
Craig Mautnerae7ecab2013-09-18 11:48:14 -0700137
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700138 /** If original intent did not allow relinquishing task identity, save that information */
139 boolean mNeverRelinquishIdentity = true;
140
Craig Mautner362449a2014-06-20 14:04:39 -0700141 // Used in the unique case where we are clearing the task in order to reuse it. In that case we
142 // do not want to delete the stack when the task goes empty.
143 boolean mReuseTask = false;
144
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700145 private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
146 private final File mLastThumbnailFile; // File containing last thubmnail.
147 private final String mFilename;
148 CharSequence lastDescription; // Last description captured for this item.
149
Craig Mautnera228ae92014-07-09 05:44:55 -0700150 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
Winson Chungec396d62014-08-06 17:08:00 -0700151 int mAffiliatedTaskColor; // color of the parent task affiliation.
Craig Mautnera228ae92014-07-09 05:44:55 -0700152 TaskRecord mPrevAffiliate; // previous task in affiliated chain.
153 int mPrevAffiliateTaskId = -1; // previous id for persistence.
154 TaskRecord mNextAffiliate; // next task in affiliated chain.
155 int mNextAffiliateTaskId = -1; // next id for persistence.
156
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700157 // For relaunching the task from recents as though it was launched by the original launcher.
158 int mCallingUid;
159 String mCallingPackage;
160
Craig Mautner21d24a22014-04-23 11:45:37 -0700161 final ActivityManagerService mService;
162
163 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
Dianne Hackborn91097de2014-04-04 18:02:06 -0700164 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700165 mService = service;
Craig Mautnera228ae92014-07-09 05:44:55 -0700166 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
167 TaskPersister.IMAGE_EXTENSION;
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700168 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 taskId = _taskId;
Craig Mautnera228ae92014-07-09 05:44:55 -0700170 mAffiliatedTaskId = _taskId;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700171 voiceSession = _voiceSession;
172 voiceInteractor = _voiceInteractor;
Craig Mautner21d24a22014-04-23 11:45:37 -0700173 mActivities = new ArrayList<ActivityRecord>();
Martijn Coenend4a69702014-06-30 11:12:17 -0700174 setIntent(_intent, info);
Craig Mautner21d24a22014-04-23 11:45:37 -0700175 }
176
Dianne Hackbornaec68bb2014-08-20 15:25:13 -0700177 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
178 ActivityManager.TaskDescription _taskDescription) {
179 mService = service;
180 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
181 TaskPersister.IMAGE_EXTENSION;
182 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
183 taskId = _taskId;
184 mAffiliatedTaskId = _taskId;
185 voiceSession = null;
186 voiceInteractor = null;
187 mActivities = new ArrayList<ActivityRecord>();
188 setIntent(_intent, info);
189
190 taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
191 isPersistable = true;
192 mCallingUid = info.applicationInfo.uid;
193 mCallingPackage = info.packageName;
194 // Clamp to [1, 100].
195 maxRecents = Math.min(Math.max(info.maxRecents, 1), 100);
196
197 taskType = APPLICATION_ACTIVITY_TYPE;
198 mTaskToReturnTo = HOME_ACTIVITY_TYPE;
199 userId = UserHandle.getUserId(info.applicationInfo.uid);
200 lastTaskDescription = _taskDescription;
201 mCallingUid = info.applicationInfo.uid;
202 mCallingPackage = info.packageName;
203 }
204
Craig Mautner21d24a22014-04-23 11:45:37 -0700205 TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
206 String _affinity, ComponentName _realActivity, ComponentName _origActivity,
Dianne Hackborn13420f22014-07-18 15:43:56 -0700207 boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode,
Dianne Hackborn885fbe52014-08-23 15:23:58 -0700208 int _taskType, int _userId, int _effectiveUid,
Winson Chungffa2ec62014-07-03 15:54:42 -0700209 String _lastDescription, ArrayList<ActivityRecord> activities, long _firstActiveTime,
210 long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity,
Craig Mautnera228ae92014-07-09 05:44:55 -0700211 ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation,
Winson Chungec396d62014-08-06 17:08:00 -0700212 int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid,
213 String callingPackage) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700214 mService = service;
Craig Mautnera228ae92014-07-09 05:44:55 -0700215 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
216 TaskPersister.IMAGE_EXTENSION;
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700217 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
Craig Mautner21d24a22014-04-23 11:45:37 -0700218 taskId = _taskId;
219 intent = _intent;
220 affinityIntent = _affinityIntent;
221 affinity = _affinity;
222 voiceSession = null;
223 voiceInteractor = null;
224 realActivity = _realActivity;
225 origActivity = _origActivity;
226 rootWasReset = _rootWasReset;
Dianne Hackborn13420f22014-07-18 15:43:56 -0700227 autoRemoveRecents = _autoRemoveRecents;
Craig Mautner21d24a22014-04-23 11:45:37 -0700228 askedCompatMode = _askedCompatMode;
229 taskType = _taskType;
Craig Mautner84984fa2014-06-19 11:19:20 -0700230 mTaskToReturnTo = HOME_ACTIVITY_TYPE;
Craig Mautner21d24a22014-04-23 11:45:37 -0700231 userId = _userId;
Dianne Hackborn885fbe52014-08-23 15:23:58 -0700232 effectiveUid = _effectiveUid;
Winson Chungffa2ec62014-07-03 15:54:42 -0700233 firstActiveTime = _firstActiveTime;
Winson Chungf1fbd772014-06-24 18:06:58 -0700234 lastActiveTime = _lastActiveTime;
Craig Mautner21d24a22014-04-23 11:45:37 -0700235 lastDescription = _lastDescription;
236 mActivities = activities;
237 mLastTimeMoved = lastTimeMoved;
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700238 mNeverRelinquishIdentity = neverRelinquishIdentity;
Winson Chung2cb86c72014-06-25 12:03:30 -0700239 lastTaskDescription = _lastTaskDescription;
Craig Mautnera228ae92014-07-09 05:44:55 -0700240 mAffiliatedTaskId = taskAffiliation;
Winson Chungec396d62014-08-06 17:08:00 -0700241 mAffiliatedTaskColor = taskAffiliationColor;
Craig Mautnera228ae92014-07-09 05:44:55 -0700242 mPrevAffiliateTaskId = prevTaskId;
243 mNextAffiliateTaskId = nextTaskId;
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700244 mCallingUid = callingUid;
245 mCallingPackage = callingPackage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 }
247
248 void touchActiveTime() {
Craig Mautner494f6bdd2014-07-21 11:17:46 -0700249 lastActiveTime = System.currentTimeMillis();
Winson Chungffa2ec62014-07-03 15:54:42 -0700250 if (firstActiveTime == 0) {
251 firstActiveTime = lastActiveTime;
252 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 long getInactiveDuration() {
Craig Mautner494f6bdd2014-07-21 11:17:46 -0700256 return System.currentTimeMillis() - lastActiveTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700258
Winson Chungfee26772014-08-05 12:21:52 -0700259 /** Sets the original intent, and the calling uid and package. */
260 void setIntent(ActivityRecord r) {
261 setIntent(r.intent, r.info);
262 mCallingUid = r.launchedFromUid;
263 mCallingPackage = r.launchedFromPackage;
264 }
265
266 /** Sets the original intent, _without_ updating the calling uid or package. */
267 private void setIntent(Intent _intent, ActivityInfo info) {
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700268 if (intent == null) {
269 mNeverRelinquishIdentity =
270 (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
271 } else if (mNeverRelinquishIdentity) {
272 return;
273 }
274
275 affinity = info.taskAffinity;
Dianne Hackborn885fbe52014-08-23 15:23:58 -0700276 effectiveUid = info.applicationInfo.uid;
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700277 stringName = null;
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 if (info.targetActivity == null) {
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800280 if (_intent != null) {
281 // If this Intent has a selector, we want to clear it for the
282 // recent task since it is not relevant if the user later wants
283 // to re-launch the app.
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700284 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800285 _intent = new Intent(_intent);
286 _intent.setSelector(null);
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700287 _intent.setSourceBounds(null);
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800288 }
289 }
Dianne Hackborn7f96b792012-05-29 18:46:45 -0700290 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
291 "Setting Intent of " + this + " to " + _intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 intent = _intent;
293 realActivity = _intent != null ? _intent.getComponent() : null;
294 origActivity = null;
295 } else {
296 ComponentName targetComponent = new ComponentName(
297 info.packageName, info.targetActivity);
298 if (_intent != null) {
299 Intent targetIntent = new Intent(_intent);
300 targetIntent.setComponent(targetComponent);
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800301 targetIntent.setSelector(null);
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700302 targetIntent.setSourceBounds(null);
Dianne Hackborn7f96b792012-05-29 18:46:45 -0700303 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
304 "Setting Intent of " + this + " to target " + targetIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 intent = targetIntent;
306 realActivity = targetComponent;
307 origActivity = _intent.getComponent();
308 } else {
309 intent = null;
310 realActivity = targetComponent;
311 origActivity = new ComponentName(info.packageName, info.name);
312 }
313 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 if (intent != null &&
316 (intent.getFlags()&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
317 // Once we are set to an Intent with this flag, we count this
318 // task as having a true root activity.
319 rootWasReset = true;
320 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700321
Dianne Hackborn09233282014-04-30 11:33:59 -0700322 userId = UserHandle.getUserId(info.applicationInfo.uid);
Craig Mautner41db4a72014-05-07 17:20:56 -0700323 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
Dianne Hackborn13420f22014-07-18 15:43:56 -0700324 // If the activity itself has requested auto-remove, then just always do it.
325 autoRemoveRecents = true;
326 } else if ((intent.getFlags()&(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
327 |Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) {
328 // If the caller has not asked for the document to be retained, then we may
329 // want to turn on auto-remove, depending on whether the target has set its
330 // own document launch mode.
331 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
332 autoRemoveRecents = false;
333 } else {
334 autoRemoveRecents = true;
335 }
336 } else {
337 autoRemoveRecents = false;
Craig Mautner41db4a72014-05-07 17:20:56 -0700338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800340
Craig Mautner84984fa2014-06-19 11:19:20 -0700341 void setTaskToReturnTo(int taskToReturnTo) {
Craig Mautner0b633fc2014-07-23 10:42:18 -0700342 if (IGNORE_RETURN_TO_RECENTS && taskToReturnTo == RECENTS_ACTIVITY_TYPE) {
343 taskToReturnTo = HOME_ACTIVITY_TYPE;
344 }
Craig Mautner84984fa2014-06-19 11:19:20 -0700345 mTaskToReturnTo = taskToReturnTo;
346 }
347
348 int getTaskToReturnTo() {
349 return mTaskToReturnTo;
350 }
351
Craig Mautnera228ae92014-07-09 05:44:55 -0700352 void setPrevAffiliate(TaskRecord prevAffiliate) {
353 mPrevAffiliate = prevAffiliate;
354 mPrevAffiliateTaskId = prevAffiliate == null ? -1 : prevAffiliate.taskId;
355 }
356
357 void setNextAffiliate(TaskRecord nextAffiliate) {
358 mNextAffiliate = nextAffiliate;
359 mNextAffiliateTaskId = nextAffiliate == null ? -1 : nextAffiliate.taskId;
360 }
361
362 // Close up recents linked list.
363 void closeRecentsChain() {
364 if (mPrevAffiliate != null) {
365 mPrevAffiliate.setNextAffiliate(mNextAffiliate);
366 }
367 if (mNextAffiliate != null) {
368 mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
369 }
370 setPrevAffiliate(null);
371 setNextAffiliate(null);
372 }
373
374 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
375 closeRecentsChain();
376 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
Winson Chungec396d62014-08-06 17:08:00 -0700377 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
Craig Mautnera228ae92014-07-09 05:44:55 -0700378 // Find the end
379 while (taskToAffiliateWith.mNextAffiliate != null) {
380 final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
381 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
382 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
383 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
384 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
385 nextRecents.setPrevAffiliate(null);
386 }
387 taskToAffiliateWith.setNextAffiliate(null);
388 break;
389 }
390 taskToAffiliateWith = nextRecents;
391 }
392 taskToAffiliateWith.setNextAffiliate(this);
393 setPrevAffiliate(taskToAffiliateWith);
394 setNextAffiliate(null);
395 }
396
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700397 void setLastThumbnail(Bitmap thumbnail) {
398 mLastThumbnail = thumbnail;
399 if (thumbnail == null) {
400 if (mLastThumbnailFile != null) {
401 mLastThumbnailFile.delete();
402 }
403 } else {
404 mService.mTaskPersister.saveImage(thumbnail, mFilename);
405 }
406 }
407
408 void getLastThumbnail(TaskThumbnail thumbs) {
409 thumbs.mainThumbnail = mLastThumbnail;
410 thumbs.thumbnailFileDescriptor = null;
Craig Mautnerf4f8bb72014-07-29 10:41:40 -0700411 if (mLastThumbnail == null) {
412 thumbs.mainThumbnail = mService.mTaskPersister.getThumbnail(mFilename);
413 }
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700414 if (mLastThumbnailFile.exists()) {
415 try {
416 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
417 ParcelFileDescriptor.MODE_READ_ONLY);
418 } catch (IOException e) {
Dianne Hackborn9844d292013-10-04 16:44:22 -0700419 }
420 }
421 }
422
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700423 void freeLastThumbnail() {
424 mLastThumbnail = null;
425 }
426
427 void disposeThumbnail() {
428 mLastThumbnail = null;
429 lastDescription = null;
430 }
431
Winson Chung1147c402014-05-14 11:05:00 -0700432 /** Returns the intent for the root activity for this task */
433 Intent getBaseIntent() {
434 return intent != null ? intent : affinityIntent;
435 }
436
Winson Chung3b3f4642014-04-22 10:08:18 -0700437 /** Returns the first non-finishing activity from the root. */
438 ActivityRecord getRootActivity() {
439 for (int i = 0; i < mActivities.size(); i++) {
440 final ActivityRecord r = mActivities.get(i);
441 if (r.finishing) {
442 continue;
443 }
444 return r;
445 }
446 return null;
447 }
448
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800449 ActivityRecord getTopActivity() {
450 for (int i = mActivities.size() - 1; i >= 0; --i) {
451 final ActivityRecord r = mActivities.get(i);
452 if (r.finishing) {
453 continue;
454 }
455 return r;
456 }
457 return null;
458 }
459
Craig Mautner6b74cb52013-09-27 17:02:21 -0700460 ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
461 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
462 ActivityRecord r = mActivities.get(activityNdx);
Amith Yamasani734983f2014-03-04 16:48:05 -0800463 if (!r.finishing && r != notTop && stack.okToShowLocked(r)) {
Craig Mautner6b74cb52013-09-27 17:02:21 -0700464 return r;
465 }
466 }
467 return null;
468 }
469
Craig Mautner3b475fe2013-12-16 15:58:31 -0800470 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
471 final void setFrontOfTask() {
472 boolean foundFront = false;
473 final int numActivities = mActivities.size();
Craig Mautner704e40b2013-12-18 16:43:51 -0800474 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
Craig Mautner3b475fe2013-12-16 15:58:31 -0800475 final ActivityRecord r = mActivities.get(activityNdx);
476 if (foundFront || r.finishing) {
477 r.frontOfTask = false;
478 } else {
479 r.frontOfTask = true;
480 // Set frontOfTask false for every following activity.
481 foundFront = true;
482 }
483 }
Craig Mautner9587ee02014-06-23 15:00:10 +0000484 if (!foundFront && numActivities > 0) {
485 // All activities of this task are finishing. As we ought to have a frontOfTask
486 // activity, make the bottom activity front.
487 mActivities.get(0).frontOfTask = true;
488 }
Craig Mautner3b475fe2013-12-16 15:58:31 -0800489 }
490
Craig Mautnerde4ef022013-04-07 19:01:33 -0700491 /**
Craig Mautner3b475fe2013-12-16 15:58:31 -0800492 * Reorder the history stack so that the passed activity is brought to the front.
Craig Mautnerde4ef022013-04-07 19:01:33 -0700493 */
494 final void moveActivityToFrontLocked(ActivityRecord newTop) {
495 if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop
496 + " to stack at top", new RuntimeException("here").fillInStackTrace());
497
Craig Mautnerde4ef022013-04-07 19:01:33 -0700498 mActivities.remove(newTop);
499 mActivities.add(newTop);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700500 updateEffectiveIntent();
Craig Mautner3b475fe2013-12-16 15:58:31 -0800501
502 setFrontOfTask();
Craig Mautnerde4ef022013-04-07 19:01:33 -0700503 }
504
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800505 void addActivityAtBottom(ActivityRecord r) {
Craig Mautner77878772013-03-04 19:46:24 -0800506 addActivityAtIndex(0, r);
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800507 }
508
509 void addActivityToTop(ActivityRecord r) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700510 addActivityAtIndex(mActivities.size(), r);
511 }
512
513 void addActivityAtIndex(int index, ActivityRecord r) {
Craig Mautner6170f732013-04-02 13:05:23 -0700514 // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800515 if (!mActivities.remove(r) && r.fullscreen) {
516 // Was not previously in list.
517 numFullscreen++;
518 }
Craig Mautner2c1faed2013-07-23 12:56:02 -0700519 // Only set this based on the first activity
520 if (mActivities.isEmpty()) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700521 taskType = r.mActivityType;
522 isPersistable = r.isPersistable();
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700523 mCallingUid = r.launchedFromUid;
524 mCallingPackage = r.launchedFromPackage;
Craig Mautnerffcfcaa2014-06-05 09:54:38 -0700525 // Clamp to [1, 100].
526 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 100);
Craig Mautner2c1faed2013-07-23 12:56:02 -0700527 } else {
528 // Otherwise make all added activities match this one.
Craig Mautner21d24a22014-04-23 11:45:37 -0700529 r.mActivityType = taskType;
Craig Mautner78733002013-06-10 13:54:49 -0700530 }
Craig Mautner77878772013-03-04 19:46:24 -0800531 mActivities.add(index, r);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700532 updateEffectiveIntent();
Craig Mautner21d24a22014-04-23 11:45:37 -0700533 if (r.isPersistable()) {
534 mService.notifyTaskPersisterLocked(this, false);
535 }
Craig Mautner77878772013-03-04 19:46:24 -0800536 }
537
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800538 /** @return true if this was the last activity in the task */
539 boolean removeActivity(ActivityRecord r) {
540 if (mActivities.remove(r) && r.fullscreen) {
541 // Was previously in list.
542 numFullscreen--;
543 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700544 if (r.isPersistable()) {
545 mService.notifyTaskPersisterLocked(this, false);
546 }
Craig Mautner41326202014-06-20 14:38:21 -0700547 if (mActivities.isEmpty()) {
Craig Mautner5afcd4d2014-06-21 18:11:33 -0700548 return !mReuseTask;
Craig Mautner41326202014-06-20 14:38:21 -0700549 }
550 updateEffectiveIntent();
551 return false;
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800552 }
553
Craig Mautner41db4a72014-05-07 17:20:56 -0700554 boolean autoRemoveFromRecents() {
Dianne Hackbornd38aed82014-06-10 21:36:35 -0700555 // We will automatically remove the task either if it has explicitly asked for
556 // this, or it is empty and has never contained an activity that got shown to
557 // the user.
Dianne Hackborn13420f22014-07-18 15:43:56 -0700558 return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible);
Craig Mautner41db4a72014-05-07 17:20:56 -0700559 }
560
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700561 /**
562 * Completely remove all activities associated with an existing
563 * task starting at a specified index.
564 */
565 final void performClearTaskAtIndexLocked(int activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700566 int numActivities = mActivities.size();
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700567 for ( ; activityNdx < numActivities; ++activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700568 final ActivityRecord r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700569 if (r.finishing) {
570 continue;
571 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700572 if (stack == null) {
573 // Task was restored from persistent storage.
574 r.takeFromHistory();
575 mActivities.remove(activityNdx);
576 --activityNdx;
577 --numActivities;
578 } else if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
579 false)) {
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700580 --activityNdx;
581 --numActivities;
582 }
583 }
584 }
585
586 /**
587 * Completely remove all activities associated with an existing task.
588 */
589 final void performClearTaskLocked() {
Craig Mautner362449a2014-06-20 14:04:39 -0700590 mReuseTask = true;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700591 performClearTaskAtIndexLocked(0);
Craig Mautner362449a2014-06-20 14:04:39 -0700592 mReuseTask = false;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700593 }
594
595 /**
596 * Perform clear operation as requested by
597 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
598 * stack to the given task, then look for
599 * an instance of that activity in the stack and, if found, finish all
600 * activities on top of it and return the instance.
601 *
602 * @param newR Description of the new activity being started.
603 * @return Returns the old activity that should be continued to be used,
604 * or null if none was found.
605 */
606 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700607 int numActivities = mActivities.size();
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700608 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700609 ActivityRecord r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700610 if (r.finishing) {
611 continue;
612 }
613 if (r.realActivity.equals(newR.realActivity)) {
614 // Here it is! Now finish everything in front...
Craig Mautner1602ec22013-05-12 10:24:27 -0700615 final ActivityRecord ret = r;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700616
617 for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700618 r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700619 if (r.finishing) {
620 continue;
621 }
622 ActivityOptions opts = r.takeOptionsLocked();
623 if (opts != null) {
624 ret.updateOptionsLocked(opts);
625 }
626 if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
627 false)) {
628 --activityNdx;
629 --numActivities;
630 }
631 }
632
633 // Finally, if this is a normal launch mode (that is, not
634 // expecting onNewIntent()), then we will finish the current
635 // instance of the activity so a new fresh one can be started.
636 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
637 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
638 if (!ret.finishing) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700639 stack.finishActivityLocked(ret, Activity.RESULT_CANCELED, null,
640 "clear", false);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700641 return null;
642 }
643 }
644
645 return ret;
646 }
647 }
648
649 return null;
650 }
651
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700652 public TaskThumbnail getTaskThumbnailLocked() {
Craig Mautner21d24a22014-04-23 11:45:37 -0700653 if (stack != null) {
654 final ActivityRecord resumedActivity = stack.mResumedActivity;
655 if (resumedActivity != null && resumedActivity.task == this) {
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700656 final Bitmap thumbnail = stack.screenshotActivities(resumedActivity);
657 setLastThumbnail(thumbnail);
Craig Mautner21d24a22014-04-23 11:45:37 -0700658 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700659 }
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700660 final TaskThumbnail taskThumbnail = new TaskThumbnail();
661 getLastThumbnail(taskThumbnail);
662 return taskThumbnail;
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700663 }
664
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700665 public void removeTaskActivitiesLocked() {
666 // Just remove the entire task.
667 performClearTaskAtIndexLocked(0);
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700668 }
669
Craig Mautnera82aa092013-09-13 15:34:08 -0700670 boolean isHomeTask() {
Craig Mautner84984fa2014-06-19 11:19:20 -0700671 return taskType == HOME_ACTIVITY_TYPE;
Craig Mautnera82aa092013-09-13 15:34:08 -0700672 }
673
Craig Mautner86d67a42013-05-14 10:34:38 -0700674 boolean isApplicationTask() {
Craig Mautner84984fa2014-06-19 11:19:20 -0700675 return taskType == APPLICATION_ACTIVITY_TYPE;
676 }
677
678 boolean isOverHomeStack() {
679 return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
Craig Mautner1602ec22013-05-12 10:24:27 -0700680 }
681
Craig Mautner525f3d92013-05-07 14:01:50 -0700682 /**
683 * Find the activity in the history stack within the given task. Returns
684 * the index within the history at which it's found, or < 0 if not found.
685 */
686 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
687 final ComponentName realActivity = r.realActivity;
688 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
689 ActivityRecord candidate = mActivities.get(activityNdx);
690 if (candidate.finishing) {
691 continue;
692 }
693 if (candidate.realActivity.equals(realActivity)) {
694 return candidate;
695 }
696 }
697 return null;
698 }
699
Winson Chunga449dc02014-05-16 11:15:04 -0700700 /** Updates the last task description values. */
701 void updateTaskDescription() {
702 // Traverse upwards looking for any break between main task activities and
703 // utility activities.
704 int activityNdx;
705 final int numActivities = mActivities.size();
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700706 final boolean relinquish = numActivities == 0 ? false :
707 (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0;
Winson Chunga449dc02014-05-16 11:15:04 -0700708 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
Craig Mautner21d24a22014-04-23 11:45:37 -0700709 ++activityNdx) {
Winson Chunga449dc02014-05-16 11:15:04 -0700710 final ActivityRecord r = mActivities.get(activityNdx);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700711 if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
712 // This will be the top activity for determining taskDescription. Pre-inc to
713 // overcome initial decrement below.
714 ++activityNdx;
715 break;
716 }
Winson Chunga449dc02014-05-16 11:15:04 -0700717 if (r.intent != null &&
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700718 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
Winson Chunga449dc02014-05-16 11:15:04 -0700719 break;
720 }
721 }
722 if (activityNdx > 0) {
723 // Traverse downwards starting below break looking for set label, icon.
724 // Note that if there are activities in the task but none of them set the
725 // recent activity values, then we do not fall back to the last set
726 // values in the TaskRecord.
727 String label = null;
728 Bitmap icon = null;
729 int colorPrimary = 0;
730 for (--activityNdx; activityNdx >= 0; --activityNdx) {
731 final ActivityRecord r = mActivities.get(activityNdx);
732 if (r.taskDescription != null) {
733 if (label == null) {
734 label = r.taskDescription.getLabel();
735 }
736 if (icon == null) {
737 icon = r.taskDescription.getIcon();
738 }
739 if (colorPrimary == 0) {
740 colorPrimary = r.taskDescription.getPrimaryColor();
Winson Chunga449dc02014-05-16 11:15:04 -0700741 }
742 }
743 }
744 lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary);
Winson Chungec396d62014-08-06 17:08:00 -0700745 // Update the task affiliation color if we are the parent of the group
746 if (taskId == mAffiliatedTaskId) {
747 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
748 }
Winson Chunga449dc02014-05-16 11:15:04 -0700749 }
750 }
751
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700752 int findEffectiveRootIndex() {
753 int activityNdx;
754 final int topActivityNdx = mActivities.size() - 1;
755 for (activityNdx = 0; activityNdx < topActivityNdx; ++activityNdx) {
756 final ActivityRecord r = mActivities.get(activityNdx);
757 if (r.finishing) {
758 continue;
759 }
760 if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
761 break;
762 }
763 }
764 return activityNdx;
765 }
766
767 void updateEffectiveIntent() {
768 final int effectiveRootIndex = findEffectiveRootIndex();
769 final ActivityRecord r = mActivities.get(effectiveRootIndex);
Winson Chungfee26772014-08-05 12:21:52 -0700770 setIntent(r);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700771 }
772
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700773 void saveTaskDescription(ActivityManager.TaskDescription taskDescription,
774 String iconFilename, XmlSerializer out) throws IOException {
775 if (taskDescription != null) {
776 final String label = taskDescription.getLabel();
777 if (label != null) {
778 out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label);
779 }
780 final int colorPrimary = taskDescription.getPrimaryColor();
781 if (colorPrimary != 0) {
782 out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary));
783 }
784 final Bitmap icon = taskDescription.getIcon();
785 if (icon != null) {
786 mService.mTaskPersister.saveImage(icon, iconFilename);
787 }
788 }
789 }
790
791 static boolean readTaskDescriptionAttribute(ActivityManager.TaskDescription taskDescription,
792 String attrName, String attrValue) {
793 if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
794 taskDescription.setLabel(attrValue);
795 } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
796 taskDescription.setPrimaryColor((int) Long.parseLong(attrValue, 16));
797 } else {
798 return false;
799 }
800 return true;
801 }
802
Winson Chung3bad5cc02014-08-19 17:44:32 -0700803 private static String createLastTaskDescriptionIconFilename(int taskId, long lastActiveTime) {
804 return String.valueOf(taskId) + LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime +
805 TaskPersister.IMAGE_EXTENSION;
806 }
807
Craig Mautner21d24a22014-04-23 11:45:37 -0700808 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
Dianne Hackbornaec68bb2014-08-20 15:25:13 -0700809 if (ActivityManagerService.DEBUG_RECENTS) Slog.i(TAG, "Saving task=" + this);
Craig Mautner21d24a22014-04-23 11:45:37 -0700810
811 out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
812 if (realActivity != null) {
813 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
814 }
815 if (origActivity != null) {
816 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
817 }
818 if (affinity != null) {
819 out.attribute(null, ATTR_AFFINITY, affinity);
820 }
821 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
Dianne Hackborn13420f22014-07-18 15:43:56 -0700822 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
Craig Mautner21d24a22014-04-23 11:45:37 -0700823 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
824 out.attribute(null, ATTR_USERID, String.valueOf(userId));
Dianne Hackborn885fbe52014-08-23 15:23:58 -0700825 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
Craig Mautner21d24a22014-04-23 11:45:37 -0700826 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
Winson Chungffa2ec62014-07-03 15:54:42 -0700827 out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
Winson Chungf1fbd772014-06-24 18:06:58 -0700828 out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime));
Craig Mautner21d24a22014-04-23 11:45:37 -0700829 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700830 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
Craig Mautner21d24a22014-04-23 11:45:37 -0700831 if (lastDescription != null) {
832 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
833 }
Winson Chung2cb86c72014-06-25 12:03:30 -0700834 if (lastTaskDescription != null) {
Winson Chung3bad5cc02014-08-19 17:44:32 -0700835 saveTaskDescription(lastTaskDescription, createLastTaskDescriptionIconFilename(taskId,
836 lastActiveTime), out);
Winson Chung2cb86c72014-06-25 12:03:30 -0700837 }
Winson Chungec396d62014-08-06 17:08:00 -0700838 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
Craig Mautnera228ae92014-07-09 05:44:55 -0700839 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
840 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
841 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700842 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
843 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
Winson Chung2cb86c72014-06-25 12:03:30 -0700844
Craig Mautner21d24a22014-04-23 11:45:37 -0700845 if (affinityIntent != null) {
846 out.startTag(null, TAG_AFFINITYINTENT);
847 affinityIntent.saveToXml(out);
848 out.endTag(null, TAG_AFFINITYINTENT);
849 }
850
851 out.startTag(null, TAG_INTENT);
852 intent.saveToXml(out);
853 out.endTag(null, TAG_INTENT);
854
855 final ArrayList<ActivityRecord> activities = mActivities;
856 final int numActivities = activities.size();
857 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
858 final ActivityRecord r = activities.get(activityNdx);
Craig Mautner43e52ed2014-06-16 17:18:52 -0700859 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
860 ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) &&
861 activityNdx > 0) {
Craig Mautnerf357c0c2014-06-09 09:23:27 -0700862 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
Craig Mautner21d24a22014-04-23 11:45:37 -0700863 break;
864 }
865 out.startTag(null, TAG_ACTIVITY);
866 r.saveToXml(out);
867 out.endTag(null, TAG_ACTIVITY);
868 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700869 }
870
871 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
872 throws IOException, XmlPullParserException {
873 Intent intent = null;
874 Intent affinityIntent = null;
875 ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
876 ComponentName realActivity = null;
877 ComponentName origActivity = null;
878 String affinity = null;
879 boolean rootHasReset = false;
Dianne Hackborn13420f22014-07-18 15:43:56 -0700880 boolean autoRemoveRecents = false;
Craig Mautner21d24a22014-04-23 11:45:37 -0700881 boolean askedCompatMode = false;
882 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
Craig Mautner21d24a22014-04-23 11:45:37 -0700883 int userId = 0;
Dianne Hackborn885fbe52014-08-23 15:23:58 -0700884 int effectiveUid = -1;
Craig Mautner21d24a22014-04-23 11:45:37 -0700885 String lastDescription = null;
Winson Chungffa2ec62014-07-03 15:54:42 -0700886 long firstActiveTime = -1;
Winson Chung2cb86c72014-06-25 12:03:30 -0700887 long lastActiveTime = -1;
Craig Mautner21d24a22014-04-23 11:45:37 -0700888 long lastTimeOnTop = 0;
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700889 boolean neverRelinquishIdentity = true;
Craig Mautner21d24a22014-04-23 11:45:37 -0700890 int taskId = -1;
891 final int outerDepth = in.getDepth();
Winson Chung2cb86c72014-06-25 12:03:30 -0700892 ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription();
Craig Mautnera228ae92014-07-09 05:44:55 -0700893 int taskAffiliation = -1;
Winson Chungec396d62014-08-06 17:08:00 -0700894 int taskAffiliationColor = 0;
Craig Mautnera228ae92014-07-09 05:44:55 -0700895 int prevTaskId = -1;
896 int nextTaskId = -1;
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700897 int callingUid = -1;
898 String callingPackage = "";
Craig Mautner21d24a22014-04-23 11:45:37 -0700899
900 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
901 final String attrName = in.getAttributeName(attrNdx);
902 final String attrValue = in.getAttributeValue(attrNdx);
903 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
904 attrName + " value=" + attrValue);
905 if (ATTR_TASKID.equals(attrName)) {
906 taskId = Integer.valueOf(attrValue);
907 } else if (ATTR_REALACTIVITY.equals(attrName)) {
908 realActivity = ComponentName.unflattenFromString(attrValue);
909 } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
910 origActivity = ComponentName.unflattenFromString(attrValue);
911 } else if (ATTR_AFFINITY.equals(attrName)) {
912 affinity = attrValue;
913 } else if (ATTR_ROOTHASRESET.equals(attrName)) {
914 rootHasReset = Boolean.valueOf(attrValue);
Dianne Hackborn13420f22014-07-18 15:43:56 -0700915 } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) {
916 autoRemoveRecents = Boolean.valueOf(attrValue);
Craig Mautner21d24a22014-04-23 11:45:37 -0700917 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
918 askedCompatMode = Boolean.valueOf(attrValue);
919 } else if (ATTR_USERID.equals(attrName)) {
920 userId = Integer.valueOf(attrValue);
Dianne Hackborn885fbe52014-08-23 15:23:58 -0700921 } else if (ATTR_EFFECTIVE_UID.equals(attrName)) {
922 effectiveUid = Integer.valueOf(attrValue);
Craig Mautner21d24a22014-04-23 11:45:37 -0700923 } else if (ATTR_TASKTYPE.equals(attrName)) {
924 taskType = Integer.valueOf(attrValue);
Winson Chungffa2ec62014-07-03 15:54:42 -0700925 } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) {
926 firstActiveTime = Long.valueOf(attrValue);
Winson Chungf1fbd772014-06-24 18:06:58 -0700927 } else if (ATTR_LASTACTIVETIME.equals(attrName)) {
928 lastActiveTime = Long.valueOf(attrValue);
Craig Mautner21d24a22014-04-23 11:45:37 -0700929 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
930 lastDescription = attrValue;
931 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
932 lastTimeOnTop = Long.valueOf(attrValue);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700933 } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
934 neverRelinquishIdentity = Boolean.valueOf(attrValue);
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700935 } else if (readTaskDescriptionAttribute(taskDescription, attrName, attrValue)) {
Winson Chung2cb86c72014-06-25 12:03:30 -0700936 // Completed in TaskPersister.readTaskDescriptionAttribute()
Craig Mautnera228ae92014-07-09 05:44:55 -0700937 } else if (ATTR_TASK_AFFILIATION.equals(attrName)) {
938 taskAffiliation = Integer.valueOf(attrValue);
939 } else if (ATTR_PREV_AFFILIATION.equals(attrName)) {
940 prevTaskId = Integer.valueOf(attrValue);
941 } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) {
942 nextTaskId = Integer.valueOf(attrValue);
Winson Chungec396d62014-08-06 17:08:00 -0700943 } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) {
944 taskAffiliationColor = Integer.valueOf(attrValue);
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700945 } else if (ATTR_CALLING_UID.equals(attrName)) {
946 callingUid = Integer.valueOf(attrValue);
947 } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
948 callingPackage = attrValue;
Craig Mautner21d24a22014-04-23 11:45:37 -0700949 } else {
950 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
951 }
952 }
953
954 int event;
955 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
956 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
957 if (event == XmlPullParser.START_TAG) {
958 final String name = in.getName();
959 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
960 name);
961 if (TAG_AFFINITYINTENT.equals(name)) {
962 affinityIntent = Intent.restoreFromXml(in);
963 } else if (TAG_INTENT.equals(name)) {
964 intent = Intent.restoreFromXml(in);
965 } else if (TAG_ACTIVITY.equals(name)) {
966 ActivityRecord activity =
967 ActivityRecord.restoreFromXml(in, taskId, stackSupervisor);
968 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
969 activity);
970 if (activity != null) {
971 activities.add(activity);
972 }
973 } else {
974 Slog.e(TAG, "restoreTask: Unexpected name=" + name);
975 XmlUtils.skipCurrentTag(in);
976 }
977 }
978 }
979
Winson Chung2cb86c72014-06-25 12:03:30 -0700980 if (lastActiveTime >= 0) {
Winson Chung3bad5cc02014-08-19 17:44:32 -0700981 taskDescription.setIcon(TaskPersister.restoreImage(
982 createLastTaskDescriptionIconFilename(taskId, lastActiveTime)));
Winson Chung2cb86c72014-06-25 12:03:30 -0700983 }
984
Dianne Hackborn885fbe52014-08-23 15:23:58 -0700985 if (effectiveUid <= 0) {
986 Intent checkIntent = intent != null ? intent : affinityIntent;
987 effectiveUid = 0;
988 if (checkIntent != null) {
989 IPackageManager pm = AppGlobals.getPackageManager();
990 try {
991 ApplicationInfo ai = pm.getApplicationInfo(
992 checkIntent.getComponent().getPackageName(),
993 PackageManager.GET_UNINSTALLED_PACKAGES
994 | PackageManager.GET_DISABLED_COMPONENTS, userId);
995 if (ai != null) {
996 effectiveUid = ai.uid;
997 }
998 } catch (RemoteException e) {
999 }
1000 }
1001 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
1002 + ": effectiveUid=" + effectiveUid);
1003 }
1004
Craig Mautner21d24a22014-04-23 11:45:37 -07001005 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
1006 affinityIntent, affinity, realActivity, origActivity, rootHasReset,
Dianne Hackborn885fbe52014-08-23 15:23:58 -07001007 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
1008 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
Winson Chungec396d62014-08-06 17:08:00 -07001009 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
1010 callingUid, callingPackage);
Craig Mautner21d24a22014-04-23 11:45:37 -07001011
1012 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
Craig Mautnerc0ffce52014-07-01 12:38:52 -07001013 activities.get(activityNdx).task = task;
Craig Mautner21d24a22014-04-23 11:45:37 -07001014 }
1015
Dianne Hackbornaec68bb2014-08-20 15:25:13 -07001016 if (ActivityManagerService.DEBUG_RECENTS) Slog.d(TAG, "Restored task=" + task);
Craig Mautner21d24a22014-04-23 11:45:37 -07001017 return task;
1018 }
1019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 void dump(PrintWriter pw, String prefix) {
Dianne Hackbornaec68bb2014-08-20 15:25:13 -07001021 pw.print(prefix); pw.print("userId="); pw.print(userId);
Dianne Hackborn885fbe52014-08-23 15:23:58 -07001022 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
1023 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
Dianne Hackbornaec68bb2014-08-20 15:25:13 -07001024 pw.print(" mCallingPackage="); pw.println(mCallingPackage);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001025 if (affinity != null) {
1026 pw.print(prefix); pw.print("affinity="); pw.println(affinity);
1027 }
Dianne Hackborn91097de2014-04-04 18:02:06 -07001028 if (voiceSession != null || voiceInteractor != null) {
1029 pw.print(prefix); pw.print("VOICE: session=0x");
1030 pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
1031 pw.print(" interactor=0x");
1032 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
1033 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001034 if (intent != null) {
1035 StringBuilder sb = new StringBuilder(128);
1036 sb.append(prefix); sb.append("intent={");
Dianne Hackborn21c241e2012-03-08 13:57:23 -08001037 intent.toShortString(sb, false, true, false, true);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001038 sb.append('}');
1039 pw.println(sb.toString());
1040 }
1041 if (affinityIntent != null) {
1042 StringBuilder sb = new StringBuilder(128);
1043 sb.append(prefix); sb.append("affinityIntent={");
Dianne Hackborn21c241e2012-03-08 13:57:23 -08001044 affinityIntent.toShortString(sb, false, true, false, true);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001045 sb.append('}');
1046 pw.println(sb.toString());
1047 }
1048 if (origActivity != null) {
1049 pw.print(prefix); pw.print("origActivity=");
1050 pw.println(origActivity.flattenToShortString());
1051 }
1052 if (realActivity != null) {
1053 pw.print(prefix); pw.print("realActivity=");
1054 pw.println(realActivity.flattenToShortString());
1055 }
Dianne Hackbornaec68bb2014-08-20 15:25:13 -07001056 if (autoRemoveRecents || taskType != 0 || mTaskToReturnTo != 0 || numFullscreen != 0) {
1057 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
1058 pw.print(" numFullscreen="); pw.print(numFullscreen);
1059 pw.print(" taskType="); pw.print(taskType);
1060 pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
1061 }
1062 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask) {
1063 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
1064 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
1065 pw.print(" mReuseTask="); pw.println(mReuseTask);
1066 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -08001067 pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
Dianne Hackborn36cd41f2011-05-25 21:00:46 -07001068 if (!askedCompatMode) {
1069 pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
1070 }
Craig Mautnerc0ffce52014-07-01 12:38:52 -07001071 pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail);
1072 pw.print(" lastThumbnailFile="); pw.print(mLastThumbnailFile);
Dianne Hackborncfb9f2b2011-08-24 10:51:49 -07001073 pw.print(" lastDescription="); pw.println(lastDescription);
Dianne Hackbornd38aed82014-06-10 21:36:35 -07001074 pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
Winson Chungffa2ec62014-07-03 15:54:42 -07001075 pw.print(" firstActiveTime="); pw.print(lastActiveTime);
Dianne Hackbornd38aed82014-06-10 21:36:35 -07001076 pw.print(" lastActiveTime="); pw.print(lastActiveTime);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001077 pw.print(" (inactive for ");
1078 pw.print((getInactiveDuration()/1000)); pw.println("s)");
Craig Mautnera228ae92014-07-09 05:44:55 -07001079 pw.print(prefix); pw.print("isPersistable="); pw.print(isPersistable);
1080 pw.print(" affiliation="); pw.print(mAffiliatedTaskId);
1081 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
1082 pw.print(" nextAffiliation="); pw.println(mNextAffiliateTaskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
1084
Craig Mautner5d9c7be2013-02-15 14:02:56 -08001085 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001087 StringBuilder sb = new StringBuilder(128);
Craig Mautnerde4ef022013-04-07 19:01:33 -07001088 if (stringName != null) {
1089 sb.append(stringName);
1090 sb.append(" U=");
1091 sb.append(userId);
1092 sb.append(" sz=");
1093 sb.append(mActivities.size());
1094 sb.append('}');
1095 return sb.toString();
1096 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001097 sb.append("TaskRecord{");
1098 sb.append(Integer.toHexString(System.identityHashCode(this)));
1099 sb.append(" #");
1100 sb.append(taskId);
1101 if (affinity != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -08001102 sb.append(" A=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001103 sb.append(affinity);
1104 } else if (intent != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -08001105 sb.append(" I=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001106 sb.append(intent.getComponent().flattenToShortString());
1107 } else if (affinityIntent != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -08001108 sb.append(" aI=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001109 sb.append(affinityIntent.getComponent().flattenToShortString());
1110 } else {
1111 sb.append(" ??");
1112 }
Craig Mautnerde4ef022013-04-07 19:01:33 -07001113 stringName = sb.toString();
1114 return toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 }
1116}