blob: 061053aef5cbddce0bd54e648e89b28303fcb0fd [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 Chung2cb86c72014-06-25 12:03:30 -070071 private static final String LAST_ACTIVITY_ICON_SUFFIX = "_last_activity_icon_";
Craig Mautner21d24a22014-04-23 11:45:37 -070072
73 private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
74
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 final int taskId; // Unique identifier for this task.
Craig Mautner9d4e9bc2014-06-18 18:34:56 -070076 String affinity; // The affinity name for this task, or null.
Dianne Hackborn91097de2014-04-04 18:02:06 -070077 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
78 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 Intent intent; // The original intent that started the task.
80 Intent affinityIntent; // Intent of affinity-moved activity that started this task.
81 ComponentName origActivity; // The non-alias activity component of the intent.
82 ComponentName realActivity; // The actual activity component that started the task.
Winson Chungffa2ec62014-07-03 15:54:42 -070083 long firstActiveTime; // First time this task was active.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 long lastActiveTime; // Last time this task was active, including sleep.
85 boolean rootWasReset; // True if the intent at the root of the task had
86 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
Dianne Hackborn13420f22014-07-18 15:43:56 -070087 boolean autoRemoveRecents; // If true, we should automatically remove the task from
88 // recents when activity finishes
Dianne Hackborn36cd41f2011-05-25 21:00:46 -070089 boolean askedCompatMode;// Have asked the user about compat mode for this task.
Dianne Hackbornd38aed82014-06-10 21:36:35 -070090 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 -080091
Dianne Hackborn1d442e02009-04-20 18:14:05 -070092 String stringName; // caching of toString() result.
Dianne Hackborn9da2d402012-03-15 13:43:08 -070093 int userId; // user for which this task was created
Dianne Hackborn09233282014-04-30 11:33:59 -070094 int creatorUid; // The app uid that originally created the task
Craig Mautner5d9c7be2013-02-15 14:02:56 -080095
96 int numFullscreen; // Number of fullscreen activities.
97
Winson Chung03a9bae2014-05-02 09:56:12 -070098 // This represents the last resolved activity values for this task
99 // NOTE: This value needs to be persisted with each task
Winson Chunga449dc02014-05-16 11:15:04 -0700100 ActivityManager.TaskDescription lastTaskDescription =
101 new ActivityManager.TaskDescription();
Winson Chung03a9bae2014-05-02 09:56:12 -0700102
Craig Mautnerd2328952013-03-05 12:46:26 -0800103 /** List of all activities in the task arranged in history order */
Craig Mautner21d24a22014-04-23 11:45:37 -0700104 final ArrayList<ActivityRecord> mActivities;
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800105
Craig Mautnerd2328952013-03-05 12:46:26 -0800106 /** Current stack */
107 ActivityStack stack;
108
Craig Mautner2c1faed2013-07-23 12:56:02 -0700109 /** Takes on same set of values as ActivityRecord.mActivityType */
Craig Mautner21d24a22014-04-23 11:45:37 -0700110 int taskType;
Craig Mautner1602ec22013-05-12 10:24:27 -0700111
Craig Mautner21d24a22014-04-23 11:45:37 -0700112 /** Takes on same value as first root activity */
113 boolean isPersistable = false;
Craig Mautnerffcfcaa2014-06-05 09:54:38 -0700114 int maxRecents;
Craig Mautner21d24a22014-04-23 11:45:37 -0700115
116 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
117 * determining the order when restoring. Sign indicates whether last task movement was to front
118 * (positive) or back (negative). Absolute value indicates time. */
119 long mLastTimeMoved = System.currentTimeMillis();
120
121 /** True if persistable, has changed, and has not yet been persisted */
122 boolean needsPersisting = false;
Craig Mautnerffcfcaa2014-06-05 09:54:38 -0700123
Craig Mautner84984fa2014-06-19 11:19:20 -0700124 /** Indication of what to run next when task exits. Use ActivityRecord types.
125 * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
126 * task stack. */
127 private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
Craig Mautnerae7ecab2013-09-18 11:48:14 -0700128
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700129 /** If original intent did not allow relinquishing task identity, save that information */
130 boolean mNeverRelinquishIdentity = true;
131
Craig Mautner362449a2014-06-20 14:04:39 -0700132 // Used in the unique case where we are clearing the task in order to reuse it. In that case we
133 // do not want to delete the stack when the task goes empty.
134 boolean mReuseTask = false;
135
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700136 private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
137 private final File mLastThumbnailFile; // File containing last thubmnail.
138 private final String mFilename;
139 CharSequence lastDescription; // Last description captured for this item.
140
Craig Mautnera228ae92014-07-09 05:44:55 -0700141 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
142 TaskRecord mPrevAffiliate; // previous task in affiliated chain.
143 int mPrevAffiliateTaskId = -1; // previous id for persistence.
144 TaskRecord mNextAffiliate; // next task in affiliated chain.
145 int mNextAffiliateTaskId = -1; // next id for persistence.
146
Craig Mautner21d24a22014-04-23 11:45:37 -0700147 final ActivityManagerService mService;
148
149 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
Dianne Hackborn91097de2014-04-04 18:02:06 -0700150 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700151 mService = service;
Craig Mautnera228ae92014-07-09 05:44:55 -0700152 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
153 TaskPersister.IMAGE_EXTENSION;
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700154 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 taskId = _taskId;
Craig Mautnera228ae92014-07-09 05:44:55 -0700156 mAffiliatedTaskId = _taskId;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700157 voiceSession = _voiceSession;
158 voiceInteractor = _voiceInteractor;
Craig Mautner21d24a22014-04-23 11:45:37 -0700159 mActivities = new ArrayList<ActivityRecord>();
Martijn Coenend4a69702014-06-30 11:12:17 -0700160 setIntent(_intent, info);
Craig Mautner21d24a22014-04-23 11:45:37 -0700161 }
162
163 TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
164 String _affinity, ComponentName _realActivity, ComponentName _origActivity,
Dianne Hackborn13420f22014-07-18 15:43:56 -0700165 boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode,
166 int _taskType, int _userId,
Winson Chungffa2ec62014-07-03 15:54:42 -0700167 String _lastDescription, ArrayList<ActivityRecord> activities, long _firstActiveTime,
168 long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity,
Craig Mautnera228ae92014-07-09 05:44:55 -0700169 ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation,
170 int prevTaskId, int nextTaskId) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700171 mService = service;
Craig Mautnera228ae92014-07-09 05:44:55 -0700172 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
173 TaskPersister.IMAGE_EXTENSION;
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700174 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
Craig Mautner21d24a22014-04-23 11:45:37 -0700175 taskId = _taskId;
176 intent = _intent;
177 affinityIntent = _affinityIntent;
178 affinity = _affinity;
179 voiceSession = null;
180 voiceInteractor = null;
181 realActivity = _realActivity;
182 origActivity = _origActivity;
183 rootWasReset = _rootWasReset;
Dianne Hackborn13420f22014-07-18 15:43:56 -0700184 autoRemoveRecents = _autoRemoveRecents;
Craig Mautner21d24a22014-04-23 11:45:37 -0700185 askedCompatMode = _askedCompatMode;
186 taskType = _taskType;
Craig Mautner84984fa2014-06-19 11:19:20 -0700187 mTaskToReturnTo = HOME_ACTIVITY_TYPE;
Craig Mautner21d24a22014-04-23 11:45:37 -0700188 userId = _userId;
Winson Chungffa2ec62014-07-03 15:54:42 -0700189 firstActiveTime = _firstActiveTime;
Winson Chungf1fbd772014-06-24 18:06:58 -0700190 lastActiveTime = _lastActiveTime;
Craig Mautner21d24a22014-04-23 11:45:37 -0700191 lastDescription = _lastDescription;
192 mActivities = activities;
193 mLastTimeMoved = lastTimeMoved;
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700194 mNeverRelinquishIdentity = neverRelinquishIdentity;
Winson Chung2cb86c72014-06-25 12:03:30 -0700195 lastTaskDescription = _lastTaskDescription;
Craig Mautnera228ae92014-07-09 05:44:55 -0700196 mAffiliatedTaskId = taskAffiliation;
197 mPrevAffiliateTaskId = prevTaskId;
198 mNextAffiliateTaskId = nextTaskId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 }
200
201 void touchActiveTime() {
202 lastActiveTime = android.os.SystemClock.elapsedRealtime();
Winson Chungffa2ec62014-07-03 15:54:42 -0700203 if (firstActiveTime == 0) {
204 firstActiveTime = lastActiveTime;
205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 long getInactiveDuration() {
209 return android.os.SystemClock.elapsedRealtime() - lastActiveTime;
210 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 void setIntent(Intent _intent, ActivityInfo info) {
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700213 if (intent == null) {
214 mNeverRelinquishIdentity =
215 (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
216 } else if (mNeverRelinquishIdentity) {
217 return;
218 }
219
220 affinity = info.taskAffinity;
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700221 stringName = null;
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 if (info.targetActivity == null) {
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800224 if (_intent != null) {
225 // If this Intent has a selector, we want to clear it for the
226 // recent task since it is not relevant if the user later wants
227 // to re-launch the app.
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700228 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800229 _intent = new Intent(_intent);
230 _intent.setSelector(null);
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700231 _intent.setSourceBounds(null);
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800232 }
233 }
Dianne Hackborn7f96b792012-05-29 18:46:45 -0700234 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
235 "Setting Intent of " + this + " to " + _intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 intent = _intent;
237 realActivity = _intent != null ? _intent.getComponent() : null;
238 origActivity = null;
239 } else {
240 ComponentName targetComponent = new ComponentName(
241 info.packageName, info.targetActivity);
242 if (_intent != null) {
243 Intent targetIntent = new Intent(_intent);
244 targetIntent.setComponent(targetComponent);
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800245 targetIntent.setSelector(null);
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700246 targetIntent.setSourceBounds(null);
Dianne Hackborn7f96b792012-05-29 18:46:45 -0700247 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
248 "Setting Intent of " + this + " to target " + targetIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 intent = targetIntent;
250 realActivity = targetComponent;
251 origActivity = _intent.getComponent();
252 } else {
253 intent = null;
254 realActivity = targetComponent;
255 origActivity = new ComponentName(info.packageName, info.name);
256 }
257 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 if (intent != null &&
260 (intent.getFlags()&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
261 // Once we are set to an Intent with this flag, we count this
262 // task as having a true root activity.
263 rootWasReset = true;
264 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700265
Dianne Hackborn09233282014-04-30 11:33:59 -0700266 userId = UserHandle.getUserId(info.applicationInfo.uid);
267 creatorUid = info.applicationInfo.uid;
Craig Mautner41db4a72014-05-07 17:20:56 -0700268 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
Dianne Hackborn13420f22014-07-18 15:43:56 -0700269 // If the activity itself has requested auto-remove, then just always do it.
270 autoRemoveRecents = true;
271 } else if ((intent.getFlags()&(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
272 |Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) {
273 // If the caller has not asked for the document to be retained, then we may
274 // want to turn on auto-remove, depending on whether the target has set its
275 // own document launch mode.
276 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
277 autoRemoveRecents = false;
278 } else {
279 autoRemoveRecents = true;
280 }
281 } else {
282 autoRemoveRecents = false;
Craig Mautner41db4a72014-05-07 17:20:56 -0700283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800285
Craig Mautner84984fa2014-06-19 11:19:20 -0700286 void setTaskToReturnTo(int taskToReturnTo) {
287 mTaskToReturnTo = taskToReturnTo;
288 }
289
290 int getTaskToReturnTo() {
291 return mTaskToReturnTo;
292 }
293
Craig Mautnera228ae92014-07-09 05:44:55 -0700294 void setPrevAffiliate(TaskRecord prevAffiliate) {
295 mPrevAffiliate = prevAffiliate;
296 mPrevAffiliateTaskId = prevAffiliate == null ? -1 : prevAffiliate.taskId;
297 }
298
299 void setNextAffiliate(TaskRecord nextAffiliate) {
300 mNextAffiliate = nextAffiliate;
301 mNextAffiliateTaskId = nextAffiliate == null ? -1 : nextAffiliate.taskId;
302 }
303
304 // Close up recents linked list.
305 void closeRecentsChain() {
306 if (mPrevAffiliate != null) {
307 mPrevAffiliate.setNextAffiliate(mNextAffiliate);
308 }
309 if (mNextAffiliate != null) {
310 mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
311 }
312 setPrevAffiliate(null);
313 setNextAffiliate(null);
314 }
315
316 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
317 closeRecentsChain();
318 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
319 // Find the end
320 while (taskToAffiliateWith.mNextAffiliate != null) {
321 final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
322 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
323 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
324 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
325 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
326 nextRecents.setPrevAffiliate(null);
327 }
328 taskToAffiliateWith.setNextAffiliate(null);
329 break;
330 }
331 taskToAffiliateWith = nextRecents;
332 }
333 taskToAffiliateWith.setNextAffiliate(this);
334 setPrevAffiliate(taskToAffiliateWith);
335 setNextAffiliate(null);
336 }
337
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700338 void setLastThumbnail(Bitmap thumbnail) {
339 mLastThumbnail = thumbnail;
340 if (thumbnail == null) {
341 if (mLastThumbnailFile != null) {
342 mLastThumbnailFile.delete();
343 }
344 } else {
345 mService.mTaskPersister.saveImage(thumbnail, mFilename);
346 }
347 }
348
349 void getLastThumbnail(TaskThumbnail thumbs) {
350 thumbs.mainThumbnail = mLastThumbnail;
351 thumbs.thumbnailFileDescriptor = null;
352 if (mLastThumbnailFile.exists()) {
353 try {
354 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
355 ParcelFileDescriptor.MODE_READ_ONLY);
356 } catch (IOException e) {
Dianne Hackborn9844d292013-10-04 16:44:22 -0700357 }
358 }
359 }
360
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700361 void freeLastThumbnail() {
362 mLastThumbnail = null;
363 }
364
365 void disposeThumbnail() {
366 mLastThumbnail = null;
367 lastDescription = null;
368 }
369
Winson Chung1147c402014-05-14 11:05:00 -0700370 /** Returns the intent for the root activity for this task */
371 Intent getBaseIntent() {
372 return intent != null ? intent : affinityIntent;
373 }
374
Winson Chung3b3f4642014-04-22 10:08:18 -0700375 /** Returns the first non-finishing activity from the root. */
376 ActivityRecord getRootActivity() {
377 for (int i = 0; i < mActivities.size(); i++) {
378 final ActivityRecord r = mActivities.get(i);
379 if (r.finishing) {
380 continue;
381 }
382 return r;
383 }
384 return null;
385 }
386
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800387 ActivityRecord getTopActivity() {
388 for (int i = mActivities.size() - 1; i >= 0; --i) {
389 final ActivityRecord r = mActivities.get(i);
390 if (r.finishing) {
391 continue;
392 }
393 return r;
394 }
395 return null;
396 }
397
Craig Mautner6b74cb52013-09-27 17:02:21 -0700398 ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
399 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
400 ActivityRecord r = mActivities.get(activityNdx);
Amith Yamasani734983f2014-03-04 16:48:05 -0800401 if (!r.finishing && r != notTop && stack.okToShowLocked(r)) {
Craig Mautner6b74cb52013-09-27 17:02:21 -0700402 return r;
403 }
404 }
405 return null;
406 }
407
Craig Mautner3b475fe2013-12-16 15:58:31 -0800408 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
409 final void setFrontOfTask() {
410 boolean foundFront = false;
411 final int numActivities = mActivities.size();
Craig Mautner704e40b2013-12-18 16:43:51 -0800412 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
Craig Mautner3b475fe2013-12-16 15:58:31 -0800413 final ActivityRecord r = mActivities.get(activityNdx);
414 if (foundFront || r.finishing) {
415 r.frontOfTask = false;
416 } else {
417 r.frontOfTask = true;
418 // Set frontOfTask false for every following activity.
419 foundFront = true;
420 }
421 }
Craig Mautner9587ee02014-06-23 15:00:10 +0000422 if (!foundFront && numActivities > 0) {
423 // All activities of this task are finishing. As we ought to have a frontOfTask
424 // activity, make the bottom activity front.
425 mActivities.get(0).frontOfTask = true;
426 }
Craig Mautner3b475fe2013-12-16 15:58:31 -0800427 }
428
Craig Mautnerde4ef022013-04-07 19:01:33 -0700429 /**
Craig Mautner3b475fe2013-12-16 15:58:31 -0800430 * Reorder the history stack so that the passed activity is brought to the front.
Craig Mautnerde4ef022013-04-07 19:01:33 -0700431 */
432 final void moveActivityToFrontLocked(ActivityRecord newTop) {
433 if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop
434 + " to stack at top", new RuntimeException("here").fillInStackTrace());
435
Craig Mautnerde4ef022013-04-07 19:01:33 -0700436 mActivities.remove(newTop);
437 mActivities.add(newTop);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700438 updateEffectiveIntent();
Craig Mautner3b475fe2013-12-16 15:58:31 -0800439
440 setFrontOfTask();
Craig Mautnerde4ef022013-04-07 19:01:33 -0700441 }
442
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800443 void addActivityAtBottom(ActivityRecord r) {
Craig Mautner77878772013-03-04 19:46:24 -0800444 addActivityAtIndex(0, r);
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800445 }
446
447 void addActivityToTop(ActivityRecord r) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700448 addActivityAtIndex(mActivities.size(), r);
449 }
450
451 void addActivityAtIndex(int index, ActivityRecord r) {
Craig Mautner6170f732013-04-02 13:05:23 -0700452 // 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 -0800453 if (!mActivities.remove(r) && r.fullscreen) {
454 // Was not previously in list.
455 numFullscreen++;
456 }
Craig Mautner2c1faed2013-07-23 12:56:02 -0700457 // Only set this based on the first activity
458 if (mActivities.isEmpty()) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700459 taskType = r.mActivityType;
460 isPersistable = r.isPersistable();
Craig Mautnerffcfcaa2014-06-05 09:54:38 -0700461 // Clamp to [1, 100].
462 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 100);
Craig Mautner2c1faed2013-07-23 12:56:02 -0700463 } else {
464 // Otherwise make all added activities match this one.
Craig Mautner21d24a22014-04-23 11:45:37 -0700465 r.mActivityType = taskType;
Craig Mautner78733002013-06-10 13:54:49 -0700466 }
Craig Mautner77878772013-03-04 19:46:24 -0800467 mActivities.add(index, r);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700468 updateEffectiveIntent();
Craig Mautner21d24a22014-04-23 11:45:37 -0700469 if (r.isPersistable()) {
470 mService.notifyTaskPersisterLocked(this, false);
471 }
Craig Mautner77878772013-03-04 19:46:24 -0800472 }
473
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800474 /** @return true if this was the last activity in the task */
475 boolean removeActivity(ActivityRecord r) {
476 if (mActivities.remove(r) && r.fullscreen) {
477 // Was previously in list.
478 numFullscreen--;
479 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700480 if (r.isPersistable()) {
481 mService.notifyTaskPersisterLocked(this, false);
482 }
Craig Mautner41326202014-06-20 14:38:21 -0700483 if (mActivities.isEmpty()) {
Craig Mautner5afcd4d2014-06-21 18:11:33 -0700484 return !mReuseTask;
Craig Mautner41326202014-06-20 14:38:21 -0700485 }
486 updateEffectiveIntent();
487 return false;
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800488 }
489
Craig Mautner41db4a72014-05-07 17:20:56 -0700490 boolean autoRemoveFromRecents() {
Dianne Hackbornd38aed82014-06-10 21:36:35 -0700491 // We will automatically remove the task either if it has explicitly asked for
492 // this, or it is empty and has never contained an activity that got shown to
493 // the user.
Dianne Hackborn13420f22014-07-18 15:43:56 -0700494 return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible);
Craig Mautner41db4a72014-05-07 17:20:56 -0700495 }
496
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700497 /**
498 * Completely remove all activities associated with an existing
499 * task starting at a specified index.
500 */
501 final void performClearTaskAtIndexLocked(int activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700502 int numActivities = mActivities.size();
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700503 for ( ; activityNdx < numActivities; ++activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700504 final ActivityRecord r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700505 if (r.finishing) {
506 continue;
507 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700508 if (stack == null) {
509 // Task was restored from persistent storage.
510 r.takeFromHistory();
511 mActivities.remove(activityNdx);
512 --activityNdx;
513 --numActivities;
514 } else if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
515 false)) {
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700516 --activityNdx;
517 --numActivities;
518 }
519 }
520 }
521
522 /**
523 * Completely remove all activities associated with an existing task.
524 */
525 final void performClearTaskLocked() {
Craig Mautner362449a2014-06-20 14:04:39 -0700526 mReuseTask = true;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700527 performClearTaskAtIndexLocked(0);
Craig Mautner362449a2014-06-20 14:04:39 -0700528 mReuseTask = false;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700529 }
530
531 /**
532 * Perform clear operation as requested by
533 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
534 * stack to the given task, then look for
535 * an instance of that activity in the stack and, if found, finish all
536 * activities on top of it and return the instance.
537 *
538 * @param newR Description of the new activity being started.
539 * @return Returns the old activity that should be continued to be used,
540 * or null if none was found.
541 */
542 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700543 int numActivities = mActivities.size();
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700544 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700545 ActivityRecord r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700546 if (r.finishing) {
547 continue;
548 }
549 if (r.realActivity.equals(newR.realActivity)) {
550 // Here it is! Now finish everything in front...
Craig Mautner1602ec22013-05-12 10:24:27 -0700551 final ActivityRecord ret = r;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700552
553 for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700554 r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700555 if (r.finishing) {
556 continue;
557 }
558 ActivityOptions opts = r.takeOptionsLocked();
559 if (opts != null) {
560 ret.updateOptionsLocked(opts);
561 }
562 if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
563 false)) {
564 --activityNdx;
565 --numActivities;
566 }
567 }
568
569 // Finally, if this is a normal launch mode (that is, not
570 // expecting onNewIntent()), then we will finish the current
571 // instance of the activity so a new fresh one can be started.
572 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
573 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
574 if (!ret.finishing) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700575 stack.finishActivityLocked(ret, Activity.RESULT_CANCELED, null,
576 "clear", false);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700577 return null;
578 }
579 }
580
581 return ret;
582 }
583 }
584
585 return null;
586 }
587
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700588 public TaskThumbnail getTaskThumbnailLocked() {
Craig Mautner21d24a22014-04-23 11:45:37 -0700589 if (stack != null) {
590 final ActivityRecord resumedActivity = stack.mResumedActivity;
591 if (resumedActivity != null && resumedActivity.task == this) {
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700592 final Bitmap thumbnail = stack.screenshotActivities(resumedActivity);
593 setLastThumbnail(thumbnail);
Craig Mautner21d24a22014-04-23 11:45:37 -0700594 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700595 }
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700596 final TaskThumbnail taskThumbnail = new TaskThumbnail();
597 getLastThumbnail(taskThumbnail);
598 return taskThumbnail;
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700599 }
600
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700601 public void removeTaskActivitiesLocked() {
602 // Just remove the entire task.
603 performClearTaskAtIndexLocked(0);
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700604 }
605
Craig Mautnera82aa092013-09-13 15:34:08 -0700606 boolean isHomeTask() {
Craig Mautner84984fa2014-06-19 11:19:20 -0700607 return taskType == HOME_ACTIVITY_TYPE;
Craig Mautnera82aa092013-09-13 15:34:08 -0700608 }
609
Craig Mautner86d67a42013-05-14 10:34:38 -0700610 boolean isApplicationTask() {
Craig Mautner84984fa2014-06-19 11:19:20 -0700611 return taskType == APPLICATION_ACTIVITY_TYPE;
612 }
613
614 boolean isOverHomeStack() {
615 return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
Craig Mautner1602ec22013-05-12 10:24:27 -0700616 }
617
Craig Mautner525f3d92013-05-07 14:01:50 -0700618 /**
619 * Find the activity in the history stack within the given task. Returns
620 * the index within the history at which it's found, or < 0 if not found.
621 */
622 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
623 final ComponentName realActivity = r.realActivity;
624 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
625 ActivityRecord candidate = mActivities.get(activityNdx);
626 if (candidate.finishing) {
627 continue;
628 }
629 if (candidate.realActivity.equals(realActivity)) {
630 return candidate;
631 }
632 }
633 return null;
634 }
635
Winson Chunga449dc02014-05-16 11:15:04 -0700636 /** Updates the last task description values. */
637 void updateTaskDescription() {
638 // Traverse upwards looking for any break between main task activities and
639 // utility activities.
640 int activityNdx;
641 final int numActivities = mActivities.size();
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700642 final boolean relinquish = numActivities == 0 ? false :
643 (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0;
Winson Chunga449dc02014-05-16 11:15:04 -0700644 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
Craig Mautner21d24a22014-04-23 11:45:37 -0700645 ++activityNdx) {
Winson Chunga449dc02014-05-16 11:15:04 -0700646 final ActivityRecord r = mActivities.get(activityNdx);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700647 if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
648 // This will be the top activity for determining taskDescription. Pre-inc to
649 // overcome initial decrement below.
650 ++activityNdx;
651 break;
652 }
Winson Chunga449dc02014-05-16 11:15:04 -0700653 if (r.intent != null &&
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700654 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
Winson Chunga449dc02014-05-16 11:15:04 -0700655 break;
656 }
657 }
658 if (activityNdx > 0) {
659 // Traverse downwards starting below break looking for set label, icon.
660 // Note that if there are activities in the task but none of them set the
661 // recent activity values, then we do not fall back to the last set
662 // values in the TaskRecord.
663 String label = null;
664 Bitmap icon = null;
665 int colorPrimary = 0;
666 for (--activityNdx; activityNdx >= 0; --activityNdx) {
667 final ActivityRecord r = mActivities.get(activityNdx);
668 if (r.taskDescription != null) {
669 if (label == null) {
670 label = r.taskDescription.getLabel();
671 }
672 if (icon == null) {
673 icon = r.taskDescription.getIcon();
674 }
675 if (colorPrimary == 0) {
676 colorPrimary = r.taskDescription.getPrimaryColor();
677
678 }
679 }
680 }
681 lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary);
682 }
683 }
684
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700685 int findEffectiveRootIndex() {
686 int activityNdx;
687 final int topActivityNdx = mActivities.size() - 1;
688 for (activityNdx = 0; activityNdx < topActivityNdx; ++activityNdx) {
689 final ActivityRecord r = mActivities.get(activityNdx);
690 if (r.finishing) {
691 continue;
692 }
693 if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
694 break;
695 }
696 }
697 return activityNdx;
698 }
699
700 void updateEffectiveIntent() {
701 final int effectiveRootIndex = findEffectiveRootIndex();
702 final ActivityRecord r = mActivities.get(effectiveRootIndex);
703 setIntent(r.intent, r.info);
704 }
705
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700706 void saveTaskDescription(ActivityManager.TaskDescription taskDescription,
707 String iconFilename, XmlSerializer out) throws IOException {
708 if (taskDescription != null) {
709 final String label = taskDescription.getLabel();
710 if (label != null) {
711 out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label);
712 }
713 final int colorPrimary = taskDescription.getPrimaryColor();
714 if (colorPrimary != 0) {
715 out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary));
716 }
717 final Bitmap icon = taskDescription.getIcon();
718 if (icon != null) {
719 mService.mTaskPersister.saveImage(icon, iconFilename);
720 }
721 }
722 }
723
724 static boolean readTaskDescriptionAttribute(ActivityManager.TaskDescription taskDescription,
725 String attrName, String attrValue) {
726 if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
727 taskDescription.setLabel(attrValue);
728 } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
729 taskDescription.setPrimaryColor((int) Long.parseLong(attrValue, 16));
730 } else {
731 return false;
732 }
733 return true;
734 }
735
Craig Mautner21d24a22014-04-23 11:45:37 -0700736 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
737 Slog.i(TAG, "Saving task=" + this);
738
739 out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
740 if (realActivity != null) {
741 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
742 }
743 if (origActivity != null) {
744 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
745 }
746 if (affinity != null) {
747 out.attribute(null, ATTR_AFFINITY, affinity);
748 }
749 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
Dianne Hackborn13420f22014-07-18 15:43:56 -0700750 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
Craig Mautner21d24a22014-04-23 11:45:37 -0700751 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
752 out.attribute(null, ATTR_USERID, String.valueOf(userId));
753 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
Winson Chungffa2ec62014-07-03 15:54:42 -0700754 out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
Winson Chungf1fbd772014-06-24 18:06:58 -0700755 out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime));
Craig Mautner21d24a22014-04-23 11:45:37 -0700756 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700757 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
Craig Mautner21d24a22014-04-23 11:45:37 -0700758 if (lastDescription != null) {
759 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
760 }
Winson Chung2cb86c72014-06-25 12:03:30 -0700761 if (lastTaskDescription != null) {
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700762 saveTaskDescription(lastTaskDescription, String.valueOf(taskId) +
Winson Chung2cb86c72014-06-25 12:03:30 -0700763 LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime, out);
764 }
Craig Mautnera228ae92014-07-09 05:44:55 -0700765 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
766 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
767 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
Winson Chung2cb86c72014-06-25 12:03:30 -0700768
Craig Mautner21d24a22014-04-23 11:45:37 -0700769 if (affinityIntent != null) {
770 out.startTag(null, TAG_AFFINITYINTENT);
771 affinityIntent.saveToXml(out);
772 out.endTag(null, TAG_AFFINITYINTENT);
773 }
774
775 out.startTag(null, TAG_INTENT);
776 intent.saveToXml(out);
777 out.endTag(null, TAG_INTENT);
778
779 final ArrayList<ActivityRecord> activities = mActivities;
780 final int numActivities = activities.size();
781 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
782 final ActivityRecord r = activities.get(activityNdx);
Craig Mautner43e52ed2014-06-16 17:18:52 -0700783 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
784 ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) &&
785 activityNdx > 0) {
Craig Mautnerf357c0c2014-06-09 09:23:27 -0700786 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
Craig Mautner21d24a22014-04-23 11:45:37 -0700787 break;
788 }
789 out.startTag(null, TAG_ACTIVITY);
790 r.saveToXml(out);
791 out.endTag(null, TAG_ACTIVITY);
792 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700793 }
794
795 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
796 throws IOException, XmlPullParserException {
797 Intent intent = null;
798 Intent affinityIntent = null;
799 ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
800 ComponentName realActivity = null;
801 ComponentName origActivity = null;
802 String affinity = null;
803 boolean rootHasReset = false;
Dianne Hackborn13420f22014-07-18 15:43:56 -0700804 boolean autoRemoveRecents = false;
Craig Mautner21d24a22014-04-23 11:45:37 -0700805 boolean askedCompatMode = false;
806 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
Craig Mautner21d24a22014-04-23 11:45:37 -0700807 int userId = 0;
808 String lastDescription = null;
Winson Chungffa2ec62014-07-03 15:54:42 -0700809 long firstActiveTime = -1;
Winson Chung2cb86c72014-06-25 12:03:30 -0700810 long lastActiveTime = -1;
Craig Mautner21d24a22014-04-23 11:45:37 -0700811 long lastTimeOnTop = 0;
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700812 boolean neverRelinquishIdentity = true;
Craig Mautner21d24a22014-04-23 11:45:37 -0700813 int taskId = -1;
814 final int outerDepth = in.getDepth();
Winson Chung2cb86c72014-06-25 12:03:30 -0700815 ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription();
Craig Mautnera228ae92014-07-09 05:44:55 -0700816 int taskAffiliation = -1;
817 int prevTaskId = -1;
818 int nextTaskId = -1;
Craig Mautner21d24a22014-04-23 11:45:37 -0700819
820 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
821 final String attrName = in.getAttributeName(attrNdx);
822 final String attrValue = in.getAttributeValue(attrNdx);
823 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
824 attrName + " value=" + attrValue);
825 if (ATTR_TASKID.equals(attrName)) {
826 taskId = Integer.valueOf(attrValue);
827 } else if (ATTR_REALACTIVITY.equals(attrName)) {
828 realActivity = ComponentName.unflattenFromString(attrValue);
829 } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
830 origActivity = ComponentName.unflattenFromString(attrValue);
831 } else if (ATTR_AFFINITY.equals(attrName)) {
832 affinity = attrValue;
833 } else if (ATTR_ROOTHASRESET.equals(attrName)) {
834 rootHasReset = Boolean.valueOf(attrValue);
Dianne Hackborn13420f22014-07-18 15:43:56 -0700835 } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) {
836 autoRemoveRecents = Boolean.valueOf(attrValue);
Craig Mautner21d24a22014-04-23 11:45:37 -0700837 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
838 askedCompatMode = Boolean.valueOf(attrValue);
839 } else if (ATTR_USERID.equals(attrName)) {
840 userId = Integer.valueOf(attrValue);
841 } else if (ATTR_TASKTYPE.equals(attrName)) {
842 taskType = Integer.valueOf(attrValue);
Winson Chungffa2ec62014-07-03 15:54:42 -0700843 } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) {
844 firstActiveTime = Long.valueOf(attrValue);
Winson Chungf1fbd772014-06-24 18:06:58 -0700845 } else if (ATTR_LASTACTIVETIME.equals(attrName)) {
846 lastActiveTime = Long.valueOf(attrValue);
Craig Mautner21d24a22014-04-23 11:45:37 -0700847 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
848 lastDescription = attrValue;
849 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
850 lastTimeOnTop = Long.valueOf(attrValue);
Craig Mautner9d4e9bc2014-06-18 18:34:56 -0700851 } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
852 neverRelinquishIdentity = Boolean.valueOf(attrValue);
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700853 } else if (readTaskDescriptionAttribute(taskDescription, attrName, attrValue)) {
Winson Chung2cb86c72014-06-25 12:03:30 -0700854 // Completed in TaskPersister.readTaskDescriptionAttribute()
Craig Mautnera228ae92014-07-09 05:44:55 -0700855 } else if (ATTR_TASK_AFFILIATION.equals(attrName)) {
856 taskAffiliation = Integer.valueOf(attrValue);
857 } else if (ATTR_PREV_AFFILIATION.equals(attrName)) {
858 prevTaskId = Integer.valueOf(attrValue);
859 } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) {
860 nextTaskId = Integer.valueOf(attrValue);
Craig Mautner21d24a22014-04-23 11:45:37 -0700861 } else {
862 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
863 }
864 }
865
866 int event;
867 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
868 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
869 if (event == XmlPullParser.START_TAG) {
870 final String name = in.getName();
871 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
872 name);
873 if (TAG_AFFINITYINTENT.equals(name)) {
874 affinityIntent = Intent.restoreFromXml(in);
875 } else if (TAG_INTENT.equals(name)) {
876 intent = Intent.restoreFromXml(in);
877 } else if (TAG_ACTIVITY.equals(name)) {
878 ActivityRecord activity =
879 ActivityRecord.restoreFromXml(in, taskId, stackSupervisor);
880 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
881 activity);
882 if (activity != null) {
883 activities.add(activity);
884 }
885 } else {
886 Slog.e(TAG, "restoreTask: Unexpected name=" + name);
887 XmlUtils.skipCurrentTag(in);
888 }
889 }
890 }
891
Winson Chung2cb86c72014-06-25 12:03:30 -0700892 if (lastActiveTime >= 0) {
893 taskDescription.setIcon(TaskPersister.restoreImage(String.valueOf(taskId) +
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700894 LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime + TaskPersister.IMAGE_EXTENSION));
Winson Chung2cb86c72014-06-25 12:03:30 -0700895 }
896
Craig Mautner21d24a22014-04-23 11:45:37 -0700897 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
898 affinityIntent, affinity, realActivity, origActivity, rootHasReset,
Dianne Hackborn13420f22014-07-18 15:43:56 -0700899 autoRemoveRecents, askedCompatMode, taskType, userId, lastDescription, activities,
900 firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
901 taskDescription, taskAffiliation, prevTaskId, nextTaskId);
Craig Mautner21d24a22014-04-23 11:45:37 -0700902
903 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700904 activities.get(activityNdx).task = task;
Craig Mautner21d24a22014-04-23 11:45:37 -0700905 }
906
Craig Mautner21d24a22014-04-23 11:45:37 -0700907 Slog.i(TAG, "Restored task=" + task);
908 return task;
909 }
910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 void dump(PrintWriter pw, String prefix) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700912 if (rootWasReset || userId != 0 || numFullscreen != 0) {
913 pw.print(prefix); pw.print(" rootWasReset="); pw.print(rootWasReset);
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800914 pw.print(" userId="); pw.print(userId);
Craig Mautner21d24a22014-04-23 11:45:37 -0700915 pw.print(" taskType="); pw.print(taskType);
Craig Mautnerae7ecab2013-09-18 11:48:14 -0700916 pw.print(" numFullscreen="); pw.print(numFullscreen);
Craig Mautner84984fa2014-06-19 11:19:20 -0700917 pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700918 }
919 if (affinity != null) {
920 pw.print(prefix); pw.print("affinity="); pw.println(affinity);
921 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700922 if (voiceSession != null || voiceInteractor != null) {
923 pw.print(prefix); pw.print("VOICE: session=0x");
924 pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
925 pw.print(" interactor=0x");
926 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
927 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700928 if (intent != null) {
929 StringBuilder sb = new StringBuilder(128);
930 sb.append(prefix); sb.append("intent={");
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800931 intent.toShortString(sb, false, true, false, true);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700932 sb.append('}');
933 pw.println(sb.toString());
934 }
935 if (affinityIntent != null) {
936 StringBuilder sb = new StringBuilder(128);
937 sb.append(prefix); sb.append("affinityIntent={");
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800938 affinityIntent.toShortString(sb, false, true, false, true);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700939 sb.append('}');
940 pw.println(sb.toString());
941 }
942 if (origActivity != null) {
943 pw.print(prefix); pw.print("origActivity=");
944 pw.println(origActivity.flattenToShortString());
945 }
946 if (realActivity != null) {
947 pw.print(prefix); pw.print("realActivity=");
948 pw.println(realActivity.flattenToShortString());
949 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800950 pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700951 if (!askedCompatMode) {
952 pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
953 }
Craig Mautnerc0ffce52014-07-01 12:38:52 -0700954 pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail);
955 pw.print(" lastThumbnailFile="); pw.print(mLastThumbnailFile);
Dianne Hackborncfb9f2b2011-08-24 10:51:49 -0700956 pw.print(" lastDescription="); pw.println(lastDescription);
Dianne Hackbornd38aed82014-06-10 21:36:35 -0700957 pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
Winson Chungffa2ec62014-07-03 15:54:42 -0700958 pw.print(" firstActiveTime="); pw.print(lastActiveTime);
Dianne Hackbornd38aed82014-06-10 21:36:35 -0700959 pw.print(" lastActiveTime="); pw.print(lastActiveTime);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700960 pw.print(" (inactive for ");
961 pw.print((getInactiveDuration()/1000)); pw.println("s)");
Craig Mautnera228ae92014-07-09 05:44:55 -0700962 pw.print(prefix); pw.print("isPersistable="); pw.print(isPersistable);
963 pw.print(" affiliation="); pw.print(mAffiliatedTaskId);
964 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
965 pw.print(" nextAffiliation="); pw.println(mNextAffiliateTaskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 }
967
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800968 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700970 StringBuilder sb = new StringBuilder(128);
Craig Mautnerde4ef022013-04-07 19:01:33 -0700971 if (stringName != null) {
972 sb.append(stringName);
973 sb.append(" U=");
974 sb.append(userId);
975 sb.append(" sz=");
976 sb.append(mActivities.size());
977 sb.append('}');
978 return sb.toString();
979 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700980 sb.append("TaskRecord{");
981 sb.append(Integer.toHexString(System.identityHashCode(this)));
982 sb.append(" #");
983 sb.append(taskId);
984 if (affinity != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800985 sb.append(" A=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700986 sb.append(affinity);
987 } else if (intent != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800988 sb.append(" I=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700989 sb.append(intent.getComponent().flattenToShortString());
990 } else if (affinityIntent != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800991 sb.append(" aI=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700992 sb.append(affinityIntent.getComponent().flattenToShortString());
993 } else {
994 sb.append(" ??");
995 }
Craig Mautnerde4ef022013-04-07 19:01:33 -0700996 stringName = sb.toString();
997 return toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 }
999}