2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.am;
19 import android.annotation.Nullable;
20 import android.app.Activity;
21 import android.app.ActivityManager;
22 import android.app.ActivityManager.StackId;
23 import android.app.ActivityManager.TaskDescription;
24 import android.app.ActivityManager.TaskThumbnail;
25 import android.app.ActivityManager.TaskThumbnailInfo;
26 import android.app.ActivityOptions;
27 import android.app.AppGlobals;
28 import android.app.IActivityManager;
29 import android.content.ComponentName;
30 import android.content.Intent;
31 import android.content.pm.ActivityInfo;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.IPackageManager;
34 import android.content.pm.PackageManager;
35 import android.content.res.Configuration;
36 import android.graphics.Bitmap;
37 import android.graphics.Point;
38 import android.graphics.Rect;
39 import android.os.Debug;
40 import android.os.ParcelFileDescriptor;
41 import android.os.RemoteException;
42 import android.os.UserHandle;
43 import android.provider.Settings;
44 import android.service.voice.IVoiceInteractionSession;
45 import android.util.DisplayMetrics;
46 import android.util.Slog;
48 import com.android.internal.app.IVoiceInteractor;
49 import com.android.internal.util.XmlUtils;
51 import org.xmlpull.v1.XmlPullParser;
52 import org.xmlpull.v1.XmlPullParserException;
53 import org.xmlpull.v1.XmlSerializer;
56 import java.io.IOException;
57 import java.io.PrintWriter;
58 import java.util.ArrayList;
59 import java.util.Objects;
61 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
62 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
63 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
64 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
65 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
66 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
67 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
68 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
69 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
70 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
71 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
72 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
73 import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
74 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
75 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
76 import static android.content.res.Configuration.SCREENLAYOUT_LONG_MASK;
77 import static android.content.res.Configuration.SCREENLAYOUT_SIZE_MASK;
78 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
79 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
80 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
81 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
82 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
83 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
84 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
85 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
86 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
87 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
88 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
89 import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
90 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
91 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
92 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
93 import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
95 final class TaskRecord {
96 private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
97 private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
98 private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
99 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
100 private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
102 static final String ATTR_TASKID = "task_id";
103 private static final String TAG_INTENT = "intent";
104 private static final String TAG_AFFINITYINTENT = "affinity_intent";
105 static final String ATTR_REALACTIVITY = "real_activity";
106 static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
107 private static final String ATTR_ORIGACTIVITY = "orig_activity";
108 private static final String TAG_ACTIVITY = "activity";
109 private static final String ATTR_AFFINITY = "affinity";
110 private static final String ATTR_ROOT_AFFINITY = "root_affinity";
111 private static final String ATTR_ROOTHASRESET = "root_has_reset";
112 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
113 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
114 private static final String ATTR_USERID = "user_id";
115 private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
116 private static final String ATTR_EFFECTIVE_UID = "effective_uid";
117 private static final String ATTR_TASKTYPE = "task_type";
118 private static final String ATTR_FIRSTACTIVETIME = "first_active_time";
119 private static final String ATTR_LASTACTIVETIME = "last_active_time";
120 private static final String ATTR_LASTDESCRIPTION = "last_description";
121 private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
122 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
123 static final String ATTR_TASK_AFFILIATION = "task_affiliation";
124 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
125 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
126 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
127 private static final String ATTR_CALLING_UID = "calling_uid";
128 private static final String ATTR_CALLING_PACKAGE = "calling_package";
129 private static final String ATTR_RESIZE_MODE = "resize_mode";
130 private static final String ATTR_PRIVILEGED = "privileged";
131 private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
132 private static final String ATTR_MIN_WIDTH = "min_width";
133 private static final String ATTR_MIN_HEIGHT = "min_height";
136 private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
138 static final int INVALID_TASK_ID = -1;
139 static final int INVALID_MIN_SIZE = -1;
141 final int taskId; // Unique identifier for this task.
142 String affinity; // The affinity name for this task, or null; may change identity.
143 String rootAffinity; // Initial base affinity, or null; does not change from initial root.
144 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
145 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
146 Intent intent; // The original intent that started the task.
147 Intent affinityIntent; // Intent of affinity-moved activity that started this task.
148 int effectiveUid; // The current effective uid of the identity of this task.
149 ComponentName origActivity; // The non-alias activity component of the intent.
150 ComponentName realActivity; // The actual activity component that started the task.
151 boolean realActivitySuspended; // True if the actual activity component that started the
152 // task is suspended.
153 long firstActiveTime; // First time this task was active.
154 long lastActiveTime; // Last time this task was active, including sleep.
155 boolean inRecents; // Actually in the recents list?
156 boolean isAvailable; // Is the activity available to be launched?
157 boolean isLaunching; // Is an activity in this task launching?
158 boolean rootWasReset; // True if the intent at the root of the task had
159 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
160 boolean autoRemoveRecents; // If true, we should automatically remove the task from
161 // recents when activity finishes
162 boolean askedCompatMode;// Have asked the user about compat mode for this task.
163 boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
165 String stringName; // caching of toString() result.
166 int userId; // user for which this task was created
167 boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
170 int numFullscreen; // Number of fullscreen activities.
172 int mResizeMode; // The resize mode of this task and its activities.
173 // Based on the {@link ActivityInfo#resizeMode} of the root activity.
174 boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
175 // changes on a temporary basis.
176 int mLockTaskMode; // Which tasklock mode to launch this task in. One of
177 // ActivityManager.LOCK_TASK_LAUNCH_MODE_*
178 private boolean mPrivileged; // The root activity application of this task holds
179 // privileged permissions.
181 /** Can't be put in lockTask mode. */
182 final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
183 /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
184 final static int LOCK_TASK_AUTH_PINNABLE = 1;
185 /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
186 final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
187 /** Can enter lockTask without user approval. Can start over existing lockTask task. */
188 final static int LOCK_TASK_AUTH_WHITELISTED = 3;
189 /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
191 final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
192 int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
194 int mLockTaskUid = -1; // The uid of the application that called startLockTask().
196 // This represents the last resolved activity values for this task
197 // NOTE: This value needs to be persisted with each task
198 TaskDescription lastTaskDescription = new TaskDescription();
200 /** List of all activities in the task arranged in history order */
201 final ArrayList<ActivityRecord> mActivities;
206 /** Takes on same set of values as ActivityRecord.mActivityType */
209 /** Takes on same value as first root activity */
210 boolean isPersistable = false;
213 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
214 * determining the order when restoring. Sign indicates whether last task movement was to front
215 * (positive) or back (negative). Absolute value indicates time. */
216 long mLastTimeMoved = System.currentTimeMillis();
218 /** Indication of what to run next when task exits. Use ActivityRecord types.
219 * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
221 private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
223 /** If original intent did not allow relinquishing task identity, save that information */
224 boolean mNeverRelinquishIdentity = true;
226 // Used in the unique case where we are clearing the task in order to reuse it. In that case we
227 // do not want to delete the stack when the task goes empty.
228 private boolean mReuseTask = false;
230 private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
231 private final File mLastThumbnailFile; // File containing last thumbnail.
232 private final String mFilename;
233 private TaskThumbnailInfo mLastThumbnailInfo;
234 CharSequence lastDescription; // Last description captured for this item.
236 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
237 int mAffiliatedTaskColor; // color of the parent task affiliation.
238 TaskRecord mPrevAffiliate; // previous task in affiliated chain.
239 int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
240 TaskRecord mNextAffiliate; // next task in affiliated chain.
241 int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
243 // For relaunching the task from recents as though it was launched by the original launcher.
245 String mCallingPackage;
247 final ActivityManagerService mService;
249 // Whether or not this task covers the entire screen; by default tasks are fullscreen.
250 boolean mFullscreen = true;
252 // Bounds of the Task. null for fullscreen tasks.
254 private final Rect mTmpStableBounds = new Rect();
255 private final Rect mTmpNonDecorBounds = new Rect();
256 private final Rect mTmpRect = new Rect();
257 private final Rect mTmpRect2 = new Rect();
259 // Last non-fullscreen bounds the task was launched in or resized to.
260 // The information is persisted and used to determine the appropriate stack to launch the
261 // task into on restore.
262 Rect mLastNonFullscreenBounds = null;
263 // Minimal width and height of this task when it's resizeable. -1 means it should use the
264 // default minimal width/height.
268 // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
269 // This number will be assigned when we evaluate OOM scores for all visible tasks.
272 Configuration mOverrideConfig = Configuration.EMPTY;
274 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
275 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
277 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
278 TaskPersister.IMAGE_EXTENSION;
279 userId = UserHandle.getUserId(info.applicationInfo.uid);
280 mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
281 mLastThumbnailInfo = new TaskThumbnailInfo();
283 mAffiliatedTaskId = _taskId;
284 voiceSession = _voiceSession;
285 voiceInteractor = _voiceInteractor;
287 mActivities = new ArrayList<>();
288 mCallingUid = info.applicationInfo.uid;
289 mCallingPackage = info.packageName;
290 setIntent(_intent, info);
291 setMinDimensions(info);
295 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
296 TaskDescription _taskDescription, TaskThumbnailInfo thumbnailInfo) {
298 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
299 TaskPersister.IMAGE_EXTENSION;
300 userId = UserHandle.getUserId(info.applicationInfo.uid);
301 mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
302 mLastThumbnailInfo = thumbnailInfo;
304 mAffiliatedTaskId = _taskId;
306 voiceInteractor = null;
308 mActivities = new ArrayList<>();
309 mCallingUid = info.applicationInfo.uid;
310 mCallingPackage = info.packageName;
311 setIntent(_intent, info);
312 setMinDimensions(info);
314 taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
315 isPersistable = true;
316 // Clamp to [1, max].
317 maxRecents = Math.min(Math.max(info.maxRecents, 1),
318 ActivityManager.getMaxAppRecentsLimitStatic());
320 taskType = APPLICATION_ACTIVITY_TYPE;
321 mTaskToReturnTo = HOME_ACTIVITY_TYPE;
322 lastTaskDescription = _taskDescription;
326 private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
327 Intent _affinityIntent, String _affinity, String _rootAffinity,
328 ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
329 boolean _autoRemoveRecents, boolean _askedCompatMode, int _taskType, int _userId,
330 int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
331 long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
332 boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
333 TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
334 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
335 int resizeMode, boolean privileged, boolean _realActivitySuspended,
336 boolean userSetupComplete, int minWidth, int minHeight) {
338 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
339 TaskPersister.IMAGE_EXTENSION;
340 mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(_userId), mFilename);
341 mLastThumbnailInfo = lastThumbnailInfo;
344 affinityIntent = _affinityIntent;
345 affinity = _affinity;
346 rootAffinity = _rootAffinity;
348 voiceInteractor = null;
349 realActivity = _realActivity;
350 realActivitySuspended = _realActivitySuspended;
351 origActivity = _origActivity;
352 rootWasReset = _rootWasReset;
354 autoRemoveRecents = _autoRemoveRecents;
355 askedCompatMode = _askedCompatMode;
356 taskType = _taskType;
357 mTaskToReturnTo = HOME_ACTIVITY_TYPE;
359 mUserSetupComplete = userSetupComplete;
360 effectiveUid = _effectiveUid;
361 firstActiveTime = _firstActiveTime;
362 lastActiveTime = _lastActiveTime;
363 lastDescription = _lastDescription;
364 mActivities = activities;
365 mLastTimeMoved = lastTimeMoved;
366 mNeverRelinquishIdentity = neverRelinquishIdentity;
367 lastTaskDescription = _lastTaskDescription;
368 mAffiliatedTaskId = taskAffiliation;
369 mAffiliatedTaskColor = taskAffiliationColor;
370 mPrevAffiliateTaskId = prevTaskId;
371 mNextAffiliateTaskId = nextTaskId;
372 mCallingUid = callingUid;
373 mCallingPackage = callingPackage;
374 mResizeMode = resizeMode;
375 mPrivileged = privileged;
376 mMinWidth = minWidth;
377 mMinHeight = minHeight;
380 void touchActiveTime() {
381 lastActiveTime = System.currentTimeMillis();
382 if (firstActiveTime == 0) {
383 firstActiveTime = lastActiveTime;
387 long getInactiveDuration() {
388 return System.currentTimeMillis() - lastActiveTime;
391 /** Sets the original intent, and the calling uid and package. */
392 void setIntent(ActivityRecord r) {
393 mCallingUid = r.launchedFromUid;
394 mCallingPackage = r.launchedFromPackage;
395 setIntent(r.intent, r.info);
398 /** Sets the original intent, _without_ updating the calling uid or package. */
399 private void setIntent(Intent _intent, ActivityInfo info) {
400 if (intent == null) {
401 mNeverRelinquishIdentity =
402 (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
403 } else if (mNeverRelinquishIdentity) {
407 affinity = info.taskAffinity;
408 if (intent == null) {
409 // If this task already has an intent associated with it, don't set the root
410 // affinity -- we don't want it changing after initially set, but the initially
411 // set value may be null.
412 rootAffinity = affinity;
414 effectiveUid = info.applicationInfo.uid;
417 if (info.targetActivity == null) {
418 if (_intent != null) {
419 // If this Intent has a selector, we want to clear it for the
420 // recent task since it is not relevant if the user later wants
421 // to re-launch the app.
422 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
423 _intent = new Intent(_intent);
424 _intent.setSelector(null);
425 _intent.setSourceBounds(null);
428 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
430 realActivity = _intent != null ? _intent.getComponent() : null;
433 ComponentName targetComponent = new ComponentName(
434 info.packageName, info.targetActivity);
435 if (_intent != null) {
436 Intent targetIntent = new Intent(_intent);
437 targetIntent.setComponent(targetComponent);
438 targetIntent.setSelector(null);
439 targetIntent.setSourceBounds(null);
440 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
441 "Setting Intent of " + this + " to target " + targetIntent);
442 intent = targetIntent;
443 realActivity = targetComponent;
444 origActivity = _intent.getComponent();
447 realActivity = targetComponent;
448 origActivity = new ComponentName(info.packageName, info.name);
452 final int intentFlags = intent == null ? 0 : intent.getFlags();
453 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
454 // Once we are set to an Intent with this flag, we count this
455 // task as having a true root activity.
458 userId = UserHandle.getUserId(info.applicationInfo.uid);
459 mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
460 USER_SETUP_COMPLETE, 0, userId) != 0;
461 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
462 // If the activity itself has requested auto-remove, then just always do it.
463 autoRemoveRecents = true;
464 } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
465 == FLAG_ACTIVITY_NEW_DOCUMENT) {
466 // If the caller has not asked for the document to be retained, then we may
467 // want to turn on auto-remove, depending on whether the target has set its
468 // own document launch mode.
469 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
470 autoRemoveRecents = false;
472 autoRemoveRecents = true;
475 autoRemoveRecents = false;
477 mResizeMode = info.resizeMode;
478 mLockTaskMode = info.lockTaskLaunchMode;
479 mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
483 /** Sets the original minimal width and height. */
484 private void setMinDimensions(ActivityInfo info) {
485 if (info != null && info.windowLayout != null) {
486 mMinWidth = info.windowLayout.minWidth;
487 mMinHeight = info.windowLayout.minHeight;
489 mMinWidth = INVALID_MIN_SIZE;
490 mMinHeight = INVALID_MIN_SIZE;
495 * Return true if the input activity has the same intent filter as the intent this task
496 * record is based on (normally the root activity intent).
498 boolean isSameIntentFilter(ActivityRecord r) {
499 final Intent intent = new Intent(r.intent);
500 // Correct the activity intent for aliasing. The task record intent will always be based on
501 // the real activity that will be launched not the alias, so we need to use an intent with
502 // the component name pointing to the real activity not the alias in the activity record.
503 intent.setComponent(r.realActivity);
504 return this.intent.filterEquals(intent);
507 void setTaskToReturnTo(int taskToReturnTo) {
508 mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE)
509 ? HOME_ACTIVITY_TYPE : taskToReturnTo;
512 int getTaskToReturnTo() {
513 return mTaskToReturnTo;
516 void setPrevAffiliate(TaskRecord prevAffiliate) {
517 mPrevAffiliate = prevAffiliate;
518 mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.taskId;
521 void setNextAffiliate(TaskRecord nextAffiliate) {
522 mNextAffiliate = nextAffiliate;
523 mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId;
526 // Close up recents linked list.
527 void closeRecentsChain() {
528 if (mPrevAffiliate != null) {
529 mPrevAffiliate.setNextAffiliate(mNextAffiliate);
531 if (mNextAffiliate != null) {
532 mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
534 setPrevAffiliate(null);
535 setNextAffiliate(null);
538 void removedFromRecents() {
543 mService.notifyTaskPersisterLocked(this, false);
547 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
549 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
550 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
552 while (taskToAffiliateWith.mNextAffiliate != null) {
553 final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
554 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
555 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
556 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
557 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
558 nextRecents.setPrevAffiliate(null);
560 taskToAffiliateWith.setNextAffiliate(null);
563 taskToAffiliateWith = nextRecents;
565 taskToAffiliateWith.setNextAffiliate(this);
566 setPrevAffiliate(taskToAffiliateWith);
567 setNextAffiliate(null);
571 * Sets the last thumbnail with the current task bounds and the system orientation.
572 * @return whether the thumbnail was set
574 boolean setLastThumbnailLocked(Bitmap thumbnail) {
575 final Configuration serviceConfig = mService.mConfiguration;
578 if (mBounds != null) {
579 // Non-fullscreen tasks
580 taskWidth = mBounds.width();
581 taskHeight = mBounds.height();
582 } else if (stack != null) {
584 final Point displaySize = new Point();
585 stack.getDisplaySize(displaySize);
586 taskWidth = displaySize.x;
587 taskHeight = displaySize.y;
589 Slog.e(TAG, "setLastThumbnailLocked() called on Task without stack");
591 return setLastThumbnailLocked(thumbnail, taskWidth, taskHeight, serviceConfig.orientation);
595 * Sets the last thumbnail with the current task bounds.
596 * @return whether the thumbnail was set
598 private boolean setLastThumbnailLocked(Bitmap thumbnail, int taskWidth, int taskHeight,
599 int screenOrientation) {
600 if (mLastThumbnail != thumbnail) {
601 mLastThumbnail = thumbnail;
602 mLastThumbnailInfo.taskWidth = taskWidth;
603 mLastThumbnailInfo.taskHeight = taskHeight;
604 mLastThumbnailInfo.screenOrientation = screenOrientation;
605 if (thumbnail == null) {
606 if (mLastThumbnailFile != null) {
607 mLastThumbnailFile.delete();
610 mService.mRecentTasks.saveImage(thumbnail, mLastThumbnailFile.getAbsolutePath());
617 void getLastThumbnail(TaskThumbnail thumbs) {
618 thumbs.mainThumbnail = mLastThumbnail;
619 thumbs.thumbnailInfo = mLastThumbnailInfo;
620 thumbs.thumbnailFileDescriptor = null;
621 if (mLastThumbnail == null) {
622 thumbs.mainThumbnail = mService.mRecentTasks.getImageFromWriteQueue(
623 mLastThumbnailFile.getAbsolutePath());
625 // Only load the thumbnail file if we don't have a thumbnail
626 if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) {
628 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
629 ParcelFileDescriptor.MODE_READ_ONLY);
630 } catch (IOException e) {
636 * Removes in-memory thumbnail data when the max number of in-memory task thumbnails is reached.
638 void freeLastThumbnail() {
639 mLastThumbnail = null;
643 * Removes all associated thumbnail data when a task is removed or pruned from recents.
645 void disposeThumbnail() {
646 mLastThumbnailInfo.reset();
647 mLastThumbnail = null;
648 lastDescription = null;
651 /** Returns the intent for the root activity for this task */
652 Intent getBaseIntent() {
653 return intent != null ? intent : affinityIntent;
656 /** Returns the first non-finishing activity from the root. */
657 ActivityRecord getRootActivity() {
658 for (int i = 0; i < mActivities.size(); i++) {
659 final ActivityRecord r = mActivities.get(i);
668 ActivityRecord getTopActivity() {
669 for (int i = mActivities.size() - 1; i >= 0; --i) {
670 final ActivityRecord r = mActivities.get(i);
679 ActivityRecord topRunningActivityLocked() {
681 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
682 ActivityRecord r = mActivities.get(activityNdx);
683 if (!r.finishing && stack.okToShowLocked(r)) {
691 ActivityRecord topRunningActivityWithStartingWindowLocked() {
693 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
694 ActivityRecord r = mActivities.get(activityNdx);
695 if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
696 || r.finishing || !stack.okToShowLocked(r)) {
705 void setFrontOfTask() {
706 setFrontOfTask(null);
709 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
710 void setFrontOfTask(ActivityRecord newTop) {
711 // If a top candidate is suggested by the caller, go ahead and use it and mark all others
712 // as not front. This is needed in situations where the current front activity in the
713 // task isn't finished yet and we want to set the front to the activity moved to the front
715 boolean foundFront = newTop != null ? true : false;
717 final int numActivities = mActivities.size();
718 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
719 final ActivityRecord r = mActivities.get(activityNdx);
720 if (foundFront || r.finishing) {
721 r.frontOfTask = false;
723 r.frontOfTask = true;
724 // Set frontOfTask false for every following activity.
728 if (!foundFront && numActivities > 0) {
729 // All activities of this task are finishing. As we ought to have a frontOfTask
730 // activity, make the bottom activity front.
731 mActivities.get(0).frontOfTask = true;
733 if (newTop != null) {
734 newTop.frontOfTask = true;
739 * Reorder the history stack so that the passed activity is brought to the front.
741 final void moveActivityToFrontLocked(ActivityRecord newTop) {
742 if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
743 "Removing and adding activity " + newTop
744 + " to stack at top callers=" + Debug.getCallers(4));
746 mActivities.remove(newTop);
747 mActivities.add(newTop);
748 updateEffectiveIntent();
750 setFrontOfTask(newTop);
753 void addActivityAtBottom(ActivityRecord r) {
754 addActivityAtIndex(0, r);
757 void addActivityToTop(ActivityRecord r) {
758 addActivityAtIndex(mActivities.size(), r);
761 void addActivityAtIndex(int index, ActivityRecord r) {
762 // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
763 if (!mActivities.remove(r) && r.fullscreen) {
764 // Was not previously in list.
767 // Only set this based on the first activity
768 if (mActivities.isEmpty()) {
769 taskType = r.mActivityType;
770 isPersistable = r.isPersistable();
771 mCallingUid = r.launchedFromUid;
772 mCallingPackage = r.launchedFromPackage;
773 // Clamp to [1, max].
774 maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
775 ActivityManager.getMaxAppRecentsLimitStatic());
777 // Otherwise make all added activities match this one.
778 r.mActivityType = taskType;
781 final int size = mActivities.size();
783 if (index == size && size > 0) {
784 final ActivityRecord top = mActivities.get(size - 1);
785 if (top.mTaskOverlay) {
786 // Place below the task overlay activity since the overlay activity should always
792 mActivities.add(index, r);
793 updateEffectiveIntent();
794 if (r.isPersistable()) {
795 mService.notifyTaskPersisterLocked(this, false);
799 /** @return true if this was the last activity in the task */
800 boolean removeActivity(ActivityRecord r) {
801 if (mActivities.remove(r) && r.fullscreen) {
802 // Was previously in list.
805 if (r.isPersistable()) {
806 mService.notifyTaskPersisterLocked(this, false);
809 if (stack != null && stack.mStackId == PINNED_STACK_ID) {
810 // We normally notify listeners of task stack changes on pause, however pinned stack
811 // activities are normally in the paused state so no notification will be sent there
812 // before the activity is removed. We send it here so instead.
813 mService.notifyTaskStackChangedLocked();
816 if (mActivities.isEmpty()) {
819 updateEffectiveIntent();
823 boolean autoRemoveFromRecents() {
824 // We will automatically remove the task either if it has explicitly asked for
825 // this, or it is empty and has never contained an activity that got shown to
827 return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible);
831 * Completely remove all activities associated with an existing
832 * task starting at a specified index.
834 final void performClearTaskAtIndexLocked(int activityNdx) {
835 int numActivities = mActivities.size();
836 for ( ; activityNdx < numActivities; ++activityNdx) {
837 final ActivityRecord r = mActivities.get(activityNdx);
842 // Task was restored from persistent storage.
844 mActivities.remove(activityNdx);
847 } else if (stack.finishActivityLocked(
848 r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) {
856 * Completely remove all activities associated with an existing task.
858 final void performClearTaskLocked() {
860 performClearTaskAtIndexLocked(0);
864 ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
866 final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
872 * Perform clear operation as requested by
873 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
874 * stack to the given task, then look for
875 * an instance of that activity in the stack and, if found, finish all
876 * activities on top of it and return the instance.
878 * @param newR Description of the new activity being started.
879 * @return Returns the old activity that should be continued to be used,
880 * or null if none was found.
882 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
883 int numActivities = mActivities.size();
884 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
885 ActivityRecord r = mActivities.get(activityNdx);
889 if (r.realActivity.equals(newR.realActivity)) {
890 // Here it is! Now finish everything in front...
891 final ActivityRecord ret = r;
893 for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
894 r = mActivities.get(activityNdx);
898 ActivityOptions opts = r.takeOptionsLocked();
900 ret.updateOptionsLocked(opts);
902 if (stack != null && stack.finishActivityLocked(
903 r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
909 // Finally, if this is a normal launch mode (that is, not
910 // expecting onNewIntent()), then we will finish the current
911 // instance of the activity so a new fresh one can be started.
912 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
913 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
914 if (!ret.finishing) {
916 stack.finishActivityLocked(
917 ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
930 public TaskThumbnail getTaskThumbnailLocked() {
932 final ActivityRecord resumedActivity = stack.mResumedActivity;
933 if (resumedActivity != null && resumedActivity.task == this) {
934 final Bitmap thumbnail = stack.screenshotActivitiesLocked(resumedActivity);
935 setLastThumbnailLocked(thumbnail);
938 final TaskThumbnail taskThumbnail = new TaskThumbnail();
939 getLastThumbnail(taskThumbnail);
940 return taskThumbnail;
943 public void removeTaskActivitiesLocked() {
944 // Just remove the entire task.
945 performClearTaskAtIndexLocked(0);
948 String lockTaskAuthToString() {
949 switch (mLockTaskAuth) {
950 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
951 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
952 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
953 case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
954 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
955 default: return "unknown=" + mLockTaskAuth;
959 void setLockTaskAuth() {
961 (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS ||
962 mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
963 // Non-priv apps are not allowed to use always or never, fall back to default
964 mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
966 switch (mLockTaskMode) {
967 case LOCK_TASK_LAUNCH_MODE_DEFAULT:
968 mLockTaskAuth = isLockTaskWhitelistedLocked() ?
969 LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
972 case LOCK_TASK_LAUNCH_MODE_NEVER:
973 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
976 case LOCK_TASK_LAUNCH_MODE_ALWAYS:
977 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
980 case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
981 mLockTaskAuth = isLockTaskWhitelistedLocked() ?
982 LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
985 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
986 " mLockTaskAuth=" + lockTaskAuthToString());
989 boolean isLockTaskWhitelistedLocked() {
990 String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
994 String[] packages = mService.mLockTaskPackages.get(userId);
995 if (packages == null) {
998 for (int i = packages.length - 1; i >= 0; --i) {
999 if (pkg.equals(packages[i])) {
1006 boolean isHomeTask() {
1007 return taskType == HOME_ACTIVITY_TYPE;
1010 boolean isRecentsTask() {
1011 return taskType == RECENTS_ACTIVITY_TYPE;
1014 boolean isApplicationTask() {
1015 return taskType == APPLICATION_ACTIVITY_TYPE;
1018 boolean isOverHomeStack() {
1019 return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
1022 boolean isResizeable() {
1023 return !isHomeTask() && (mService.mForceResizableActivities
1024 || ActivityInfo.isResizeableMode(mResizeMode)) && !mTemporarilyUnresizable;
1027 boolean inCropWindowsResizeMode() {
1028 return !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
1031 boolean canGoInDockedStack() {
1032 return isResizeable() || inCropWindowsResizeMode();
1036 * Find the activity in the history stack within the given task. Returns
1037 * the index within the history at which it's found, or < 0 if not found.
1039 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
1040 final ComponentName realActivity = r.realActivity;
1041 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1042 ActivityRecord candidate = mActivities.get(activityNdx);
1043 if (candidate.finishing) {
1046 if (candidate.realActivity.equals(realActivity)) {
1053 /** Updates the last task description values. */
1054 void updateTaskDescription() {
1055 // Traverse upwards looking for any break between main task activities and
1056 // utility activities.
1058 final int numActivities = mActivities.size();
1059 final boolean relinquish = numActivities == 0 ? false :
1060 (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0;
1061 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
1063 final ActivityRecord r = mActivities.get(activityNdx);
1064 if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1065 // This will be the top activity for determining taskDescription. Pre-inc to
1066 // overcome initial decrement below.
1070 if (r.intent != null &&
1071 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1075 if (activityNdx > 0) {
1076 // Traverse downwards starting below break looking for set label, icon.
1077 // Note that if there are activities in the task but none of them set the
1078 // recent activity values, then we do not fall back to the last set
1079 // values in the TaskRecord.
1080 String label = null;
1081 String iconFilename = null;
1082 int colorPrimary = 0;
1083 int colorBackground = 0;
1084 for (--activityNdx; activityNdx >= 0; --activityNdx) {
1085 final ActivityRecord r = mActivities.get(activityNdx);
1086 if (r.taskDescription != null) {
1087 if (label == null) {
1088 label = r.taskDescription.getLabel();
1090 if (iconFilename == null) {
1091 iconFilename = r.taskDescription.getIconFilename();
1093 if (colorPrimary == 0) {
1094 colorPrimary = r.taskDescription.getPrimaryColor();
1096 if (colorBackground == 0) {
1097 colorBackground = r.taskDescription.getBackgroundColor();
1101 lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
1103 // Update the task affiliation color if we are the parent of the group
1104 if (taskId == mAffiliatedTaskId) {
1105 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
1110 int findEffectiveRootIndex() {
1111 int effectiveNdx = 0;
1112 final int topActivityNdx = mActivities.size() - 1;
1113 for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
1114 final ActivityRecord r = mActivities.get(activityNdx);
1118 effectiveNdx = activityNdx;
1119 if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1123 return effectiveNdx;
1126 void updateEffectiveIntent() {
1127 final int effectiveRootIndex = findEffectiveRootIndex();
1128 final ActivityRecord r = mActivities.get(effectiveRootIndex);
1132 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
1133 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
1135 out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
1136 if (realActivity != null) {
1137 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
1139 out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
1140 if (origActivity != null) {
1141 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
1143 // Write affinity, and root affinity if it is different from affinity.
1144 // We use the special string "@" for a null root affinity, so we can identify
1145 // later whether we were given a root affinity or should just make it the
1146 // same as the affinity.
1147 if (affinity != null) {
1148 out.attribute(null, ATTR_AFFINITY, affinity);
1149 if (!affinity.equals(rootAffinity)) {
1150 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
1152 } else if (rootAffinity != null) {
1153 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
1155 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
1156 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
1157 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
1158 out.attribute(null, ATTR_USERID, String.valueOf(userId));
1159 out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
1160 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
1161 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
1162 out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
1163 out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime));
1164 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
1165 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
1166 if (lastDescription != null) {
1167 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
1169 if (lastTaskDescription != null) {
1170 lastTaskDescription.saveToXml(out);
1172 mLastThumbnailInfo.saveToXml(out);
1173 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
1174 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
1175 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
1176 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
1177 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
1178 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
1179 out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
1180 out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
1181 if (mLastNonFullscreenBounds != null) {
1183 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
1185 out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
1186 out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
1188 if (affinityIntent != null) {
1189 out.startTag(null, TAG_AFFINITYINTENT);
1190 affinityIntent.saveToXml(out);
1191 out.endTag(null, TAG_AFFINITYINTENT);
1194 out.startTag(null, TAG_INTENT);
1195 intent.saveToXml(out);
1196 out.endTag(null, TAG_INTENT);
1198 final ArrayList<ActivityRecord> activities = mActivities;
1199 final int numActivities = activities.size();
1200 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
1201 final ActivityRecord r = activities.get(activityNdx);
1202 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
1203 ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
1204 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
1206 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
1209 out.startTag(null, TAG_ACTIVITY);
1211 out.endTag(null, TAG_ACTIVITY);
1215 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
1216 throws IOException, XmlPullParserException {
1217 Intent intent = null;
1218 Intent affinityIntent = null;
1219 ArrayList<ActivityRecord> activities = new ArrayList<>();
1220 ComponentName realActivity = null;
1221 boolean realActivitySuspended = false;
1222 ComponentName origActivity = null;
1223 String affinity = null;
1224 String rootAffinity = null;
1225 boolean hasRootAffinity = false;
1226 boolean rootHasReset = false;
1227 boolean autoRemoveRecents = false;
1228 boolean askedCompatMode = false;
1229 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
1231 boolean userSetupComplete = true;
1232 int effectiveUid = -1;
1233 String lastDescription = null;
1234 long firstActiveTime = -1;
1235 long lastActiveTime = -1;
1236 long lastTimeOnTop = 0;
1237 boolean neverRelinquishIdentity = true;
1238 int taskId = INVALID_TASK_ID;
1239 final int outerDepth = in.getDepth();
1240 TaskDescription taskDescription = new TaskDescription();
1241 TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo();
1242 int taskAffiliation = INVALID_TASK_ID;
1243 int taskAffiliationColor = 0;
1244 int prevTaskId = INVALID_TASK_ID;
1245 int nextTaskId = INVALID_TASK_ID;
1246 int callingUid = -1;
1247 String callingPackage = "";
1248 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
1249 boolean privileged = false;
1251 int minWidth = INVALID_MIN_SIZE;
1252 int minHeight = INVALID_MIN_SIZE;
1254 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
1255 final String attrName = in.getAttributeName(attrNdx);
1256 final String attrValue = in.getAttributeValue(attrNdx);
1257 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
1258 attrName + " value=" + attrValue);
1259 if (ATTR_TASKID.equals(attrName)) {
1260 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
1261 } else if (ATTR_REALACTIVITY.equals(attrName)) {
1262 realActivity = ComponentName.unflattenFromString(attrValue);
1263 } else if (ATTR_REALACTIVITY_SUSPENDED.equals(attrName)) {
1264 realActivitySuspended = Boolean.valueOf(attrValue);
1265 } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
1266 origActivity = ComponentName.unflattenFromString(attrValue);
1267 } else if (ATTR_AFFINITY.equals(attrName)) {
1268 affinity = attrValue;
1269 } else if (ATTR_ROOT_AFFINITY.equals(attrName)) {
1270 rootAffinity = attrValue;
1271 hasRootAffinity = true;
1272 } else if (ATTR_ROOTHASRESET.equals(attrName)) {
1273 rootHasReset = Boolean.valueOf(attrValue);
1274 } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) {
1275 autoRemoveRecents = Boolean.valueOf(attrValue);
1276 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
1277 askedCompatMode = Boolean.valueOf(attrValue);
1278 } else if (ATTR_USERID.equals(attrName)) {
1279 userId = Integer.parseInt(attrValue);
1280 } else if (ATTR_USER_SETUP_COMPLETE.equals(attrName)) {
1281 userSetupComplete = Boolean.valueOf(attrValue);
1282 } else if (ATTR_EFFECTIVE_UID.equals(attrName)) {
1283 effectiveUid = Integer.parseInt(attrValue);
1284 } else if (ATTR_TASKTYPE.equals(attrName)) {
1285 taskType = Integer.parseInt(attrValue);
1286 } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) {
1287 firstActiveTime = Long.valueOf(attrValue);
1288 } else if (ATTR_LASTACTIVETIME.equals(attrName)) {
1289 lastActiveTime = Long.valueOf(attrValue);
1290 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
1291 lastDescription = attrValue;
1292 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
1293 lastTimeOnTop = Long.valueOf(attrValue);
1294 } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
1295 neverRelinquishIdentity = Boolean.valueOf(attrValue);
1296 } else if (attrName.startsWith(TaskThumbnailInfo.ATTR_TASK_THUMBNAILINFO_PREFIX)) {
1297 thumbnailInfo.restoreFromXml(attrName, attrValue);
1298 } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
1299 taskDescription.restoreFromXml(attrName, attrValue);
1300 } else if (ATTR_TASK_AFFILIATION.equals(attrName)) {
1301 taskAffiliation = Integer.parseInt(attrValue);
1302 } else if (ATTR_PREV_AFFILIATION.equals(attrName)) {
1303 prevTaskId = Integer.parseInt(attrValue);
1304 } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) {
1305 nextTaskId = Integer.parseInt(attrValue);
1306 } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) {
1307 taskAffiliationColor = Integer.parseInt(attrValue);
1308 } else if (ATTR_CALLING_UID.equals(attrName)) {
1309 callingUid = Integer.parseInt(attrValue);
1310 } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
1311 callingPackage = attrValue;
1312 } else if (ATTR_RESIZE_MODE.equals(attrName)) {
1313 resizeMode = Integer.parseInt(attrValue);
1314 resizeMode = (resizeMode == RESIZE_MODE_CROP_WINDOWS)
1315 ? RESIZE_MODE_FORCE_RESIZEABLE : resizeMode;
1316 } else if (ATTR_PRIVILEGED.equals(attrName)) {
1317 privileged = Boolean.valueOf(attrValue);
1318 } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
1319 bounds = Rect.unflattenFromString(attrValue);
1320 } else if (ATTR_MIN_WIDTH.equals(attrName)) {
1321 minWidth = Integer.parseInt(attrValue);
1322 } else if (ATTR_MIN_HEIGHT.equals(attrName)) {
1323 minHeight = Integer.parseInt(attrValue);
1325 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
1330 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
1331 (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
1332 if (event == XmlPullParser.START_TAG) {
1333 final String name = in.getName();
1334 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
1336 if (TAG_AFFINITYINTENT.equals(name)) {
1337 affinityIntent = Intent.restoreFromXml(in);
1338 } else if (TAG_INTENT.equals(name)) {
1339 intent = Intent.restoreFromXml(in);
1340 } else if (TAG_ACTIVITY.equals(name)) {
1341 ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor);
1342 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
1344 if (activity != null) {
1345 activities.add(activity);
1348 Slog.e(TAG, "restoreTask: Unexpected name=" + name);
1349 XmlUtils.skipCurrentTag(in);
1353 if (!hasRootAffinity) {
1354 rootAffinity = affinity;
1355 } else if ("@".equals(rootAffinity)) {
1356 rootAffinity = null;
1358 if (effectiveUid <= 0) {
1359 Intent checkIntent = intent != null ? intent : affinityIntent;
1361 if (checkIntent != null) {
1362 IPackageManager pm = AppGlobals.getPackageManager();
1364 ApplicationInfo ai = pm.getApplicationInfo(
1365 checkIntent.getComponent().getPackageName(),
1366 PackageManager.GET_UNINSTALLED_PACKAGES
1367 | PackageManager.GET_DISABLED_COMPONENTS, userId);
1369 effectiveUid = ai.uid;
1371 } catch (RemoteException e) {
1374 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
1375 + ": effectiveUid=" + effectiveUid);
1378 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
1379 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
1380 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
1381 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
1382 taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
1383 taskAffiliationColor, callingUid, callingPackage, resizeMode, privileged,
1384 realActivitySuspended, userSetupComplete, minWidth, minHeight);
1385 task.updateOverrideConfiguration(bounds);
1387 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
1388 activities.get(activityNdx).task = task;
1391 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
1395 private void adjustForMinimalTaskDimensions(Rect bounds) {
1396 if (bounds == null) {
1399 int minWidth = mMinWidth;
1400 int minHeight = mMinHeight;
1401 // If the task has no requested minimal size, we'd like to enforce a minimal size
1402 // so that the user can not render the task too small to manipulate. We don't need
1403 // to do this for the pinned stack as the bounds are controlled by the system.
1404 if (stack.mStackId != PINNED_STACK_ID) {
1405 if (minWidth == INVALID_MIN_SIZE) {
1406 minWidth = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask;
1408 if (minHeight == INVALID_MIN_SIZE) {
1409 minHeight = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask;
1412 final boolean adjustWidth = minWidth > bounds.width();
1413 final boolean adjustHeight = minHeight > bounds.height();
1414 if (!(adjustWidth || adjustHeight)) {
1419 if (mBounds != null && bounds.right == mBounds.right) {
1420 bounds.left = bounds.right - minWidth;
1422 // Either left bounds match, or neither match, or the previous bounds were
1423 // fullscreen and we default to keeping left.
1424 bounds.right = bounds.left + minWidth;
1428 if (mBounds != null && bounds.bottom == mBounds.bottom) {
1429 bounds.top = bounds.bottom - minHeight;
1431 // Either top bounds match, or neither match, or the previous bounds were
1432 // fullscreen and we default to keeping top.
1433 bounds.bottom = bounds.top + minHeight;
1439 * Update task's override configuration based on the bounds.
1440 * @param bounds The bounds of the task.
1441 * @return Update configuration or null if there is no change.
1443 Configuration updateOverrideConfiguration(Rect bounds) {
1444 return updateOverrideConfiguration(bounds, null /* insetBounds */);
1448 * Update task's override configuration based on the bounds.
1449 * @param bounds The bounds of the task.
1450 * @param insetBounds The bounds used to calculate the system insets, which is used here to
1451 * subtract the navigation bar/status bar size from the screen size reported
1452 * to the application. See {@link IActivityManager#resizeDockedStack}.
1453 * @return Update configuration or null if there is no change.
1455 Configuration updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) {
1456 if (Objects.equals(mBounds, bounds)) {
1459 final Configuration oldConfig = mOverrideConfig;
1460 final boolean oldFullscreen = mFullscreen;
1462 mFullscreen = bounds == null;
1464 if (mBounds != null && StackId.persistTaskBounds(stack.mStackId)) {
1465 mLastNonFullscreenBounds = mBounds;
1468 mOverrideConfig = Configuration.EMPTY;
1470 mTmpRect.set(bounds);
1471 adjustForMinimalTaskDimensions(mTmpRect);
1472 if (mBounds == null) {
1473 mBounds = new Rect(mTmpRect);
1475 mBounds.set(mTmpRect);
1477 if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {
1478 mLastNonFullscreenBounds = mBounds;
1480 mOverrideConfig = calculateOverrideConfig(mTmpRect, insetBounds,
1481 mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom);
1484 if (mFullscreen != oldFullscreen) {
1485 mService.mStackSupervisor.scheduleReportMultiWindowModeChanged(this);
1488 return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
1491 private void subtractNonDecorInsets(Rect inOutBounds, Rect inInsetBounds,
1492 boolean overrideWidth, boolean overrideHeight) {
1493 mTmpRect2.set(inInsetBounds);
1494 mService.mWindowManager.subtractNonDecorInsets(mTmpRect2);
1495 int leftInset = mTmpRect2.left - inInsetBounds.left;
1496 int topInset = mTmpRect2.top - inInsetBounds.top;
1497 int rightInset = overrideWidth ? 0 : inInsetBounds.right - mTmpRect2.right;
1498 int bottomInset = overrideHeight ? 0 : inInsetBounds.bottom - mTmpRect2.bottom;
1499 inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
1502 private void subtractStableInsets(Rect inOutBounds, Rect inInsetBounds,
1503 boolean overrideWidth, boolean overrideHeight) {
1504 mTmpRect2.set(inInsetBounds);
1505 mService.mWindowManager.subtractStableInsets(mTmpRect2);
1506 int leftInset = mTmpRect2.left - inInsetBounds.left;
1507 int topInset = mTmpRect2.top - inInsetBounds.top;
1508 int rightInset = overrideWidth ? 0 : inInsetBounds.right - mTmpRect2.right;
1509 int bottomInset = overrideHeight ? 0 : inInsetBounds.bottom - mTmpRect2.bottom;
1510 inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
1513 private Configuration calculateOverrideConfig(Rect bounds, Rect insetBounds,
1514 boolean overrideWidth, boolean overrideHeight) {
1515 mTmpNonDecorBounds.set(bounds);
1516 mTmpStableBounds.set(bounds);
1517 subtractNonDecorInsets(
1518 mTmpNonDecorBounds, insetBounds != null ? insetBounds : bounds,
1519 overrideWidth, overrideHeight);
1520 subtractStableInsets(
1521 mTmpStableBounds, insetBounds != null ? insetBounds : bounds,
1522 overrideWidth, overrideHeight);
1524 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen area,
1525 // i.e. the screen area without the system bars.
1526 final Configuration serviceConfig = mService.mConfiguration;
1527 final Configuration config = new Configuration(Configuration.EMPTY);
1528 // TODO(multidisplay): Update Dp to that of display stack is on.
1529 final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
1530 config.screenWidthDp =
1531 Math.min((int)(mTmpStableBounds.width() / density), serviceConfig.screenWidthDp);
1532 config.screenHeightDp =
1533 Math.min((int)(mTmpStableBounds.height() / density), serviceConfig.screenHeightDp);
1535 // TODO: Orientation?
1536 config.orientation = (config.screenWidthDp <= config.screenHeightDp)
1537 ? Configuration.ORIENTATION_PORTRAIT
1538 : Configuration.ORIENTATION_LANDSCAPE;
1540 // Always set fontScale to be euqal to global. Can't set to 0, as that makes the override
1541 // config not equal to EMPTY. Also can't set to 1, as Configuration.updateFrom will use
1542 // the override scale as long as it's non-zero, and we'll always use 1.
1543 config.fontScale = serviceConfig.fontScale;
1545 // For calculating screen layout, we need to use the non-decor inset screen area for the
1546 // calculation for compatibility reasons, i.e. screen area without system bars that could
1547 // never go away in Honeycomb.
1548 final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density);
1549 final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density);
1550 final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
1551 final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
1552 final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);;
1553 config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
1555 config.smallestScreenWidthDp = mService.mWindowManager.getSmallestWidthForTaskBounds(
1556 insetBounds != null ? insetBounds : bounds);
1561 * Using the existing configuration {@param config}, creates a new task override config such
1562 * that all the fields that are usually set in an override config are set to the ones in
1565 Configuration extractOverrideConfig(Configuration config) {
1566 final Configuration extracted = new Configuration(Configuration.EMPTY);
1567 extracted.screenWidthDp = config.screenWidthDp;
1568 extracted.screenHeightDp = config.screenHeightDp;
1569 extracted.smallestScreenWidthDp = config.smallestScreenWidthDp;
1570 extracted.orientation = config.orientation;
1571 extracted.screenLayout = config.screenLayout;
1572 extracted.fontScale = config.fontScale;
1576 Rect updateOverrideConfigurationFromLaunchBounds() {
1577 final Rect bounds = validateBounds(getLaunchBounds());
1578 updateOverrideConfiguration(bounds);
1579 if (bounds != null) {
1580 bounds.set(mBounds);
1586 * Update fields that are not overridden for task from global configuration.
1588 * @param globalConfig global configuration to update from.
1590 void sanitizeOverrideConfiguration(Configuration globalConfig) {
1591 // If it's fullscreen, the override config should be empty and we should leave it alone.
1596 // screenLayout field is set in #calculateOverrideConfig but only part of it is really
1597 // overridden - aspect ratio and size. Other flags (like layout direction) can be updated
1598 // separately in global config and they also must be updated in override config.
1599 int overrideScreenLayout = mOverrideConfig.screenLayout;
1600 int newScreenLayout = globalConfig.screenLayout;
1601 newScreenLayout = (newScreenLayout & ~SCREENLAYOUT_LONG_MASK)
1602 | (overrideScreenLayout & SCREENLAYOUT_LONG_MASK);
1603 newScreenLayout = (newScreenLayout & ~SCREENLAYOUT_SIZE_MASK)
1604 | (overrideScreenLayout & SCREENLAYOUT_SIZE_MASK);
1605 mOverrideConfig.screenLayout = newScreenLayout;
1606 // we never override the fontScale, however we need to copy over the global value
1607 // so that the default 1.0 doesn't get applied as an override.
1608 mOverrideConfig.fontScale = globalConfig.fontScale;
1611 static Rect validateBounds(Rect bounds) {
1612 if (bounds != null && bounds.isEmpty()) {
1613 Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable());
1619 /** Updates the task's bounds and override configuration to match what is expected for the
1621 void updateOverrideConfigurationForStack(ActivityStack inStack) {
1622 if (stack != null && stack == inStack) {
1626 if (inStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
1627 if (!isResizeable()) {
1628 throw new IllegalArgumentException("Can not position non-resizeable task="
1629 + this + " in stack=" + inStack);
1631 if (mBounds != null) {
1634 if (mLastNonFullscreenBounds != null) {
1635 updateOverrideConfiguration(mLastNonFullscreenBounds);
1637 inStack.layoutTaskInStack(this, null);
1640 updateOverrideConfiguration(inStack.mBounds);
1645 * Returns the correct stack to use based on task type and currently set bounds,
1646 * regardless of the focused stack and current stack association of the task.
1647 * The task will be moved (and stack focus changed) later if necessary.
1649 int getLaunchStackId() {
1650 if (!isApplicationTask()) {
1651 return HOME_STACK_ID;
1653 if (mBounds != null) {
1654 return FREEFORM_WORKSPACE_STACK_ID;
1656 return FULLSCREEN_WORKSPACE_STACK_ID;
1659 /** Returns the bounds that should be used to launch this task. */
1660 Rect getLaunchBounds() {
1661 // If we're over lockscreen, forget about stack bounds and use fullscreen.
1662 if (mService.mLockScreenShown == LOCK_SCREEN_SHOWN) {
1666 if (stack == null) {
1670 final int stackId = stack.mStackId;
1671 if (stackId == HOME_STACK_ID
1672 || stackId == FULLSCREEN_WORKSPACE_STACK_ID
1673 || (stackId == DOCKED_STACK_ID && !isResizeable())) {
1674 return isResizeable() ? stack.mBounds : null;
1675 } else if (!StackId.persistTaskBounds(stackId)) {
1676 return stack.mBounds;
1678 return mLastNonFullscreenBounds;
1681 boolean canMatchRootAffinity() {
1682 // We don't allow root affinity matching on the pinned stack as no other task should
1683 // be launching in it based on affinity.
1684 return rootAffinity != null && (stack == null || stack.mStackId != PINNED_STACK_ID);
1687 void dump(PrintWriter pw, String prefix) {
1688 pw.print(prefix); pw.print("userId="); pw.print(userId);
1689 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
1690 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
1691 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
1692 pw.print(" mCallingPackage="); pw.println(mCallingPackage);
1693 if (affinity != null || rootAffinity != null) {
1694 pw.print(prefix); pw.print("affinity="); pw.print(affinity);
1695 if (affinity == null || !affinity.equals(rootAffinity)) {
1696 pw.print(" root="); pw.println(rootAffinity);
1701 if (voiceSession != null || voiceInteractor != null) {
1702 pw.print(prefix); pw.print("VOICE: session=0x");
1703 pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
1704 pw.print(" interactor=0x");
1705 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
1707 if (intent != null) {
1708 StringBuilder sb = new StringBuilder(128);
1709 sb.append(prefix); sb.append("intent={");
1710 intent.toShortString(sb, false, true, false, true);
1712 pw.println(sb.toString());
1714 if (affinityIntent != null) {
1715 StringBuilder sb = new StringBuilder(128);
1716 sb.append(prefix); sb.append("affinityIntent={");
1717 affinityIntent.toShortString(sb, false, true, false, true);
1719 pw.println(sb.toString());
1721 if (origActivity != null) {
1722 pw.print(prefix); pw.print("origActivity=");
1723 pw.println(origActivity.flattenToShortString());
1725 if (realActivity != null) {
1726 pw.print(prefix); pw.print("realActivity=");
1727 pw.println(realActivity.flattenToShortString());
1729 if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0
1730 || numFullscreen != 0) {
1731 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
1732 pw.print(" isPersistable="); pw.print(isPersistable);
1733 pw.print(" numFullscreen="); pw.print(numFullscreen);
1734 pw.print(" taskType="); pw.print(taskType);
1735 pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
1737 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
1738 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
1739 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
1740 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
1741 pw.print(" mReuseTask="); pw.print(mReuseTask);
1742 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
1744 if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID
1745 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
1746 || mNextAffiliate != null) {
1747 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
1748 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
1750 if (mPrevAffiliate == null) {
1753 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
1755 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
1757 if (mNextAffiliate == null) {
1760 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
1764 pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
1765 if (!askedCompatMode || !inRecents || !isAvailable) {
1766 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
1767 pw.print(" inRecents="); pw.print(inRecents);
1768 pw.print(" isAvailable="); pw.println(isAvailable);
1770 pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail);
1771 pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile);
1772 if (lastDescription != null) {
1773 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
1775 if (stack != null) {
1776 pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId);
1778 pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
1779 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
1780 pw.print(" isResizeable=" + isResizeable());
1781 pw.print(" firstActiveTime=" + lastActiveTime);
1782 pw.print(" lastActiveTime=" + lastActiveTime);
1783 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
1787 public String toString() {
1788 StringBuilder sb = new StringBuilder(128);
1789 if (stringName != null) {
1790 sb.append(stringName);
1793 sb.append(" StackId=");
1794 sb.append(stack != null ? stack.mStackId : INVALID_STACK_ID);
1796 sb.append(mActivities.size());
1798 return sb.toString();
1800 sb.append("TaskRecord{");
1801 sb.append(Integer.toHexString(System.identityHashCode(this)));
1804 if (affinity != null) {
1806 sb.append(affinity);
1807 } else if (intent != null) {
1809 sb.append(intent.getComponent().flattenToShortString());
1810 } else if (affinityIntent != null) {
1812 sb.append(affinityIntent.getComponent().flattenToShortString());
1816 stringName = sb.toString();