blob: 1df230e7bb68464b073ccd4b6ed25098bb72cd2c [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 Mautner0eea92c2013-05-16 13:35:39 -070020import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
Craig Mautnerde4ef022013-04-07 19:01:33 -070021
Craig Mautnerb0f7dc72013-04-01 16:34:45 -070022import android.app.Activity;
Craig Mautner9db9a0b2013-04-29 17:05:56 -070023import android.app.ActivityManager;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -070024import android.app.ActivityOptions;
Craig Mautner9db9a0b2013-04-29 17:05:56 -070025import android.app.IThumbnailRetriever;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.ComponentName;
27import android.content.Intent;
28import android.content.pm.ActivityInfo;
Craig Mautner9db9a0b2013-04-29 17:05:56 -070029import android.graphics.Bitmap;
Craig Mautner21d24a22014-04-23 11:45:37 -070030import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070031import android.os.UserHandle;
Dianne Hackborn91097de2014-04-04 18:02:06 -070032import android.service.voice.IVoiceInteractionSession;
Dianne Hackborn7f96b792012-05-29 18:46:45 -070033import android.util.Slog;
Dianne Hackborn91097de2014-04-04 18:02:06 -070034import com.android.internal.app.IVoiceInteractor;
Craig Mautner21d24a22014-04-23 11:45:37 -070035import com.android.internal.util.XmlUtils;
36import org.xmlpull.v1.XmlPullParser;
37import org.xmlpull.v1.XmlPullParserException;
38import org.xmlpull.v1.XmlSerializer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
Craig Mautner21d24a22014-04-23 11:45:37 -070040import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import java.io.PrintWriter;
Craig Mautner5d9c7be2013-02-15 14:02:56 -080042import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
Dianne Hackbornbe4e6aa2013-06-07 13:25:29 -070044final class TaskRecord extends ThumbnailHolder {
Craig Mautner21d24a22014-04-23 11:45:37 -070045 private static final String TAG_TASK = "task";
46 private static final String ATTR_TASKID = "task_id";
47 private static final String TAG_INTENT = "intent";
48 private static final String TAG_AFFINITYINTENT = "affinity_intent";
49 private static final String ATTR_REALACTIVITY = "real_activity";
50 private static final String ATTR_ORIGACTIVITY = "orig_activity";
51 private static final String TAG_ACTIVITY = "activity";
52 private static final String ATTR_AFFINITY = "affinity";
53 private static final String ATTR_ROOTHASRESET = "root_has_reset";
54 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
55 private static final String ATTR_USERID = "user_id";
56 private static final String ATTR_TASKTYPE = "task_type";
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +000057 private static final String ATTR_ONTOPOFHOME = "on_top_of_home";
Craig Mautner21d24a22014-04-23 11:45:37 -070058 private static final String ATTR_LASTDESCRIPTION = "last_description";
59 private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
60
61 private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
62
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 final int taskId; // Unique identifier for this task.
64 final String affinity; // The affinity name for this task, or null.
Dianne Hackborn91097de2014-04-04 18:02:06 -070065 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
66 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 Intent intent; // The original intent that started the task.
68 Intent affinityIntent; // Intent of affinity-moved activity that started this task.
69 ComponentName origActivity; // The non-alias activity component of the intent.
70 ComponentName realActivity; // The actual activity component that started the task.
71 int numActivities; // Current number of activities in this task.
72 long lastActiveTime; // Last time this task was active, including sleep.
73 boolean rootWasReset; // True if the intent at the root of the task had
74 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
Dianne Hackborn36cd41f2011-05-25 21:00:46 -070075 boolean askedCompatMode;// Have asked the user about compat mode for this task.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076
Dianne Hackborn1d442e02009-04-20 18:14:05 -070077 String stringName; // caching of toString() result.
Dianne Hackborn9da2d402012-03-15 13:43:08 -070078 int userId; // user for which this task was created
Dianne Hackborn09233282014-04-30 11:33:59 -070079 int creatorUid; // The app uid that originally created the task
Craig Mautner5d9c7be2013-02-15 14:02:56 -080080
81 int numFullscreen; // Number of fullscreen activities.
82
Winson Chung03a9bae2014-05-02 09:56:12 -070083 // This represents the last resolved activity values for this task
84 // NOTE: This value needs to be persisted with each task
Winson Chunga449dc02014-05-16 11:15:04 -070085 ActivityManager.TaskDescription lastTaskDescription =
86 new ActivityManager.TaskDescription();
Winson Chung03a9bae2014-05-02 09:56:12 -070087
Craig Mautnerd2328952013-03-05 12:46:26 -080088 /** List of all activities in the task arranged in history order */
Craig Mautner21d24a22014-04-23 11:45:37 -070089 final ArrayList<ActivityRecord> mActivities;
Craig Mautner5d9c7be2013-02-15 14:02:56 -080090
Craig Mautnerd2328952013-03-05 12:46:26 -080091 /** Current stack */
92 ActivityStack stack;
93
Craig Mautner2c1faed2013-07-23 12:56:02 -070094 /** Takes on same set of values as ActivityRecord.mActivityType */
Craig Mautner21d24a22014-04-23 11:45:37 -070095 int taskType;
Craig Mautner1602ec22013-05-12 10:24:27 -070096
Craig Mautner21d24a22014-04-23 11:45:37 -070097 /** Takes on same value as first root activity */
98 boolean isPersistable = false;
Craig Mautnerffcfcaa2014-06-05 09:54:38 -070099 int maxRecents;
Craig Mautner21d24a22014-04-23 11:45:37 -0700100
101 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
102 * determining the order when restoring. Sign indicates whether last task movement was to front
103 * (positive) or back (negative). Absolute value indicates time. */
104 long mLastTimeMoved = System.currentTimeMillis();
105
106 /** True if persistable, has changed, and has not yet been persisted */
107 boolean needsPersisting = false;
Craig Mautnerffcfcaa2014-06-05 09:54:38 -0700108
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000109 /** Launch the home activity when leaving this task. Will be false for tasks that are not on
110 * Display.DEFAULT_DISPLAY. */
111 boolean mOnTopOfHome = false;
Craig Mautnerae7ecab2013-09-18 11:48:14 -0700112
Craig Mautner21d24a22014-04-23 11:45:37 -0700113 final ActivityManagerService mService;
114
115 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
Dianne Hackborn91097de2014-04-04 18:02:06 -0700116 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700117 mService = service;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 taskId = _taskId;
119 affinity = info.taskAffinity;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700120 voiceSession = _voiceSession;
121 voiceInteractor = _voiceInteractor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 setIntent(_intent, info);
Craig Mautner21d24a22014-04-23 11:45:37 -0700123 mActivities = new ArrayList<ActivityRecord>();
124 }
125
126 TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
127 String _affinity, ComponentName _realActivity, ComponentName _origActivity,
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000128 boolean _rootWasReset, boolean _askedCompatMode, int _taskType, boolean _onTopOfHome,
129 int _userId, String _lastDescription, ArrayList<ActivityRecord> activities,
130 long lastTimeMoved) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700131 mService = service;
132 taskId = _taskId;
133 intent = _intent;
134 affinityIntent = _affinityIntent;
135 affinity = _affinity;
136 voiceSession = null;
137 voiceInteractor = null;
138 realActivity = _realActivity;
139 origActivity = _origActivity;
140 rootWasReset = _rootWasReset;
141 askedCompatMode = _askedCompatMode;
142 taskType = _taskType;
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000143 mOnTopOfHome = _onTopOfHome;
Craig Mautner21d24a22014-04-23 11:45:37 -0700144 userId = _userId;
145 lastDescription = _lastDescription;
146 mActivities = activities;
147 mLastTimeMoved = lastTimeMoved;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 }
149
150 void touchActiveTime() {
151 lastActiveTime = android.os.SystemClock.elapsedRealtime();
152 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 long getInactiveDuration() {
155 return android.os.SystemClock.elapsedRealtime() - lastActiveTime;
156 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 void setIntent(Intent _intent, ActivityInfo info) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700159 stringName = null;
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 if (info.targetActivity == null) {
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800162 if (_intent != null) {
163 // If this Intent has a selector, we want to clear it for the
164 // recent task since it is not relevant if the user later wants
165 // to re-launch the app.
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700166 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800167 _intent = new Intent(_intent);
168 _intent.setSelector(null);
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700169 _intent.setSourceBounds(null);
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800170 }
171 }
Dianne Hackborn7f96b792012-05-29 18:46:45 -0700172 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
173 "Setting Intent of " + this + " to " + _intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 intent = _intent;
175 realActivity = _intent != null ? _intent.getComponent() : null;
176 origActivity = null;
177 } else {
178 ComponentName targetComponent = new ComponentName(
179 info.packageName, info.targetActivity);
180 if (_intent != null) {
181 Intent targetIntent = new Intent(_intent);
182 targetIntent.setComponent(targetComponent);
Dianne Hackbornf5b86712011-12-05 17:42:41 -0800183 targetIntent.setSelector(null);
Dianne Hackbornd367ca82012-05-07 15:49:39 -0700184 targetIntent.setSourceBounds(null);
Dianne Hackborn7f96b792012-05-29 18:46:45 -0700185 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
186 "Setting Intent of " + this + " to target " + targetIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 intent = targetIntent;
188 realActivity = targetComponent;
189 origActivity = _intent.getComponent();
190 } else {
191 intent = null;
192 realActivity = targetComponent;
193 origActivity = new ComponentName(info.packageName, info.name);
194 }
195 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 if (intent != null &&
198 (intent.getFlags()&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
199 // Once we are set to an Intent with this flag, we count this
200 // task as having a true root activity.
201 rootWasReset = true;
202 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700203
Dianne Hackborn09233282014-04-30 11:33:59 -0700204 userId = UserHandle.getUserId(info.applicationInfo.uid);
205 creatorUid = info.applicationInfo.uid;
Craig Mautner41db4a72014-05-07 17:20:56 -0700206 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
207 intent.addFlags(Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800210
Dianne Hackborn9844d292013-10-04 16:44:22 -0700211 void disposeThumbnail() {
212 super.disposeThumbnail();
213 for (int i=mActivities.size()-1; i>=0; i--) {
214 ThumbnailHolder thumb = mActivities.get(i).thumbHolder;
215 if (thumb != this) {
216 thumb.disposeThumbnail();
217 }
218 }
219 }
220
Winson Chung1147c402014-05-14 11:05:00 -0700221 /** Returns the intent for the root activity for this task */
222 Intent getBaseIntent() {
223 return intent != null ? intent : affinityIntent;
224 }
225
Winson Chung3b3f4642014-04-22 10:08:18 -0700226 /** Returns the first non-finishing activity from the root. */
227 ActivityRecord getRootActivity() {
228 for (int i = 0; i < mActivities.size(); i++) {
229 final ActivityRecord r = mActivities.get(i);
230 if (r.finishing) {
231 continue;
232 }
233 return r;
234 }
235 return null;
236 }
237
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800238 ActivityRecord getTopActivity() {
239 for (int i = mActivities.size() - 1; i >= 0; --i) {
240 final ActivityRecord r = mActivities.get(i);
241 if (r.finishing) {
242 continue;
243 }
244 return r;
245 }
246 return null;
247 }
248
Craig Mautner6b74cb52013-09-27 17:02:21 -0700249 ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
250 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
251 ActivityRecord r = mActivities.get(activityNdx);
Amith Yamasani734983f2014-03-04 16:48:05 -0800252 if (!r.finishing && r != notTop && stack.okToShowLocked(r)) {
Craig Mautner6b74cb52013-09-27 17:02:21 -0700253 return r;
254 }
255 }
256 return null;
257 }
258
Craig Mautner3b475fe2013-12-16 15:58:31 -0800259 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
260 final void setFrontOfTask() {
261 boolean foundFront = false;
262 final int numActivities = mActivities.size();
Craig Mautner704e40b2013-12-18 16:43:51 -0800263 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
Craig Mautner3b475fe2013-12-16 15:58:31 -0800264 final ActivityRecord r = mActivities.get(activityNdx);
265 if (foundFront || r.finishing) {
266 r.frontOfTask = false;
267 } else {
268 r.frontOfTask = true;
269 // Set frontOfTask false for every following activity.
270 foundFront = true;
271 }
272 }
273 }
274
Craig Mautnerde4ef022013-04-07 19:01:33 -0700275 /**
Craig Mautner3b475fe2013-12-16 15:58:31 -0800276 * Reorder the history stack so that the passed activity is brought to the front.
Craig Mautnerde4ef022013-04-07 19:01:33 -0700277 */
278 final void moveActivityToFrontLocked(ActivityRecord newTop) {
279 if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop
280 + " to stack at top", new RuntimeException("here").fillInStackTrace());
281
Craig Mautnerde4ef022013-04-07 19:01:33 -0700282 mActivities.remove(newTop);
283 mActivities.add(newTop);
Craig Mautner3b475fe2013-12-16 15:58:31 -0800284
285 setFrontOfTask();
Craig Mautnerde4ef022013-04-07 19:01:33 -0700286 }
287
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800288 void addActivityAtBottom(ActivityRecord r) {
Craig Mautner77878772013-03-04 19:46:24 -0800289 addActivityAtIndex(0, r);
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800290 }
291
292 void addActivityToTop(ActivityRecord r) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700293 addActivityAtIndex(mActivities.size(), r);
294 }
295
296 void addActivityAtIndex(int index, ActivityRecord r) {
Craig Mautner6170f732013-04-02 13:05:23 -0700297 // 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 -0800298 if (!mActivities.remove(r) && r.fullscreen) {
299 // Was not previously in list.
300 numFullscreen++;
301 }
Craig Mautner2c1faed2013-07-23 12:56:02 -0700302 // Only set this based on the first activity
303 if (mActivities.isEmpty()) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700304 taskType = r.mActivityType;
305 isPersistable = r.isPersistable();
Craig Mautnerffcfcaa2014-06-05 09:54:38 -0700306 // Clamp to [1, 100].
307 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 100);
Craig Mautner2c1faed2013-07-23 12:56:02 -0700308 } else {
309 // Otherwise make all added activities match this one.
Craig Mautner21d24a22014-04-23 11:45:37 -0700310 r.mActivityType = taskType;
Craig Mautner78733002013-06-10 13:54:49 -0700311 }
Craig Mautner77878772013-03-04 19:46:24 -0800312 mActivities.add(index, r);
Craig Mautner21d24a22014-04-23 11:45:37 -0700313 if (r.isPersistable()) {
314 mService.notifyTaskPersisterLocked(this, false);
315 }
Craig Mautner77878772013-03-04 19:46:24 -0800316 }
317
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800318 /** @return true if this was the last activity in the task */
319 boolean removeActivity(ActivityRecord r) {
320 if (mActivities.remove(r) && r.fullscreen) {
321 // Was previously in list.
322 numFullscreen--;
323 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700324 if (r.isPersistable()) {
325 mService.notifyTaskPersisterLocked(this, false);
326 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800327 return mActivities.size() == 0;
328 }
329
Craig Mautner41db4a72014-05-07 17:20:56 -0700330 boolean autoRemoveFromRecents() {
331 return intent != null &&
332 (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0;
333 }
334
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700335 /**
336 * Completely remove all activities associated with an existing
337 * task starting at a specified index.
338 */
339 final void performClearTaskAtIndexLocked(int activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700340 int numActivities = mActivities.size();
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700341 for ( ; activityNdx < numActivities; ++activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700342 final ActivityRecord r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700343 if (r.finishing) {
344 continue;
345 }
Craig Mautner21d24a22014-04-23 11:45:37 -0700346 if (stack == null) {
347 // Task was restored from persistent storage.
348 r.takeFromHistory();
349 mActivities.remove(activityNdx);
350 --activityNdx;
351 --numActivities;
352 } else if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
353 false)) {
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700354 --activityNdx;
355 --numActivities;
356 }
357 }
358 }
359
360 /**
361 * Completely remove all activities associated with an existing task.
362 */
363 final void performClearTaskLocked() {
364 performClearTaskAtIndexLocked(0);
365 }
366
367 /**
368 * Perform clear operation as requested by
369 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
370 * stack to the given task, then look for
371 * an instance of that activity in the stack and, if found, finish all
372 * activities on top of it and return the instance.
373 *
374 * @param newR Description of the new activity being started.
375 * @return Returns the old activity that should be continued to be used,
376 * or null if none was found.
377 */
378 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700379 int numActivities = mActivities.size();
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700380 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700381 ActivityRecord r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700382 if (r.finishing) {
383 continue;
384 }
385 if (r.realActivity.equals(newR.realActivity)) {
386 // Here it is! Now finish everything in front...
Craig Mautner1602ec22013-05-12 10:24:27 -0700387 final ActivityRecord ret = r;
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700388
389 for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700390 r = mActivities.get(activityNdx);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700391 if (r.finishing) {
392 continue;
393 }
394 ActivityOptions opts = r.takeOptionsLocked();
395 if (opts != null) {
396 ret.updateOptionsLocked(opts);
397 }
398 if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
399 false)) {
400 --activityNdx;
401 --numActivities;
402 }
403 }
404
405 // Finally, if this is a normal launch mode (that is, not
406 // expecting onNewIntent()), then we will finish the current
407 // instance of the activity so a new fresh one can be started.
408 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
409 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
410 if (!ret.finishing) {
Craig Mautner1602ec22013-05-12 10:24:27 -0700411 stack.finishActivityLocked(ret, Activity.RESULT_CANCELED, null,
412 "clear", false);
Craig Mautnerb0f7dc72013-04-01 16:34:45 -0700413 return null;
414 }
415 }
416
417 return ret;
418 }
419 }
420
421 return null;
422 }
423
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700424 public ActivityManager.TaskThumbnails getTaskThumbnailsLocked() {
Winson Chung3b3f4642014-04-22 10:08:18 -0700425 TaskAccessInfo info = getTaskAccessInfoLocked();
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700426 final ActivityRecord resumedActivity = stack.mResumedActivity;
427 if (resumedActivity != null && resumedActivity.thumbHolder == this) {
428 info.mainThumbnail = stack.screenshotActivities(resumedActivity);
429 }
430 if (info.mainThumbnail == null) {
431 info.mainThumbnail = lastThumbnail;
432 }
433 return info;
434 }
435
436 public Bitmap getTaskTopThumbnailLocked() {
Craig Mautner21d24a22014-04-23 11:45:37 -0700437 if (stack != null) {
438 final ActivityRecord resumedActivity = stack.mResumedActivity;
439 if (resumedActivity != null && resumedActivity.task == this) {
440 // This task is the current resumed task, we just need to take
441 // a screenshot of it and return that.
442 return stack.screenshotActivities(resumedActivity);
443 }
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700444 }
445 // Return the information about the task, to figure out the top
446 // thumbnail to return.
Winson Chung3b3f4642014-04-22 10:08:18 -0700447 TaskAccessInfo info = getTaskAccessInfoLocked();
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700448 if (info.numSubThumbbails <= 0) {
449 return info.mainThumbnail != null ? info.mainThumbnail : lastThumbnail;
450 }
451 return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
452 }
453
454 public ActivityRecord removeTaskActivitiesLocked(int subTaskIndex,
455 boolean taskRequired) {
Winson Chung3b3f4642014-04-22 10:08:18 -0700456 TaskAccessInfo info = getTaskAccessInfoLocked();
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700457 if (info.root == null) {
458 if (taskRequired) {
459 Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
460 }
461 return null;
462 }
463
464 if (subTaskIndex < 0) {
465 // Just remove the entire task.
466 performClearTaskAtIndexLocked(info.rootIndex);
467 return info.root;
468 }
469
470 if (subTaskIndex >= info.subtasks.size()) {
471 if (taskRequired) {
472 Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex);
473 }
474 return null;
475 }
476
477 // Remove all of this task's activities starting at the sub task.
478 TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex);
479 performClearTaskAtIndexLocked(subtask.index);
480 return subtask.activity;
481 }
482
Craig Mautnera82aa092013-09-13 15:34:08 -0700483 boolean isHomeTask() {
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000484 return taskType == ActivityRecord.HOME_ACTIVITY_TYPE;
Craig Mautnera82aa092013-09-13 15:34:08 -0700485 }
486
Craig Mautner86d67a42013-05-14 10:34:38 -0700487 boolean isApplicationTask() {
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000488 return taskType == ActivityRecord.APPLICATION_ACTIVITY_TYPE;
Craig Mautner1602ec22013-05-12 10:24:27 -0700489 }
490
Winson Chung3b3f4642014-04-22 10:08:18 -0700491 public TaskAccessInfo getTaskAccessInfoLocked() {
Craig Mautner9db9a0b2013-04-29 17:05:56 -0700492 final TaskAccessInfo thumbs = new TaskAccessInfo();
493 // How many different sub-thumbnails?
494 final int NA = mActivities.size();
495 int j = 0;
496 ThumbnailHolder holder = null;
497 while (j < NA) {
498 ActivityRecord ar = mActivities.get(j);
499 if (!ar.finishing) {
500 thumbs.root = ar;
501 thumbs.rootIndex = j;
502 holder = ar.thumbHolder;
503 if (holder != null) {
504 thumbs.mainThumbnail = holder.lastThumbnail;
505 }
506 j++;
507 break;
508 }
509 j++;
510 }
511
512 if (j >= NA) {
513 return thumbs;
514 }
515
516 ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
517 thumbs.subtasks = subtasks;
518 while (j < NA) {
519 ActivityRecord ar = mActivities.get(j);
520 j++;
521 if (ar.finishing) {
522 continue;
523 }
524 if (ar.thumbHolder != holder && holder != null) {
525 thumbs.numSubThumbbails++;
526 holder = ar.thumbHolder;
527 TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
528 sub.holder = holder;
529 sub.activity = ar;
530 sub.index = j-1;
531 subtasks.add(sub);
532 }
533 }
534 if (thumbs.numSubThumbbails > 0) {
535 thumbs.retriever = new IThumbnailRetriever.Stub() {
536 @Override
537 public Bitmap getThumbnail(int index) {
538 if (index < 0 || index >= thumbs.subtasks.size()) {
539 return null;
540 }
541 TaskAccessInfo.SubTask sub = thumbs.subtasks.get(index);
542 ActivityRecord resumedActivity = stack.mResumedActivity;
543 if (resumedActivity != null && resumedActivity.thumbHolder == sub.holder) {
544 return stack.screenshotActivities(resumedActivity);
545 }
546 return sub.holder.lastThumbnail;
547 }
548 };
549 }
550 return thumbs;
551 }
552
Craig Mautner525f3d92013-05-07 14:01:50 -0700553 /**
554 * Find the activity in the history stack within the given task. Returns
555 * the index within the history at which it's found, or < 0 if not found.
556 */
557 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
558 final ComponentName realActivity = r.realActivity;
559 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
560 ActivityRecord candidate = mActivities.get(activityNdx);
561 if (candidate.finishing) {
562 continue;
563 }
564 if (candidate.realActivity.equals(realActivity)) {
565 return candidate;
566 }
567 }
568 return null;
569 }
570
Winson Chunga449dc02014-05-16 11:15:04 -0700571 /** Updates the last task description values. */
572 void updateTaskDescription() {
573 // Traverse upwards looking for any break between main task activities and
574 // utility activities.
575 int activityNdx;
576 final int numActivities = mActivities.size();
577 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
Craig Mautner21d24a22014-04-23 11:45:37 -0700578 ++activityNdx) {
Winson Chunga449dc02014-05-16 11:15:04 -0700579 final ActivityRecord r = mActivities.get(activityNdx);
580 if (r.intent != null &&
581 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
582 != 0) {
583 break;
584 }
585 }
586 if (activityNdx > 0) {
587 // Traverse downwards starting below break looking for set label, icon.
588 // Note that if there are activities in the task but none of them set the
589 // recent activity values, then we do not fall back to the last set
590 // values in the TaskRecord.
591 String label = null;
592 Bitmap icon = null;
593 int colorPrimary = 0;
594 for (--activityNdx; activityNdx >= 0; --activityNdx) {
595 final ActivityRecord r = mActivities.get(activityNdx);
596 if (r.taskDescription != null) {
597 if (label == null) {
598 label = r.taskDescription.getLabel();
599 }
600 if (icon == null) {
601 icon = r.taskDescription.getIcon();
602 }
603 if (colorPrimary == 0) {
604 colorPrimary = r.taskDescription.getPrimaryColor();
605
606 }
607 }
608 }
609 lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary);
610 }
611 }
612
Craig Mautner21d24a22014-04-23 11:45:37 -0700613 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
614 Slog.i(TAG, "Saving task=" + this);
615
616 out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
617 if (realActivity != null) {
618 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
619 }
620 if (origActivity != null) {
621 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
622 }
623 if (affinity != null) {
624 out.attribute(null, ATTR_AFFINITY, affinity);
625 }
626 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
627 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
628 out.attribute(null, ATTR_USERID, String.valueOf(userId));
629 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000630 out.attribute(null, ATTR_ONTOPOFHOME, String.valueOf(mOnTopOfHome));
Craig Mautner21d24a22014-04-23 11:45:37 -0700631 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
632 if (lastDescription != null) {
633 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
634 }
635
636 if (affinityIntent != null) {
637 out.startTag(null, TAG_AFFINITYINTENT);
638 affinityIntent.saveToXml(out);
639 out.endTag(null, TAG_AFFINITYINTENT);
640 }
641
642 out.startTag(null, TAG_INTENT);
643 intent.saveToXml(out);
644 out.endTag(null, TAG_INTENT);
645
646 final ArrayList<ActivityRecord> activities = mActivities;
647 final int numActivities = activities.size();
648 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
649 final ActivityRecord r = activities.get(activityNdx);
650 if (!r.isPersistable() || (r.intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) ==
651 Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) {
652 break;
653 }
654 out.startTag(null, TAG_ACTIVITY);
655 r.saveToXml(out);
656 out.endTag(null, TAG_ACTIVITY);
657 }
658
659 final Bitmap thumbnail = getTaskTopThumbnailLocked();
660 if (thumbnail != null) {
661 TaskPersister.saveImage(thumbnail, String.valueOf(taskId) + TASK_THUMBNAIL_SUFFIX);
662 }
663 }
664
665 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
666 throws IOException, XmlPullParserException {
667 Intent intent = null;
668 Intent affinityIntent = null;
669 ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
670 ComponentName realActivity = null;
671 ComponentName origActivity = null;
672 String affinity = null;
673 boolean rootHasReset = false;
674 boolean askedCompatMode = false;
675 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000676 boolean onTopOfHome = true;
Craig Mautner21d24a22014-04-23 11:45:37 -0700677 int userId = 0;
678 String lastDescription = null;
679 long lastTimeOnTop = 0;
680 int taskId = -1;
681 final int outerDepth = in.getDepth();
682
683 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
684 final String attrName = in.getAttributeName(attrNdx);
685 final String attrValue = in.getAttributeValue(attrNdx);
686 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
687 attrName + " value=" + attrValue);
688 if (ATTR_TASKID.equals(attrName)) {
689 taskId = Integer.valueOf(attrValue);
690 } else if (ATTR_REALACTIVITY.equals(attrName)) {
691 realActivity = ComponentName.unflattenFromString(attrValue);
692 } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
693 origActivity = ComponentName.unflattenFromString(attrValue);
694 } else if (ATTR_AFFINITY.equals(attrName)) {
695 affinity = attrValue;
696 } else if (ATTR_ROOTHASRESET.equals(attrName)) {
697 rootHasReset = Boolean.valueOf(attrValue);
698 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
699 askedCompatMode = Boolean.valueOf(attrValue);
700 } else if (ATTR_USERID.equals(attrName)) {
701 userId = Integer.valueOf(attrValue);
702 } else if (ATTR_TASKTYPE.equals(attrName)) {
703 taskType = Integer.valueOf(attrValue);
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000704 } else if (ATTR_ONTOPOFHOME.equals(attrName)) {
705 onTopOfHome = Boolean.valueOf(attrValue);
Craig Mautner21d24a22014-04-23 11:45:37 -0700706 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
707 lastDescription = attrValue;
708 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
709 lastTimeOnTop = Long.valueOf(attrValue);
710 } else {
711 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
712 }
713 }
714
715 int event;
716 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
717 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
718 if (event == XmlPullParser.START_TAG) {
719 final String name = in.getName();
720 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
721 name);
722 if (TAG_AFFINITYINTENT.equals(name)) {
723 affinityIntent = Intent.restoreFromXml(in);
724 } else if (TAG_INTENT.equals(name)) {
725 intent = Intent.restoreFromXml(in);
726 } else if (TAG_ACTIVITY.equals(name)) {
727 ActivityRecord activity =
728 ActivityRecord.restoreFromXml(in, taskId, stackSupervisor);
729 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
730 activity);
731 if (activity != null) {
732 activities.add(activity);
733 }
734 } else {
735 Slog.e(TAG, "restoreTask: Unexpected name=" + name);
736 XmlUtils.skipCurrentTag(in);
737 }
738 }
739 }
740
741 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
742 affinityIntent, affinity, realActivity, origActivity, rootHasReset,
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000743 askedCompatMode, taskType, onTopOfHome, userId, lastDescription, activities,
744 lastTimeOnTop);
Craig Mautner21d24a22014-04-23 11:45:37 -0700745
746 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
747 final ActivityRecord r = activities.get(activityNdx);
748 r.thumbHolder = r.task = task;
749 }
750
751 task.lastThumbnail = TaskPersister.restoreImage(taskId + TASK_THUMBNAIL_SUFFIX);
752
753 Slog.i(TAG, "Restored task=" + task);
754 return task;
755 }
756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 void dump(PrintWriter pw, String prefix) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700758 if (rootWasReset || userId != 0 || numFullscreen != 0) {
759 pw.print(prefix); pw.print(" rootWasReset="); pw.print(rootWasReset);
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800760 pw.print(" userId="); pw.print(userId);
Craig Mautner21d24a22014-04-23 11:45:37 -0700761 pw.print(" taskType="); pw.print(taskType);
Craig Mautnerae7ecab2013-09-18 11:48:14 -0700762 pw.print(" numFullscreen="); pw.print(numFullscreen);
Craig Mautnerb9a6c8a2014-05-29 16:50:59 +0000763 pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700764 }
765 if (affinity != null) {
766 pw.print(prefix); pw.print("affinity="); pw.println(affinity);
767 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700768 if (voiceSession != null || voiceInteractor != null) {
769 pw.print(prefix); pw.print("VOICE: session=0x");
770 pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
771 pw.print(" interactor=0x");
772 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
773 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700774 if (intent != null) {
775 StringBuilder sb = new StringBuilder(128);
776 sb.append(prefix); sb.append("intent={");
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800777 intent.toShortString(sb, false, true, false, true);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700778 sb.append('}');
779 pw.println(sb.toString());
780 }
781 if (affinityIntent != null) {
782 StringBuilder sb = new StringBuilder(128);
783 sb.append(prefix); sb.append("affinityIntent={");
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800784 affinityIntent.toShortString(sb, false, true, false, true);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700785 sb.append('}');
786 pw.println(sb.toString());
787 }
788 if (origActivity != null) {
789 pw.print(prefix); pw.print("origActivity=");
790 pw.println(origActivity.flattenToShortString());
791 }
792 if (realActivity != null) {
793 pw.print(prefix); pw.print("realActivity=");
794 pw.println(realActivity.flattenToShortString());
795 }
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800796 pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700797 if (!askedCompatMode) {
798 pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
799 }
Dianne Hackborncfb9f2b2011-08-24 10:51:49 -0700800 pw.print(prefix); pw.print("lastThumbnail="); pw.print(lastThumbnail);
801 pw.print(" lastDescription="); pw.println(lastDescription);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700802 pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
803 pw.print(" (inactive for ");
804 pw.print((getInactiveDuration()/1000)); pw.println("s)");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 }
806
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800807 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700809 StringBuilder sb = new StringBuilder(128);
Craig Mautnerde4ef022013-04-07 19:01:33 -0700810 if (stringName != null) {
811 sb.append(stringName);
812 sb.append(" U=");
813 sb.append(userId);
814 sb.append(" sz=");
815 sb.append(mActivities.size());
816 sb.append('}');
817 return sb.toString();
818 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700819 sb.append("TaskRecord{");
820 sb.append(Integer.toHexString(System.identityHashCode(this)));
821 sb.append(" #");
822 sb.append(taskId);
823 if (affinity != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800824 sb.append(" A=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700825 sb.append(affinity);
826 } else if (intent != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800827 sb.append(" I=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700828 sb.append(intent.getComponent().flattenToShortString());
829 } else if (affinityIntent != null) {
Craig Mautner5d9c7be2013-02-15 14:02:56 -0800830 sb.append(" aI=");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700831 sb.append(affinityIntent.getComponent().flattenToShortString());
832 } else {
833 sb.append(" ??");
834 }
Craig Mautnerde4ef022013-04-07 19:01:33 -0700835 stringName = sb.toString();
836 return toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 }
838}