blob: d0ec106d4ddf85641dd93f1b9771d4ebcb815920 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.content.ComponentName;
30import android.content.Intent;
31import android.content.pm.ActivityInfo;
Craig Mautner9db9a0b2013-04-29 17:05:56 -070032import android.graphics.Bitmap;
Craig Mautnerc0ffce52014-07-01 12:38:52 -070033import android.os.ParcelFileDescriptor;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070034import android.os.UserHandle;
Dianne Hackborn91097de2014-04-04 18:02:06 -070035import android.service.voice.IVoiceInteractionSession;
Dianne Hackborn7f96b792012-05-29 18:46:45 -070036import android.util.Slog;
Dianne Hackborn91097de2014-04-04 18:02:06 -070037import com.android.internal.app.IVoiceInteractor;
Craig Mautner21d24a22014-04-23 11:45:37 -070038import com.android.internal.util.XmlUtils;
39import org.xmlpull.v1.XmlPullParser;
40import org.xmlpull.v1.XmlPullParserException;
41import org.xmlpull.v1.XmlSerializer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
Craig Mautnerc0ffce52014-07-01 12:38:52 -070043import java.io.File;
Craig Mautner21d24a22014-04-23 11:45:37 -070044import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import java.io.PrintWriter;
Craig Mautner5d9c7be2013-02-15 14:02:56 -080046import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047
Craig Mautnerc0ffce52014-07-01 12:38:52 -070048final class TaskRecord {
Craig Mautner21d24a22014-04-23 11:45:37 -070049 private static final String ATTR_TASKID = "task_id";
50 private static final String TAG_INTENT = "intent";
51 private static final String TAG_AFFINITYINTENT = "affinity_intent";
52 private static final String ATTR_REALACTIVITY = "real_activity";
53 private static final String ATTR_ORIGACTIVITY = "orig_activity";
54 private static final String TAG_ACTIVITY = "activity";
55 private static final String ATTR_AFFINITY = "affinity";
56 private static final String ATTR_ROOTHASRESET = "root_has_reset";
Dianne Hackborn13420f22014-07-18 15:43:56 -070057 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
Craig Mautner21d24a22014-04-23 11:45:37 -070058 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
59 private static final String ATTR_USERID = "user_id";
60 private static final String ATTR_TASKTYPE = "task_type";
Winson Chungffa2ec62014-07-03 15:54:42 -070061 private static final String ATTR_FIRSTACTIVETIME = "first_active_time";
Winson Chungf1fbd772014-06-24 18:06:58 -070062 private static final String ATTR_LASTACTIVETIME = "last_active_time";
Craig Mautner21d24a22014-04-23 11:45:37 -070063 private static final String ATTR_LASTDESCRIPTION = "last_description";
64 private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
Craig Mautner9d4e9bc2014-06-18 18:34:56 -070065 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
Craig Mautnerc0ffce52014-07-01 12:38:52 -070066 private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label";
67 private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color";
Craig Mautnera228ae92014-07-09 05:44:55 -070068 private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
69 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
70 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
Winson Chungec396d62014-08-06 17:08:00 -070071 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
Craig Mautnerdc00cbe2014-07-20 17:48:47 -070072 private static final String ATTR_CALLING_UID = "calling_uid";
73 private static final String ATTR_CALLING_PACKAGE = "calling_package";
Winson Chung2cb86c72014-06-25 12:03:30 -070074 private static final String LAST_ACTIVITY_ICON_SUFFIX = "_last_activity_icon_";
Craig Mautner21d24a22014-04-23 11:45:37 -070075
76 private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
77
Craig Mautner0b633fc2014-07-23 10:42:18 -070078 static final boolean IGNORE_RETURN_TO_RECENTS = true;
79
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 final int taskId; // Unique identifier for this task.
Craig Mautner9d4e9bc2014-06-18 18:34:56 -070081 String affinity; // The affinity name for this task, or null.
Dianne Hackborn91097de2014-04-04 18:02:06 -070082 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
83 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 Intent intent; // The original intent that started the task.
85 Intent affinityIntent; // Intent of affinity-moved activity that started this task.
86 ComponentName origActivity; // The non-alias activity component of the intent.
87 ComponentName realActivity; // The actual activity component that started the task.
Winson Chungffa2ec62014-07-03 15:54:42 -070088 long firstActiveTime; // First time this task was active.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 long lastActiveTime; // Last time this task was active, including sleep.
90 boolean rootWasReset; // True if the intent at the root of the task had
91 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
Dianne Hackborn13420f22014-07-18 15:43:56 -070092 boolean autoRemoveRecents; // If true, we should automatically remove the task from
93 // recents when activity finishes
Dianne Hackborn36cd41f2011-05-25 21:00:46 -070094 boolean askedCompatMode;// Have asked the user about compat mode for this task.
Dianne Hackbornd38aed82014-06-10 21:36:35 -070095 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 -080096
Dianne Hackborn1d442e02009-04-20 18:14:05 -070097 String stringName; // caching of toString() result.
Dianne Hackborn9da2d402012-03-15 13:43:08 -070098 int userId; // user for which this task was created
Dianne Hackborn09233282014-04-30 11:33:59 -070099 int creatorUid; // The app uid that originally created the task
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800100
101 int numFullscreen; // Number of fullscreen activities.
102
Winson Chung03a9bae2014-05-02 09:56:12 -0700103 // This represents the last resolved activity values for this task
104 // NOTE: This value needs to be persisted with each task
Winson Chunga449dc02014-05-16 11:15:04 -0700105 ActivityManager.TaskDescription lastTaskDescription =
106 new ActivityManager.TaskDescription();
Winson Chung03a9bae2014-05-02 09:56:12 -0700107
Craig Mautnerd2328952013-03-05 12:46:26 -0800108 /** List of all activities in the task arranged in history order */
Craig Mautner21d24a22014-04-23 11:45:37 -0700109 final ArrayList<ActivityRecord> mActivities;
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800110
Craig Mautnerd2328952013-03-05 12:46:26 -0800111 /** Current stack */
112 ActivityStack stack;
113
Craig Mautner2c1faed2013-07-23 12:56:02 -0700114 /** Takes on same set of values as ActivityRecord.mActivityType */
Craig Mautner21d24a22014-04-23 11:45:37 -0700115 int taskType;
Craig Mautner1602ec22013-05-12 10:24:27 -0700116
Craig Mautner21d24a22014-04-23 11:45:37 -0700117 /** Takes on same value as first root activity */
118 boolean isPersistable = false;
Craig Mautnerffcfcaa2014-06-05 09:54:38 -0700119 int maxRecents;
Craig Mautner21d24a22014-04-23 11:45:37 -0700120
121 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
122 * determining the order when restoring. Sign indicates whether last task movement was to front
123 * (positive) or back (negative). Absolute value indicates time. */
124 long mLastTimeMoved = System.currentTimeMillis();
125
Craig Mautner84984fa2014-06-19 11:19:20 -0700126 /** Indication of what to run next when task exits. Use ActivityRecord types.
127 * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
128 * task stack. */
129 private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
Craig Mautnerae7ecab2013-09-18 11:48:14 -0700130
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700131 /** If original intent did not allow relinquishing task identity, save that information */
132 boolean mNeverRelinquishIdentity = true;
133
Craig Mautner362449a2014-06-20 14:04:39 -0700134 // Used in the unique case where we are clearing the task in order to reuse it. In that case we
135 // do not want to delete the stack when the task goes empty.
136 boolean mReuseTask = false;
137
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700138 private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
139 private final File mLastThumbnailFile; // File containing last thubmnail.
140 private final String mFilename;
141 CharSequence lastDescription; // Last description captured for this item.
142
Craig Mautnera228ae92014-07-09 05:44:55 -0700143 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
Winson Chungec396d62014-08-06 17:08:00 -0700144 int mAffiliatedTaskColor; // color of the parent task affiliation.
Craig Mautnera228ae92014-07-09 05:44:55 -0700145 TaskRecord mPrevAffiliate; // previous task in affiliated chain.
146 int mPrevAffiliateTaskId = -1; // previous id for persistence.
147 TaskRecord mNextAffiliate; // next task in affiliated chain.
148 int mNextAffiliateTaskId = -1; // next id for persistence.
149
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700150 // For relaunching the task from recents as though it was launched by the original launcher.
151 int mCallingUid;
152 String mCallingPackage;
153
Craig Mautner21d24a22014-04-23 11:45:37 -0700154 final ActivityManagerService mService;
155
156 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
Dianne Hackborn91097de2014-04-04 18:02:06 -0700157 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700158 mService = service;
Craig Mautnera228ae92014-07-09 05:44:55 -0700159 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
160 TaskPersister.IMAGE_EXTENSION;
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700161 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 taskId = _taskId;
Craig Mautnera228ae92014-07-09 05:44:55 -0700163 mAffiliatedTaskId = _taskId;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700164 voiceSession = _voiceSession;
165 voiceInteractor = _voiceInteractor;
Craig Mautner21d24a22014-04-23 11:45:37 -0700166 mActivities = new ArrayList<ActivityRecord>();
Martijn Coenend4a69702014-06-30 11:12:17 -0700167 setIntent(_intent, info);
Craig Mautner21d24a22014-04-23 11:45:37 -0700168 }
169
170 TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
171 String _affinity, ComponentName _realActivity, ComponentName _origActivity,
Dianne Hackborn13420f22014-07-18 15:43:56 -0700172 boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode,
173 int _taskType, int _userId,
Winson Chungffa2ec62014-07-03 15:54:42 -0700174 String _lastDescription, ArrayList<ActivityRecord> activities, long _firstActiveTime,
175 long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity,
Craig Mautnera228ae92014-07-09 05:44:55 -0700176 ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation,
Winson Chungec396d62014-08-06 17:08:00 -0700177 int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid,
178 String callingPackage) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700179 mService = service;
Craig Mautnera228ae92014-07-09 05:44:55 -0700180 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
181 TaskPersister.IMAGE_EXTENSION;
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700182 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
Craig Mautner21d24a22014-04-23 11:45:37 -0700183 taskId = _taskId;
184 intent = _intent;
185 affinityIntent = _affinityIntent;
186 affinity = _affinity;
187 voiceSession = null;
188 voiceInteractor = null;
189 realActivity = _realActivity;
190 origActivity = _origActivity;
191 rootWasReset = _rootWasReset;
Dianne Hackborn13420f22014-07-18 15:43:56 -0700192 autoRemoveRecents = _autoRemoveRecents;
Craig Mautner21d24a22014-04-23 11:45:37 -0700193 askedCompatMode = _askedCompatMode;
194 taskType = _taskType;
Craig Mautner84984fa2014-06-19 11:19:20 -0700195 mTaskToReturnTo = HOME_ACTIVITY_TYPE;
Craig Mautner21d24a22014-04-23 11:45:37 -0700196 userId = _userId;
Winson Chungffa2ec62014-07-03 15:54:42 -0700197 firstActiveTime = _firstActiveTime;
Winson Chungf1fbd772014-06-24 18:06:58 -0700198 lastActiveTime = _lastActiveTime;
Craig Mautner21d24a22014-04-23 11:45:37 -0700199 lastDescription = _lastDescription;
200 mActivities = activities;
201 mLastTimeMoved = lastTimeMoved;
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700202 mNeverRelinquishIdentity = neverRelinquishIdentity;
Winson Chung2cb86c72014-06-25 12:03:30 -0700203 lastTaskDescription = _lastTaskDescription;
Craig Mautnera228ae92014-07-09 05:44:55 -0700204 mAffiliatedTaskId = taskAffiliation;
Winson Chungec396d62014-08-06 17:08:00 -0700205 mAffiliatedTaskColor = taskAffiliationColor;
Craig Mautnera228ae92014-07-09 05:44:55 -0700206 mPrevAffiliateTaskId = prevTaskId;
207 mNextAffiliateTaskId = nextTaskId;
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700208 mCallingUid = callingUid;
209 mCallingPackage = callingPackage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 }
211
212 void touchActiveTime() {
Craig Mautner494f6bdd2014-07-21 11:17:46 -0700213 lastActiveTime = System.currentTimeMillis();
Winson Chungffa2ec62014-07-03 15:54:42 -0700214 if (firstActiveTime == 0) {
215 firstActiveTime = lastActiveTime;
216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 long getInactiveDuration() {
Craig Mautner494f6bdd2014-07-21 11:17:46 -0700220 return System.currentTimeMillis() - lastActiveTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 void setIntent(Intent _intent, ActivityInfo info) {
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700224 if (intent == null) {
225 mNeverRelinquishIdentity =
226 (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
227 } else if (mNeverRelinquishIdentity) {
228 return;
229 }
230
231 affinity = info.taskAffinity;
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700232 stringName = null;
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 if (info.targetActivity == null) {
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800235 if (_intent != null) {
236 // If this Intent has a selector, we want to clear it for the
237 // recent task since it is not relevant if the user later wants
238 // to re-launch the app.
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700239 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800240 _intent = new Intent(_intent);
241 _intent.setSelector(null);
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700242 _intent.setSourceBounds(null);
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800243 }
244 }
Dianne Hackborn7f96b792012-05-29 18:46:45 -0700245 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
246 "Setting Intent of " + this + " to " + _intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 intent = _intent;
248 realActivity = _intent != null ? _intent.getComponent() : null;
249 origActivity = null;
250 } else {
251 ComponentName targetComponent = new ComponentName(
252 info.packageName, info.targetActivity);
253 if (_intent != null) {
254 Intent targetIntent = new Intent(_intent);
255 targetIntent.setComponent(targetComponent);
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800256 targetIntent.setSelector(null);
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700257 targetIntent.setSourceBounds(null);
Dianne Hackborn7f96b792012-05-29 18:46:45 -0700258 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
259 "Setting Intent of " + this + " to target " + targetIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 intent = targetIntent;
261 realActivity = targetComponent;
262 origActivity = _intent.getComponent();
263 } else {
264 intent = null;
265 realActivity = targetComponent;
266 origActivity = new ComponentName(info.packageName, info.name);
267 }
268 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 if (intent != null &&
271 (intent.getFlags()&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
272 // Once we are set to an Intent with this flag, we count this
273 // task as having a true root activity.
274 rootWasReset = true;
275 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700276
Dianne Hackborn09233282014-04-30 11:33:59 -0700277 userId = UserHandle.getUserId(info.applicationInfo.uid);
278 creatorUid = info.applicationInfo.uid;
Craig Mautner41db4a72014-05-07 17:20:56 -0700279 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
Dianne Hackborn13420f22014-07-18 15:43:56 -0700280 // If the activity itself has requested auto-remove, then just always do it.
281 autoRemoveRecents = true;
282 } else if ((intent.getFlags()&(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
283 |Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) {
284 // If the caller has not asked for the document to be retained, then we may
285 // want to turn on auto-remove, depending on whether the target has set its
286 // own document launch mode.
287 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
288 autoRemoveRecents = false;
289 } else {
290 autoRemoveRecents = true;
291 }
292 } else {
293 autoRemoveRecents = false;
Craig Mautner41db4a72014-05-07 17:20:56 -0700294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800296
Craig Mautner84984fa2014-06-19 11:19:20 -0700297 void setTaskToReturnTo(int taskToReturnTo) {
Craig Mautner0b633fc2014-07-23 10:42:18 -0700298 if (IGNORE_RETURN_TO_RECENTS && taskToReturnTo == RECENTS_ACTIVITY_TYPE) {
299 taskToReturnTo = HOME_ACTIVITY_TYPE;
300 }
Craig Mautner84984fa2014-06-19 11:19:20 -0700301 mTaskToReturnTo = taskToReturnTo;
302 }
303
304 int getTaskToReturnTo() {
305 return mTaskToReturnTo;
306 }
307
Craig Mautnera228ae92014-07-09 05:44:55 -0700308 void setPrevAffiliate(TaskRecord prevAffiliate) {
309 mPrevAffiliate = prevAffiliate;
310 mPrevAffiliateTaskId = prevAffiliate == null ? -1 : prevAffiliate.taskId;
311 }
312
313 void setNextAffiliate(TaskRecord nextAffiliate) {
314 mNextAffiliate = nextAffiliate;
315 mNextAffiliateTaskId = nextAffiliate == null ? -1 : nextAffiliate.taskId;
316 }
317
318 // Close up recents linked list.
319 void closeRecentsChain() {
320 if (mPrevAffiliate != null) {
321 mPrevAffiliate.setNextAffiliate(mNextAffiliate);
322 }
323 if (mNextAffiliate != null) {
324 mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
325 }
326 setPrevAffiliate(null);
327 setNextAffiliate(null);
328 }
329
330 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
331 closeRecentsChain();
332 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
Winson Chungec396d62014-08-06 17:08:00 -0700333 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
Craig Mautnera228ae92014-07-09 05:44:55 -0700334 // Find the end
335 while (taskToAffiliateWith.mNextAffiliate != null) {
336 final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
337 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
338 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
339 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
340 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
341 nextRecents.setPrevAffiliate(null);
342 }
343 taskToAffiliateWith.setNextAffiliate(null);
344 break;
345 }
346 taskToAffiliateWith = nextRecents;
347 }
348 taskToAffiliateWith.setNextAffiliate(this);
349 setPrevAffiliate(taskToAffiliateWith);
350 setNextAffiliate(null);
351 }
352
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700353 void setLastThumbnail(Bitmap thumbnail) {
354 mLastThumbnail = thumbnail;
355 if (thumbnail == null) {
356 if (mLastThumbnailFile != null) {
357 mLastThumbnailFile.delete();
358 }
359 } else {
360 mService.mTaskPersister.saveImage(thumbnail, mFilename);
361 }
362 }
363
364 void getLastThumbnail(TaskThumbnail thumbs) {
365 thumbs.mainThumbnail = mLastThumbnail;
366 thumbs.thumbnailFileDescriptor = null;
Craig Mautnerf4f8bb72014-07-29 10:41:40 -0700367 if (mLastThumbnail == null) {
368 thumbs.mainThumbnail = mService.mTaskPersister.getThumbnail(mFilename);
369 }
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700370 if (mLastThumbnailFile.exists()) {
371 try {
372 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
373 ParcelFileDescriptor.MODE_READ_ONLY);
374 } catch (IOException e) {
Dianne Hackborn9844d292013-10-04 16:44:22 -0700375 }
376 }
377 }
378
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700379 void freeLastThumbnail() {
380 mLastThumbnail = null;
381 }
382
383 void disposeThumbnail() {
384 mLastThumbnail = null;
385 lastDescription = null;
386 }
387
Winson Chung1147c402014-05-14 11:05:00 -0700388 /** Returns the intent for the root activity for this task */
389 Intent getBaseIntent() {
390 return intent != null ? intent : affinityIntent;
391 }
392
Winson Chung3b3f4642014-04-22 10:08:18 -0700393 /** Returns the first non-finishing activity from the root. */
394 ActivityRecord getRootActivity() {
395 for (int i = 0; i < mActivities.size(); i++) {
396 final ActivityRecord r = mActivities.get(i);
397 if (r.finishing) {
398 continue;
399 }
400 return r;
401 }
402 return null;
403 }
404
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800405 ActivityRecord getTopActivity() {
406 for (int i = mActivities.size() - 1; i >= 0; --i) {
407 final ActivityRecord r = mActivities.get(i);
408 if (r.finishing) {
409 continue;
410 }
411 return r;
412 }
413 return null;
414 }
415
Craig Mautner6b74cb52013-09-27 17:02:21 -0700416 ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
417 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
418 ActivityRecord r = mActivities.get(activityNdx);
Amith Yamasani734983f2014-03-04 16:48:05 -0800419 if (!r.finishing && r != notTop && stack.okToShowLocked(r)) {
Craig Mautner6b74cb52013-09-27 17:02:21 -0700420 return r;
421 }
422 }
423 return null;
424 }
425
Craig Mautner3b475fe2013-12-16 15:58:31 -0800426 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
427 final void setFrontOfTask() {
428 boolean foundFront = false;
429 final int numActivities = mActivities.size();
Craig Mautner704e40b2013-12-18 16:43:51 -0800430 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
Craig Mautner3b475fe2013-12-16 15:58:31 -0800431 final ActivityRecord r = mActivities.get(activityNdx);
432 if (foundFront || r.finishing) {
433 r.frontOfTask = false;
434 } else {
435 r.frontOfTask = true;
436 // Set frontOfTask false for every following activity.
437 foundFront = true;
438 }
439 }
Craig Mautner9587ee02014-06-23 15:00:10 +0000440 if (!foundFront && numActivities > 0) {
441 // All activities of this task are finishing. As we ought to have a frontOfTask
442 // activity, make the bottom activity front.
443 mActivities.get(0).frontOfTask = true;
444 }
Craig Mautner3b475fe2013-12-16 15:58:31 -0800445 }
446
Craig Mautnerde4ef022013-04-07 19:01:33 -0700447 /**
Craig Mautner3b475fe2013-12-16 15:58:31 -0800448 * Reorder the history stack so that the passed activity is brought to the front.
Craig Mautnerde4ef022013-04-07 19:01:33 -0700449 */
450 final void moveActivityToFrontLocked(ActivityRecord newTop) {
451 if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop
452 + " to stack at top", new RuntimeException("here").fillInStackTrace());
453
Craig Mautnerde4ef022013-04-07 19:01:33 -0700454 mActivities.remove(newTop);
455 mActivities.add(newTop);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700456 updateEffectiveIntent();
Craig Mautner3b475fe2013-12-16 15:58:31 -0800457
458 setFrontOfTask();
Craig Mautnerde4ef022013-04-07 19:01:33 -0700459 }
460
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800461 void addActivityAtBottom(ActivityRecord r) {
Craig Mautner77878772013-03-04 19:46:24 -0800462 addActivityAtIndex(0, r);
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800463 }
464
465 void addActivityToTop(ActivityRecord r) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700466 addActivityAtIndex(mActivities.size(), r);
467 }
468
469 void addActivityAtIndex(int index, ActivityRecord r) {
Craig Mautner6170f732013-04-02 13:05:23 -0700470 // 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 -0800471 if (!mActivities.remove(r) && r.fullscreen) {
472 // Was not previously in list.
473 numFullscreen++;
474 }
Craig Mautner2c1faed2013-07-23 12:56:02 -0700475 // Only set this based on the first activity
476 if (mActivities.isEmpty()) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700477 taskType = r.mActivityType;
478 isPersistable = r.isPersistable();
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700479 mCallingUid = r.launchedFromUid;
480 mCallingPackage = r.launchedFromPackage;
Craig Mautnerffcfcaa2014-06-05 09:54:38 -0700481 // Clamp to [1, 100].
482 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 100);
Craig Mautner2c1faed2013-07-23 12:56:02 -0700483 } else {
484 // Otherwise make all added activities match this one.
Craig Mautner21d24a22014-04-23 11:45:37 -0700485 r.mActivityType = taskType;
Craig Mautner78733002013-06-10 13:54:49 -0700486 }
Craig Mautner77878772013-03-04 19:46:24 -0800487 mActivities.add(index, r);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700488 updateEffectiveIntent();
Craig Mautner21d24a22014-04-23 11:45:37 -0700489 if (r.isPersistable()) {
490 mService.notifyTaskPersisterLocked(this, false);
491 }
Craig Mautner77878772013-03-04 19:46:24 -0800492 }
493
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800494 /** @return true if this was the last activity in the task */
495 boolean removeActivity(ActivityRecord r) {
496 if (mActivities.remove(r) && r.fullscreen) {
497 // Was previously in list.
498 numFullscreen--;
499 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700500 if (r.isPersistable()) {
501 mService.notifyTaskPersisterLocked(this, false);
502 }
Craig Mautner41326202014-06-20 14:38:21 -0700503 if (mActivities.isEmpty()) {
Craig Mautner5afcd4d2014-06-21 18:11:33 -0700504 return !mReuseTask;
Craig Mautner41326202014-06-20 14:38:21 -0700505 }
506 updateEffectiveIntent();
507 return false;
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800508 }
509
Craig Mautner41db4a72014-05-07 17:20:56 -0700510 boolean autoRemoveFromRecents() {
Dianne Hackbornd38aed82014-06-10 21:36:35 -0700511 // We will automatically remove the task either if it has explicitly asked for
512 // this, or it is empty and has never contained an activity that got shown to
513 // the user.
Dianne Hackborn13420f22014-07-18 15:43:56 -0700514 return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible);
Craig Mautner41db4a72014-05-07 17:20:56 -0700515 }
516
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700517 /**
518 * Completely remove all activities associated with an existing
519 * task starting at a specified index.
520 */
521 final void performClearTaskAtIndexLocked(int activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700522 int numActivities = mActivities.size();
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700523 for ( ; activityNdx < numActivities; ++activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700524 final ActivityRecord r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700525 if (r.finishing) {
526 continue;
527 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700528 if (stack == null) {
529 // Task was restored from persistent storage.
530 r.takeFromHistory();
531 mActivities.remove(activityNdx);
532 --activityNdx;
533 --numActivities;
534 } else if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
535 false)) {
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700536 --activityNdx;
537 --numActivities;
538 }
539 }
540 }
541
542 /**
543 * Completely remove all activities associated with an existing task.
544 */
545 final void performClearTaskLocked() {
Craig Mautner362449a2014-06-20 14:04:39 -0700546 mReuseTask = true;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700547 performClearTaskAtIndexLocked(0);
Craig Mautner362449a2014-06-20 14:04:39 -0700548 mReuseTask = false;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700549 }
550
551 /**
552 * Perform clear operation as requested by
553 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
554 * stack to the given task, then look for
555 * an instance of that activity in the stack and, if found, finish all
556 * activities on top of it and return the instance.
557 *
558 * @param newR Description of the new activity being started.
559 * @return Returns the old activity that should be continued to be used,
560 * or null if none was found.
561 */
562 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700563 int numActivities = mActivities.size();
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700564 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700565 ActivityRecord r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700566 if (r.finishing) {
567 continue;
568 }
569 if (r.realActivity.equals(newR.realActivity)) {
570 // Here it is! Now finish everything in front...
Craig Mautner1602ec22013-05-12 10:24:27 -0700571 final ActivityRecord ret = r;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700572
573 for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700574 r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700575 if (r.finishing) {
576 continue;
577 }
578 ActivityOptions opts = r.takeOptionsLocked();
579 if (opts != null) {
580 ret.updateOptionsLocked(opts);
581 }
582 if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
583 false)) {
584 --activityNdx;
585 --numActivities;
586 }
587 }
588
589 // Finally, if this is a normal launch mode (that is, not
590 // expecting onNewIntent()), then we will finish the current
591 // instance of the activity so a new fresh one can be started.
592 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
593 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
594 if (!ret.finishing) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700595 stack.finishActivityLocked(ret, Activity.RESULT_CANCELED, null,
596 "clear", false);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700597 return null;
598 }
599 }
600
601 return ret;
602 }
603 }
604
605 return null;
606 }
607
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700608 public TaskThumbnail getTaskThumbnailLocked() {
Craig Mautner21d24a22014-04-23 11:45:37 -0700609 if (stack != null) {
610 final ActivityRecord resumedActivity = stack.mResumedActivity;
611 if (resumedActivity != null && resumedActivity.task == this) {
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700612 final Bitmap thumbnail = stack.screenshotActivities(resumedActivity);
613 setLastThumbnail(thumbnail);
Craig Mautner21d24a22014-04-23 11:45:37 -0700614 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700615 }
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700616 final TaskThumbnail taskThumbnail = new TaskThumbnail();
617 getLastThumbnail(taskThumbnail);
618 return taskThumbnail;
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700619 }
620
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700621 public void removeTaskActivitiesLocked() {
622 // Just remove the entire task.
623 performClearTaskAtIndexLocked(0);
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700624 }
625
Craig Mautnera82aa092013-09-13 15:34:08 -0700626 boolean isHomeTask() {
Craig Mautner84984fa2014-06-19 11:19:20 -0700627 return taskType == HOME_ACTIVITY_TYPE;
Craig Mautnera82aa092013-09-13 15:34:08 -0700628 }
629
Craig Mautner86d67a42013-05-14 10:34:38 -0700630 boolean isApplicationTask() {
Craig Mautner84984fa2014-06-19 11:19:20 -0700631 return taskType == APPLICATION_ACTIVITY_TYPE;
632 }
633
634 boolean isOverHomeStack() {
635 return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
Craig Mautner1602ec22013-05-12 10:24:27 -0700636 }
637
Craig Mautner525f3d92013-05-07 14:01:50 -0700638 /**
639 * Find the activity in the history stack within the given task. Returns
640 * the index within the history at which it's found, or < 0 if not found.
641 */
642 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
643 final ComponentName realActivity = r.realActivity;
644 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
645 ActivityRecord candidate = mActivities.get(activityNdx);
646 if (candidate.finishing) {
647 continue;
648 }
649 if (candidate.realActivity.equals(realActivity)) {
650 return candidate;
651 }
652 }
653 return null;
654 }
655
Winson Chunga449dc02014-05-16 11:15:04 -0700656 /** Updates the last task description values. */
657 void updateTaskDescription() {
658 // Traverse upwards looking for any break between main task activities and
659 // utility activities.
660 int activityNdx;
661 final int numActivities = mActivities.size();
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700662 final boolean relinquish = numActivities == 0 ? false :
663 (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0;
Winson Chunga449dc02014-05-16 11:15:04 -0700664 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
Craig Mautner21d24a22014-04-23 11:45:37 -0700665 ++activityNdx) {
Winson Chunga449dc02014-05-16 11:15:04 -0700666 final ActivityRecord r = mActivities.get(activityNdx);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700667 if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
668 // This will be the top activity for determining taskDescription. Pre-inc to
669 // overcome initial decrement below.
670 ++activityNdx;
671 break;
672 }
Winson Chunga449dc02014-05-16 11:15:04 -0700673 if (r.intent != null &&
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700674 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
Winson Chunga449dc02014-05-16 11:15:04 -0700675 break;
676 }
677 }
678 if (activityNdx > 0) {
679 // Traverse downwards starting below break looking for set label, icon.
680 // Note that if there are activities in the task but none of them set the
681 // recent activity values, then we do not fall back to the last set
682 // values in the TaskRecord.
683 String label = null;
684 Bitmap icon = null;
685 int colorPrimary = 0;
686 for (--activityNdx; activityNdx >= 0; --activityNdx) {
687 final ActivityRecord r = mActivities.get(activityNdx);
688 if (r.taskDescription != null) {
689 if (label == null) {
690 label = r.taskDescription.getLabel();
691 }
692 if (icon == null) {
693 icon = r.taskDescription.getIcon();
694 }
695 if (colorPrimary == 0) {
696 colorPrimary = r.taskDescription.getPrimaryColor();
Winson Chunga449dc02014-05-16 11:15:04 -0700697 }
698 }
699 }
700 lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary);
Winson Chungec396d62014-08-06 17:08:00 -0700701 // Update the task affiliation color if we are the parent of the group
702 if (taskId == mAffiliatedTaskId) {
703 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
704 }
Winson Chunga449dc02014-05-16 11:15:04 -0700705 }
706 }
707
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700708 int findEffectiveRootIndex() {
709 int activityNdx;
710 final int topActivityNdx = mActivities.size() - 1;
711 for (activityNdx = 0; activityNdx < topActivityNdx; ++activityNdx) {
712 final ActivityRecord r = mActivities.get(activityNdx);
713 if (r.finishing) {
714 continue;
715 }
716 if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
717 break;
718 }
719 }
720 return activityNdx;
721 }
722
723 void updateEffectiveIntent() {
724 final int effectiveRootIndex = findEffectiveRootIndex();
725 final ActivityRecord r = mActivities.get(effectiveRootIndex);
726 setIntent(r.intent, r.info);
727 }
728
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700729 void saveTaskDescription(ActivityManager.TaskDescription taskDescription,
730 String iconFilename, XmlSerializer out) throws IOException {
731 if (taskDescription != null) {
732 final String label = taskDescription.getLabel();
733 if (label != null) {
734 out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label);
735 }
736 final int colorPrimary = taskDescription.getPrimaryColor();
737 if (colorPrimary != 0) {
738 out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary));
739 }
740 final Bitmap icon = taskDescription.getIcon();
741 if (icon != null) {
742 mService.mTaskPersister.saveImage(icon, iconFilename);
743 }
744 }
745 }
746
747 static boolean readTaskDescriptionAttribute(ActivityManager.TaskDescription taskDescription,
748 String attrName, String attrValue) {
749 if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
750 taskDescription.setLabel(attrValue);
751 } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
752 taskDescription.setPrimaryColor((int) Long.parseLong(attrValue, 16));
753 } else {
754 return false;
755 }
756 return true;
757 }
758
Craig Mautner21d24a22014-04-23 11:45:37 -0700759 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
760 Slog.i(TAG, "Saving task=" + this);
761
762 out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
763 if (realActivity != null) {
764 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
765 }
766 if (origActivity != null) {
767 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
768 }
769 if (affinity != null) {
770 out.attribute(null, ATTR_AFFINITY, affinity);
771 }
772 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
Dianne Hackborn13420f22014-07-18 15:43:56 -0700773 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
Craig Mautner21d24a22014-04-23 11:45:37 -0700774 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
775 out.attribute(null, ATTR_USERID, String.valueOf(userId));
776 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
Winson Chungffa2ec62014-07-03 15:54:42 -0700777 out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
Winson Chungf1fbd772014-06-24 18:06:58 -0700778 out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime));
Craig Mautner21d24a22014-04-23 11:45:37 -0700779 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700780 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
Craig Mautner21d24a22014-04-23 11:45:37 -0700781 if (lastDescription != null) {
782 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
783 }
Winson Chung2cb86c72014-06-25 12:03:30 -0700784 if (lastTaskDescription != null) {
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700785 saveTaskDescription(lastTaskDescription, String.valueOf(taskId) +
Winson Chung2cb86c72014-06-25 12:03:30 -0700786 LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime, out);
787 }
Winson Chungec396d62014-08-06 17:08:00 -0700788 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
Craig Mautnera228ae92014-07-09 05:44:55 -0700789 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
790 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
791 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700792 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
793 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
Winson Chung2cb86c72014-06-25 12:03:30 -0700794
Craig Mautner21d24a22014-04-23 11:45:37 -0700795 if (affinityIntent != null) {
796 out.startTag(null, TAG_AFFINITYINTENT);
797 affinityIntent.saveToXml(out);
798 out.endTag(null, TAG_AFFINITYINTENT);
799 }
800
801 out.startTag(null, TAG_INTENT);
802 intent.saveToXml(out);
803 out.endTag(null, TAG_INTENT);
804
805 final ArrayList<ActivityRecord> activities = mActivities;
806 final int numActivities = activities.size();
807 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
808 final ActivityRecord r = activities.get(activityNdx);
Craig Mautner43e52ed2014-06-16 17:18:52 -0700809 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
810 ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) &&
811 activityNdx > 0) {
Craig Mautnerf357c0c2014-06-09 09:23:27 -0700812 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
Craig Mautner21d24a22014-04-23 11:45:37 -0700813 break;
814 }
815 out.startTag(null, TAG_ACTIVITY);
816 r.saveToXml(out);
817 out.endTag(null, TAG_ACTIVITY);
818 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700819 }
820
821 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
822 throws IOException, XmlPullParserException {
823 Intent intent = null;
824 Intent affinityIntent = null;
825 ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
826 ComponentName realActivity = null;
827 ComponentName origActivity = null;
828 String affinity = null;
829 boolean rootHasReset = false;
Dianne Hackborn13420f22014-07-18 15:43:56 -0700830 boolean autoRemoveRecents = false;
Craig Mautner21d24a22014-04-23 11:45:37 -0700831 boolean askedCompatMode = false;
832 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
Craig Mautner21d24a22014-04-23 11:45:37 -0700833 int userId = 0;
834 String lastDescription = null;
Winson Chungffa2ec62014-07-03 15:54:42 -0700835 long firstActiveTime = -1;
Winson Chung2cb86c72014-06-25 12:03:30 -0700836 long lastActiveTime = -1;
Craig Mautner21d24a22014-04-23 11:45:37 -0700837 long lastTimeOnTop = 0;
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700838 boolean neverRelinquishIdentity = true;
Craig Mautner21d24a22014-04-23 11:45:37 -0700839 int taskId = -1;
840 final int outerDepth = in.getDepth();
Winson Chung2cb86c72014-06-25 12:03:30 -0700841 ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription();
Craig Mautnera228ae92014-07-09 05:44:55 -0700842 int taskAffiliation = -1;
Winson Chungec396d62014-08-06 17:08:00 -0700843 int taskAffiliationColor = 0;
Craig Mautnera228ae92014-07-09 05:44:55 -0700844 int prevTaskId = -1;
845 int nextTaskId = -1;
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700846 int callingUid = -1;
847 String callingPackage = "";
Craig Mautner21d24a22014-04-23 11:45:37 -0700848
849 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
850 final String attrName = in.getAttributeName(attrNdx);
851 final String attrValue = in.getAttributeValue(attrNdx);
852 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
853 attrName + " value=" + attrValue);
854 if (ATTR_TASKID.equals(attrName)) {
855 taskId = Integer.valueOf(attrValue);
856 } else if (ATTR_REALACTIVITY.equals(attrName)) {
857 realActivity = ComponentName.unflattenFromString(attrValue);
858 } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
859 origActivity = ComponentName.unflattenFromString(attrValue);
860 } else if (ATTR_AFFINITY.equals(attrName)) {
861 affinity = attrValue;
862 } else if (ATTR_ROOTHASRESET.equals(attrName)) {
863 rootHasReset = Boolean.valueOf(attrValue);
Dianne Hackborn13420f22014-07-18 15:43:56 -0700864 } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) {
865 autoRemoveRecents = Boolean.valueOf(attrValue);
Craig Mautner21d24a22014-04-23 11:45:37 -0700866 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
867 askedCompatMode = Boolean.valueOf(attrValue);
868 } else if (ATTR_USERID.equals(attrName)) {
869 userId = Integer.valueOf(attrValue);
870 } else if (ATTR_TASKTYPE.equals(attrName)) {
871 taskType = Integer.valueOf(attrValue);
Winson Chungffa2ec62014-07-03 15:54:42 -0700872 } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) {
873 firstActiveTime = Long.valueOf(attrValue);
Winson Chungf1fbd772014-06-24 18:06:58 -0700874 } else if (ATTR_LASTACTIVETIME.equals(attrName)) {
875 lastActiveTime = Long.valueOf(attrValue);
Craig Mautner21d24a22014-04-23 11:45:37 -0700876 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
877 lastDescription = attrValue;
878 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
879 lastTimeOnTop = Long.valueOf(attrValue);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700880 } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
881 neverRelinquishIdentity = Boolean.valueOf(attrValue);
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700882 } else if (readTaskDescriptionAttribute(taskDescription, attrName, attrValue)) {
Winson Chung2cb86c72014-06-25 12:03:30 -0700883 // Completed in TaskPersister.readTaskDescriptionAttribute()
Craig Mautnera228ae92014-07-09 05:44:55 -0700884 } else if (ATTR_TASK_AFFILIATION.equals(attrName)) {
885 taskAffiliation = Integer.valueOf(attrValue);
886 } else if (ATTR_PREV_AFFILIATION.equals(attrName)) {
887 prevTaskId = Integer.valueOf(attrValue);
888 } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) {
889 nextTaskId = Integer.valueOf(attrValue);
Winson Chungec396d62014-08-06 17:08:00 -0700890 } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) {
891 taskAffiliationColor = Integer.valueOf(attrValue);
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700892 } else if (ATTR_CALLING_UID.equals(attrName)) {
893 callingUid = Integer.valueOf(attrValue);
894 } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
895 callingPackage = attrValue;
Craig Mautner21d24a22014-04-23 11:45:37 -0700896 } else {
897 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
898 }
899 }
900
901 int event;
902 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
903 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
904 if (event == XmlPullParser.START_TAG) {
905 final String name = in.getName();
906 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
907 name);
908 if (TAG_AFFINITYINTENT.equals(name)) {
909 affinityIntent = Intent.restoreFromXml(in);
910 } else if (TAG_INTENT.equals(name)) {
911 intent = Intent.restoreFromXml(in);
912 } else if (TAG_ACTIVITY.equals(name)) {
913 ActivityRecord activity =
914 ActivityRecord.restoreFromXml(in, taskId, stackSupervisor);
915 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
916 activity);
917 if (activity != null) {
918 activities.add(activity);
919 }
920 } else {
921 Slog.e(TAG, "restoreTask: Unexpected name=" + name);
922 XmlUtils.skipCurrentTag(in);
923 }
924 }
925 }
926
Winson Chung2cb86c72014-06-25 12:03:30 -0700927 if (lastActiveTime >= 0) {
928 taskDescription.setIcon(TaskPersister.restoreImage(String.valueOf(taskId) +
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700929 LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime + TaskPersister.IMAGE_EXTENSION));
Winson Chung2cb86c72014-06-25 12:03:30 -0700930 }
931
Craig Mautner21d24a22014-04-23 11:45:37 -0700932 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
933 affinityIntent, affinity, realActivity, origActivity, rootHasReset,
Dianne Hackborn13420f22014-07-18 15:43:56 -0700934 autoRemoveRecents, askedCompatMode, taskType, userId, lastDescription, activities,
935 firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
Winson Chungec396d62014-08-06 17:08:00 -0700936 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
937 callingUid, callingPackage);
Craig Mautner21d24a22014-04-23 11:45:37 -0700938
939 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700940 activities.get(activityNdx).task = task;
Craig Mautner21d24a22014-04-23 11:45:37 -0700941 }
942
Craig Mautner21d24a22014-04-23 11:45:37 -0700943 Slog.i(TAG, "Restored task=" + task);
944 return task;
945 }
946
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 void dump(PrintWriter pw, String prefix) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700948 if (rootWasReset || userId != 0 || numFullscreen != 0) {
949 pw.print(prefix); pw.print(" rootWasReset="); pw.print(rootWasReset);
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800950 pw.print(" userId="); pw.print(userId);
Craig Mautner21d24a22014-04-23 11:45:37 -0700951 pw.print(" taskType="); pw.print(taskType);
Craig Mautnerae7ecab2013-09-18 11:48:14 -0700952 pw.print(" numFullscreen="); pw.print(numFullscreen);
Craig Mautner84984fa2014-06-19 11:19:20 -0700953 pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700954 }
955 if (affinity != null) {
956 pw.print(prefix); pw.print("affinity="); pw.println(affinity);
957 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700958 if (voiceSession != null || voiceInteractor != null) {
959 pw.print(prefix); pw.print("VOICE: session=0x");
960 pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
961 pw.print(" interactor=0x");
962 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
963 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700964 if (intent != null) {
965 StringBuilder sb = new StringBuilder(128);
966 sb.append(prefix); sb.append("intent={");
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800967 intent.toShortString(sb, false, true, false, true);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700968 sb.append('}');
969 pw.println(sb.toString());
970 }
971 if (affinityIntent != null) {
972 StringBuilder sb = new StringBuilder(128);
973 sb.append(prefix); sb.append("affinityIntent={");
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800974 affinityIntent.toShortString(sb, false, true, false, true);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700975 sb.append('}');
976 pw.println(sb.toString());
977 }
978 if (origActivity != null) {
979 pw.print(prefix); pw.print("origActivity=");
980 pw.println(origActivity.flattenToShortString());
981 }
982 if (realActivity != null) {
983 pw.print(prefix); pw.print("realActivity=");
984 pw.println(realActivity.flattenToShortString());
985 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800986 pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700987 if (!askedCompatMode) {
988 pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
989 }
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700990 pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail);
991 pw.print(" lastThumbnailFile="); pw.print(mLastThumbnailFile);
Dianne Hackborncfb9f2b2011-08-24 10:51:49 -0700992 pw.print(" lastDescription="); pw.println(lastDescription);
Dianne Hackbornd38aed82014-06-10 21:36:35 -0700993 pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
Winson Chungffa2ec62014-07-03 15:54:42 -0700994 pw.print(" firstActiveTime="); pw.print(lastActiveTime);
Dianne Hackbornd38aed82014-06-10 21:36:35 -0700995 pw.print(" lastActiveTime="); pw.print(lastActiveTime);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700996 pw.print(" (inactive for ");
997 pw.print((getInactiveDuration()/1000)); pw.println("s)");
Craig Mautnera228ae92014-07-09 05:44:55 -0700998 pw.print(prefix); pw.print("isPersistable="); pw.print(isPersistable);
999 pw.print(" affiliation="); pw.print(mAffiliatedTaskId);
1000 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
1001 pw.print(" nextAffiliation="); pw.println(mNextAffiliateTaskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 }
1003
Craig Mautner5d9c7be2013-02-15 14:02:56 -08001004 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001006 StringBuilder sb = new StringBuilder(128);
Craig Mautnerde4ef022013-04-07 19:01:33 -07001007 if (stringName != null) {
1008 sb.append(stringName);
1009 sb.append(" U=");
1010 sb.append(userId);
1011 sb.append(" sz=");
1012 sb.append(mActivities.size());
1013 sb.append('}');
1014 return sb.toString();
1015 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001016 sb.append("TaskRecord{");
1017 sb.append(Integer.toHexString(System.identityHashCode(this)));
1018 sb.append(" #");
1019 sb.append(taskId);
1020 if (affinity != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -08001021 sb.append(" A=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001022 sb.append(affinity);
1023 } else if (intent != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -08001024 sb.append(" I=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001025 sb.append(intent.getComponent().flattenToShortString());
1026 } else if (affinityIntent != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -08001027 sb.append(" aI=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001028 sb.append(affinityIntent.getComponent().flattenToShortString());
1029 } else {
1030 sb.append(" ??");
1031 }
Craig Mautnerde4ef022013-04-07 19:01:33 -07001032 stringName = sb.toString();
1033 return toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 }
1035}