TaskRecord.java revision dd3d44faf9d74a793458a515fddf153432601dd6
1/*
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
19import android.annotation.Nullable;
20import android.app.Activity;
21import android.app.ActivityManager;
22import android.app.ActivityManager.StackId;
23import android.app.ActivityManager.TaskDescription;
24import android.app.ActivityManager.TaskThumbnail;
25import android.app.ActivityManager.TaskThumbnailInfo;
26import android.app.ActivityOptions;
27import android.app.AppGlobals;
28import android.app.IActivityManager;
29import android.content.ComponentName;
30import android.content.Intent;
31import android.content.pm.ActivityInfo;
32import android.content.pm.ApplicationInfo;
33import android.content.pm.IPackageManager;
34import android.content.pm.PackageManager;
35import android.content.res.Configuration;
36import android.graphics.Bitmap;
37import android.graphics.Point;
38import android.graphics.Rect;
39import android.os.Debug;
40import android.os.ParcelFileDescriptor;
41import android.os.RemoteException;
42import android.os.UserHandle;
43import android.provider.Settings;
44import android.service.voice.IVoiceInteractionSession;
45import android.util.DisplayMetrics;
46import android.util.Slog;
47
48import com.android.internal.app.IVoiceInteractor;
49import com.android.internal.util.XmlUtils;
50
51import org.xmlpull.v1.XmlPullParser;
52import org.xmlpull.v1.XmlPullParserException;
53import org.xmlpull.v1.XmlSerializer;
54
55import java.io.File;
56import java.io.IOException;
57import java.io.PrintWriter;
58import java.util.ArrayList;
59import java.util.Objects;
60
61import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
62import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
63import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
64import static android.app.ActivityManager.StackId.HOME_STACK_ID;
65import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
66import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
67import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
68import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
69import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
70import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
71import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
72import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
73import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
74import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
75import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
76import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
77import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
78import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
79import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
80import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
81import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
82import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
83import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
84import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
85import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
86import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
87import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
88import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
89import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
90import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
91
92final class TaskRecord {
93    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
94    private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
95    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
96    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
97    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
98
99    static final String ATTR_TASKID = "task_id";
100    private static final String TAG_INTENT = "intent";
101    private static final String TAG_AFFINITYINTENT = "affinity_intent";
102    static final String ATTR_REALACTIVITY = "real_activity";
103    static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
104    private static final String ATTR_ORIGACTIVITY = "orig_activity";
105    private static final String TAG_ACTIVITY = "activity";
106    private static final String ATTR_AFFINITY = "affinity";
107    private static final String ATTR_ROOT_AFFINITY = "root_affinity";
108    private static final String ATTR_ROOTHASRESET = "root_has_reset";
109    private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
110    private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
111    private static final String ATTR_USERID = "user_id";
112    private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
113    private static final String ATTR_EFFECTIVE_UID = "effective_uid";
114    private static final String ATTR_TASKTYPE = "task_type";
115    private static final String ATTR_FIRSTACTIVETIME = "first_active_time";
116    private static final String ATTR_LASTACTIVETIME = "last_active_time";
117    private static final String ATTR_LASTDESCRIPTION = "last_description";
118    private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
119    private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
120    static final String ATTR_TASK_AFFILIATION = "task_affiliation";
121    private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
122    private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
123    private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
124    private static final String ATTR_CALLING_UID = "calling_uid";
125    private static final String ATTR_CALLING_PACKAGE = "calling_package";
126    private static final String ATTR_RESIZE_MODE = "resize_mode";
127    private static final String ATTR_PRIVILEGED = "privileged";
128    private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
129    private static final String ATTR_MINIMAL_WIDTH = "minimal_width";
130    private static final String ATTR_MINIMAL_HEIGHT = "minimal_height";
131
132
133    private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
134
135    static final int INVALID_TASK_ID = -1;
136    static final int INVALID_MINIMAL_SIZE = -1;
137
138    final int taskId;       // Unique identifier for this task.
139    String affinity;        // The affinity name for this task, or null; may change identity.
140    String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
141    final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
142    final IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
143    Intent intent;          // The original intent that started the task.
144    Intent affinityIntent;  // Intent of affinity-moved activity that started this task.
145    int effectiveUid;       // The current effective uid of the identity of this task.
146    ComponentName origActivity; // The non-alias activity component of the intent.
147    ComponentName realActivity; // The actual activity component that started the task.
148    boolean realActivitySuspended; // True if the actual activity component that started the
149                                   // task is suspended.
150    long firstActiveTime;   // First time this task was active.
151    long lastActiveTime;    // Last time this task was active, including sleep.
152    boolean inRecents;      // Actually in the recents list?
153    boolean isAvailable;    // Is the activity available to be launched?
154    boolean rootWasReset;   // True if the intent at the root of the task had
155                            // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
156    boolean autoRemoveRecents;  // If true, we should automatically remove the task from
157                                // recents when activity finishes
158    boolean askedCompatMode;// Have asked the user about compat mode for this task.
159    boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
160
161    String stringName;      // caching of toString() result.
162    int userId;             // user for which this task was created
163    boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
164                                // was changed.
165
166    int numFullscreen;      // Number of fullscreen activities.
167
168    int mResizeMode;        // The resize mode of this task and its activities.
169                            // Based on the {@link ActivityInfo#resizeMode} of the root activity.
170    boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
171                                     // changes on a temporary basis.
172    int mLockTaskMode;      // Which tasklock mode to launch this task in. One of
173                            // ActivityManager.LOCK_TASK_LAUNCH_MODE_*
174    private boolean mPrivileged;    // The root activity application of this task holds
175                                    // privileged permissions.
176
177    /** Can't be put in lockTask mode. */
178    final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
179    /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
180    final static int LOCK_TASK_AUTH_PINNABLE = 1;
181    /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
182    final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
183    /** Can enter lockTask without user approval. Can start over existing lockTask task. */
184    final static int LOCK_TASK_AUTH_WHITELISTED = 3;
185    /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
186     * lockTask task. */
187    final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
188    int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
189
190    int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
191
192    // This represents the last resolved activity values for this task
193    // NOTE: This value needs to be persisted with each task
194    TaskDescription lastTaskDescription = new TaskDescription();
195
196    /** List of all activities in the task arranged in history order */
197    final ArrayList<ActivityRecord> mActivities;
198
199    /** Current stack */
200    ActivityStack stack;
201
202    /** Takes on same set of values as ActivityRecord.mActivityType */
203    int taskType;
204
205    /** Takes on same value as first root activity */
206    boolean isPersistable = false;
207    int maxRecents;
208
209    /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
210     * determining the order when restoring. Sign indicates whether last task movement was to front
211     * (positive) or back (negative). Absolute value indicates time. */
212    long mLastTimeMoved = System.currentTimeMillis();
213
214    /** Indication of what to run next when task exits. Use ActivityRecord types.
215     * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
216     * task stack. */
217    private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
218
219    /** If original intent did not allow relinquishing task identity, save that information */
220    boolean mNeverRelinquishIdentity = true;
221
222    // Used in the unique case where we are clearing the task in order to reuse it. In that case we
223    // do not want to delete the stack when the task goes empty.
224    private boolean mReuseTask = false;
225
226    private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
227    private final File mLastThumbnailFile; // File containing last thumbnail.
228    private final String mFilename;
229    private TaskThumbnailInfo mLastThumbnailInfo;
230    CharSequence lastDescription; // Last description captured for this item.
231
232    int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
233    int mAffiliatedTaskColor; // color of the parent task affiliation.
234    TaskRecord mPrevAffiliate; // previous task in affiliated chain.
235    int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
236    TaskRecord mNextAffiliate; // next task in affiliated chain.
237    int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
238
239    // For relaunching the task from recents as though it was launched by the original launcher.
240    int mCallingUid;
241    String mCallingPackage;
242
243    final ActivityManagerService mService;
244
245    // Whether or not this task covers the entire screen; by default tasks are fullscreen.
246    boolean mFullscreen = true;
247
248    // Bounds of the Task. null for fullscreen tasks.
249    Rect mBounds = null;
250    private final Rect mTmpStableBounds = new Rect();
251    private final Rect mTmpNonDecorBounds = new Rect();
252    private final Rect mTmpRect = new Rect();
253    private final Rect mTmpRect2 = new Rect();
254
255    // Last non-fullscreen bounds the task was launched in or resized to.
256    // The information is persisted and used to determine the appropriate stack to launch the
257    // task into on restore.
258    Rect mLastNonFullscreenBounds = null;
259    // Minimal width and height of this task when it's resizeable. -1 means it should use the
260    // default minimal width/height.
261    int mMinimalWidth;
262    int mMinimalHeight;
263
264    // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
265    // This number will be assigned when we evaluate OOM scores for all visible tasks.
266    int mLayerRank = -1;
267
268    Configuration mOverrideConfig = Configuration.EMPTY;
269
270    TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
271            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
272        mService = service;
273        mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
274                TaskPersister.IMAGE_EXTENSION;
275        userId = UserHandle.getUserId(info.applicationInfo.uid);
276        mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
277        mLastThumbnailInfo = new TaskThumbnailInfo();
278        taskId = _taskId;
279        mAffiliatedTaskId = _taskId;
280        voiceSession = _voiceSession;
281        voiceInteractor = _voiceInteractor;
282        isAvailable = true;
283        mActivities = new ArrayList<>();
284        mCallingUid = info.applicationInfo.uid;
285        mCallingPackage = info.packageName;
286        setIntent(_intent, info);
287        setMinDimensions(info);
288        touchActiveTime();
289    }
290
291    TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
292            TaskDescription _taskDescription, TaskThumbnailInfo thumbnailInfo) {
293        mService = service;
294        mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
295                TaskPersister.IMAGE_EXTENSION;
296        userId = UserHandle.getUserId(info.applicationInfo.uid);
297        mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
298        mLastThumbnailInfo = thumbnailInfo;
299        taskId = _taskId;
300        mAffiliatedTaskId = _taskId;
301        voiceSession = null;
302        voiceInteractor = null;
303        isAvailable = true;
304        mActivities = new ArrayList<>();
305        mCallingUid = info.applicationInfo.uid;
306        mCallingPackage = info.packageName;
307        setIntent(_intent, info);
308        setMinDimensions(info);
309
310        taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
311        isPersistable = true;
312        // Clamp to [1, max].
313        maxRecents = Math.min(Math.max(info.maxRecents, 1),
314                ActivityManager.getMaxAppRecentsLimitStatic());
315
316        taskType = APPLICATION_ACTIVITY_TYPE;
317        mTaskToReturnTo = HOME_ACTIVITY_TYPE;
318        lastTaskDescription = _taskDescription;
319        touchActiveTime();
320    }
321
322    private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
323            Intent _affinityIntent, String _affinity, String _rootAffinity,
324            ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
325            boolean _autoRemoveRecents, boolean _askedCompatMode, int _taskType, int _userId,
326            int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
327            long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
328            boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
329            TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
330            int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
331            int resizeMode, boolean privileged, boolean _realActivitySuspended,
332            boolean userSetupComplete, int minimalWidth, int minimalHeight) {
333        mService = service;
334        mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
335                TaskPersister.IMAGE_EXTENSION;
336        mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(_userId), mFilename);
337        mLastThumbnailInfo = lastThumbnailInfo;
338        taskId = _taskId;
339        intent = _intent;
340        affinityIntent = _affinityIntent;
341        affinity = _affinity;
342        rootAffinity = _rootAffinity;
343        voiceSession = null;
344        voiceInteractor = null;
345        realActivity = _realActivity;
346        realActivitySuspended = _realActivitySuspended;
347        origActivity = _origActivity;
348        rootWasReset = _rootWasReset;
349        isAvailable = true;
350        autoRemoveRecents = _autoRemoveRecents;
351        askedCompatMode = _askedCompatMode;
352        taskType = _taskType;
353        mTaskToReturnTo = HOME_ACTIVITY_TYPE;
354        userId = _userId;
355        mUserSetupComplete = userSetupComplete;
356        effectiveUid = _effectiveUid;
357        firstActiveTime = _firstActiveTime;
358        lastActiveTime = _lastActiveTime;
359        lastDescription = _lastDescription;
360        mActivities = activities;
361        mLastTimeMoved = lastTimeMoved;
362        mNeverRelinquishIdentity = neverRelinquishIdentity;
363        lastTaskDescription = _lastTaskDescription;
364        mAffiliatedTaskId = taskAffiliation;
365        mAffiliatedTaskColor = taskAffiliationColor;
366        mPrevAffiliateTaskId = prevTaskId;
367        mNextAffiliateTaskId = nextTaskId;
368        mCallingUid = callingUid;
369        mCallingPackage = callingPackage;
370        mResizeMode = resizeMode;
371        mPrivileged = privileged;
372        mMinimalWidth = minimalWidth;
373        mMinimalHeight = minimalHeight;
374    }
375
376    void touchActiveTime() {
377        lastActiveTime = System.currentTimeMillis();
378        if (firstActiveTime == 0) {
379            firstActiveTime = lastActiveTime;
380        }
381    }
382
383    long getInactiveDuration() {
384        return System.currentTimeMillis() - lastActiveTime;
385    }
386
387    /** Sets the original intent, and the calling uid and package. */
388    void setIntent(ActivityRecord r) {
389        mCallingUid = r.launchedFromUid;
390        mCallingPackage = r.launchedFromPackage;
391        setIntent(r.intent, r.info);
392    }
393
394    /** Sets the original intent, _without_ updating the calling uid or package. */
395    private void setIntent(Intent _intent, ActivityInfo info) {
396        if (intent == null) {
397            mNeverRelinquishIdentity =
398                    (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
399        } else if (mNeverRelinquishIdentity) {
400            return;
401        }
402
403        affinity = info.taskAffinity;
404        if (intent == null) {
405            // If this task already has an intent associated with it, don't set the root
406            // affinity -- we don't want it changing after initially set, but the initially
407            // set value may be null.
408            rootAffinity = affinity;
409        }
410        effectiveUid = info.applicationInfo.uid;
411        stringName = null;
412
413        if (info.targetActivity == null) {
414            if (_intent != null) {
415                // If this Intent has a selector, we want to clear it for the
416                // recent task since it is not relevant if the user later wants
417                // to re-launch the app.
418                if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
419                    _intent = new Intent(_intent);
420                    _intent.setSelector(null);
421                    _intent.setSourceBounds(null);
422                }
423            }
424            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
425            intent = _intent;
426            realActivity = _intent != null ? _intent.getComponent() : null;
427            origActivity = null;
428        } else {
429            ComponentName targetComponent = new ComponentName(
430                    info.packageName, info.targetActivity);
431            if (_intent != null) {
432                Intent targetIntent = new Intent(_intent);
433                targetIntent.setComponent(targetComponent);
434                targetIntent.setSelector(null);
435                targetIntent.setSourceBounds(null);
436                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
437                        "Setting Intent of " + this + " to target " + targetIntent);
438                intent = targetIntent;
439                realActivity = targetComponent;
440                origActivity = _intent.getComponent();
441            } else {
442                intent = null;
443                realActivity = targetComponent;
444                origActivity = new ComponentName(info.packageName, info.name);
445            }
446        }
447
448        final int intentFlags = intent == null ? 0 : intent.getFlags();
449        if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
450            // Once we are set to an Intent with this flag, we count this
451            // task as having a true root activity.
452            rootWasReset = true;
453        }
454        userId = UserHandle.getUserId(info.applicationInfo.uid);
455        mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
456                USER_SETUP_COMPLETE, 0, userId) != 0;
457        if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
458            // If the activity itself has requested auto-remove, then just always do it.
459            autoRemoveRecents = true;
460        } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
461                == FLAG_ACTIVITY_NEW_DOCUMENT) {
462            // If the caller has not asked for the document to be retained, then we may
463            // want to turn on auto-remove, depending on whether the target has set its
464            // own document launch mode.
465            if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
466                autoRemoveRecents = false;
467            } else {
468                autoRemoveRecents = true;
469            }
470        } else {
471            autoRemoveRecents = false;
472        }
473        mResizeMode = info.resizeMode;
474        mLockTaskMode = info.lockTaskLaunchMode;
475        mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
476        setLockTaskAuth();
477    }
478
479    /** Sets the original minimal width and height. */
480    private void setMinDimensions(ActivityInfo info) {
481        if (info != null && info.windowLayout != null) {
482            mMinimalWidth = info.windowLayout.minimalWidth;
483            mMinimalHeight = info.windowLayout.minimalHeight;
484        } else {
485            mMinimalWidth = INVALID_MINIMAL_SIZE;
486            mMinimalHeight = INVALID_MINIMAL_SIZE;
487        }
488    }
489
490    /**
491     * Return true if the input activity has the same intent resolution as the intent this task
492     * record is based on (normally the root activity intent).
493     */
494    boolean isSameIntentResolution(ActivityRecord r) {
495        final Intent intent = new Intent(r.intent);
496        // Correct the activity intent for aliasing. The task record intent will always be based on
497        // the real activity that will be launched not the alias, so we need to use an intent with
498        // the component name pointing to the real activity not the alias in the activity record.
499        intent.setComponent(r.realActivity);
500        return this.intent.filterEquals(intent);
501    }
502
503    void setTaskToReturnTo(int taskToReturnTo) {
504        mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE)
505                ? HOME_ACTIVITY_TYPE : taskToReturnTo;
506    }
507
508    int getTaskToReturnTo() {
509        return mTaskToReturnTo;
510    }
511
512    void setPrevAffiliate(TaskRecord prevAffiliate) {
513        mPrevAffiliate = prevAffiliate;
514        mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.taskId;
515    }
516
517    void setNextAffiliate(TaskRecord nextAffiliate) {
518        mNextAffiliate = nextAffiliate;
519        mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId;
520    }
521
522    // Close up recents linked list.
523    void closeRecentsChain() {
524        if (mPrevAffiliate != null) {
525            mPrevAffiliate.setNextAffiliate(mNextAffiliate);
526        }
527        if (mNextAffiliate != null) {
528            mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
529        }
530        setPrevAffiliate(null);
531        setNextAffiliate(null);
532    }
533
534    void removedFromRecents() {
535        disposeThumbnail();
536        closeRecentsChain();
537        if (inRecents) {
538            inRecents = false;
539            mService.notifyTaskPersisterLocked(this, false);
540        }
541    }
542
543    void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
544        closeRecentsChain();
545        mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
546        mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
547        // Find the end
548        while (taskToAffiliateWith.mNextAffiliate != null) {
549            final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
550            if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
551                Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
552                        + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
553                if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
554                    nextRecents.setPrevAffiliate(null);
555                }
556                taskToAffiliateWith.setNextAffiliate(null);
557                break;
558            }
559            taskToAffiliateWith = nextRecents;
560        }
561        taskToAffiliateWith.setNextAffiliate(this);
562        setPrevAffiliate(taskToAffiliateWith);
563        setNextAffiliate(null);
564    }
565
566    /**
567     * Sets the last thumbnail with the current task bounds and the system orientation.
568     * @return whether the thumbnail was set
569     */
570    boolean setLastThumbnailLocked(Bitmap thumbnail) {
571        final Configuration serviceConfig = mService.mConfiguration;
572        int taskWidth = 0;
573        int taskHeight = 0;
574        if (mBounds != null) {
575            // Non-fullscreen tasks
576            taskWidth = mBounds.width();
577            taskHeight = mBounds.height();
578        } else if (stack != null) {
579            // Fullscreen tasks
580            final Point displaySize = new Point();
581            stack.getDisplaySize(displaySize);
582            taskWidth = displaySize.x;
583            taskHeight = displaySize.y;
584        } else {
585            Slog.e(TAG, "setLastThumbnailLocked() called on Task without stack");
586        }
587        return setLastThumbnailLocked(thumbnail, taskWidth, taskHeight, serviceConfig.orientation);
588    }
589
590    /**
591     * Sets the last thumbnail with the current task bounds.
592     * @return whether the thumbnail was set
593     */
594    private boolean setLastThumbnailLocked(Bitmap thumbnail, int taskWidth, int taskHeight,
595            int screenOrientation) {
596        if (mLastThumbnail != thumbnail) {
597            mLastThumbnail = thumbnail;
598            mLastThumbnailInfo.taskWidth = taskWidth;
599            mLastThumbnailInfo.taskHeight = taskHeight;
600            mLastThumbnailInfo.screenOrientation = screenOrientation;
601            if (thumbnail == null) {
602                if (mLastThumbnailFile != null) {
603                    mLastThumbnailFile.delete();
604                }
605            } else {
606                mService.mRecentTasks.saveImage(thumbnail, mLastThumbnailFile.getAbsolutePath());
607            }
608            return true;
609        }
610        return false;
611    }
612
613    void getLastThumbnail(TaskThumbnail thumbs) {
614        thumbs.mainThumbnail = mLastThumbnail;
615        thumbs.thumbnailInfo = mLastThumbnailInfo;
616        thumbs.thumbnailFileDescriptor = null;
617        if (mLastThumbnail == null) {
618            thumbs.mainThumbnail = mService.mRecentTasks.getImageFromWriteQueue(
619                    mLastThumbnailFile.getAbsolutePath());
620        }
621        // Only load the thumbnail file if we don't have a thumbnail
622        if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) {
623            try {
624                thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
625                        ParcelFileDescriptor.MODE_READ_ONLY);
626            } catch (IOException e) {
627            }
628        }
629    }
630
631    /**
632     * Removes in-memory thumbnail data when the max number of in-memory task thumbnails is reached.
633     */
634    void freeLastThumbnail() {
635        mLastThumbnail = null;
636    }
637
638    /**
639     * Removes all associated thumbnail data when a task is removed or pruned from recents.
640     */
641    void disposeThumbnail() {
642        mLastThumbnailInfo.reset();
643        mLastThumbnail = null;
644        lastDescription = null;
645    }
646
647    /** Returns the intent for the root activity for this task */
648    Intent getBaseIntent() {
649        return intent != null ? intent : affinityIntent;
650    }
651
652    /** Returns the first non-finishing activity from the root. */
653    ActivityRecord getRootActivity() {
654        for (int i = 0; i < mActivities.size(); i++) {
655            final ActivityRecord r = mActivities.get(i);
656            if (r.finishing) {
657                continue;
658            }
659            return r;
660        }
661        return null;
662    }
663
664    ActivityRecord getTopActivity() {
665        for (int i = mActivities.size() - 1; i >= 0; --i) {
666            final ActivityRecord r = mActivities.get(i);
667            if (r.finishing) {
668                continue;
669            }
670            return r;
671        }
672        return null;
673    }
674
675    ActivityRecord topRunningActivityLocked() {
676        if (stack != null) {
677            for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
678                ActivityRecord r = mActivities.get(activityNdx);
679                if (!r.finishing && stack.okToShowLocked(r)) {
680                    return r;
681                }
682            }
683        }
684        return null;
685    }
686
687    void setFrontOfTask() {
688        setFrontOfTask(null);
689    }
690
691    /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
692    void setFrontOfTask(ActivityRecord newTop) {
693        // If a top candidate is suggested by the caller, go ahead and use it and mark all others
694        // as not front. This is needed in situations where the current front activity in the
695        // task isn't finished yet and we want to set the front to the activity moved to the front
696        // of the task.
697        boolean foundFront = newTop != null ? true : false;
698
699        final int numActivities = mActivities.size();
700        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
701            final ActivityRecord r = mActivities.get(activityNdx);
702            if (foundFront || r.finishing) {
703                r.frontOfTask = false;
704            } else {
705                r.frontOfTask = true;
706                // Set frontOfTask false for every following activity.
707                foundFront = true;
708            }
709        }
710        if (!foundFront && numActivities > 0) {
711            // All activities of this task are finishing. As we ought to have a frontOfTask
712            // activity, make the bottom activity front.
713            mActivities.get(0).frontOfTask = true;
714        }
715        if (newTop != null) {
716            newTop.frontOfTask = true;
717        }
718    }
719
720    /**
721     * Reorder the history stack so that the passed activity is brought to the front.
722     */
723    final void moveActivityToFrontLocked(ActivityRecord newTop) {
724        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
725                "Removing and adding activity " + newTop
726                + " to stack at top callers=" + Debug.getCallers(4));
727
728        mActivities.remove(newTop);
729        mActivities.add(newTop);
730        updateEffectiveIntent();
731
732        setFrontOfTask(newTop);
733    }
734
735    void addActivityAtBottom(ActivityRecord r) {
736        addActivityAtIndex(0, r);
737    }
738
739    void addActivityToTop(ActivityRecord r) {
740        addActivityAtIndex(mActivities.size(), r);
741    }
742
743    void addActivityAtIndex(int index, ActivityRecord r) {
744        // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
745        if (!mActivities.remove(r) && r.fullscreen) {
746            // Was not previously in list.
747            numFullscreen++;
748        }
749        // Only set this based on the first activity
750        if (mActivities.isEmpty()) {
751            taskType = r.mActivityType;
752            isPersistable = r.isPersistable();
753            mCallingUid = r.launchedFromUid;
754            mCallingPackage = r.launchedFromPackage;
755            // Clamp to [1, max].
756            maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
757                    ActivityManager.getMaxAppRecentsLimitStatic());
758        } else {
759            // Otherwise make all added activities match this one.
760            r.mActivityType = taskType;
761        }
762        mActivities.add(index, r);
763        updateEffectiveIntent();
764        if (r.isPersistable()) {
765            mService.notifyTaskPersisterLocked(this, false);
766        }
767    }
768
769    /** @return true if this was the last activity in the task */
770    boolean removeActivity(ActivityRecord r) {
771        if (mActivities.remove(r) && r.fullscreen) {
772            // Was previously in list.
773            numFullscreen--;
774        }
775        if (r.isPersistable()) {
776            mService.notifyTaskPersisterLocked(this, false);
777        }
778
779        if (stack != null && stack.mStackId == PINNED_STACK_ID) {
780            // We normally notify listeners of task stack changes on pause, however pinned stack
781            // activities are normally in the paused state so no notification will be sent there
782            // before the activity is removed. We send it here so instead.
783            mService.notifyTaskStackChangedLocked();
784        }
785
786        if (mActivities.isEmpty()) {
787            return !mReuseTask;
788        }
789        updateEffectiveIntent();
790        return false;
791    }
792
793    boolean autoRemoveFromRecents() {
794        // We will automatically remove the task either if it has explicitly asked for
795        // this, or it is empty and has never contained an activity that got shown to
796        // the user.
797        return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible);
798    }
799
800    /**
801     * Completely remove all activities associated with an existing
802     * task starting at a specified index.
803     */
804    final void performClearTaskAtIndexLocked(int activityNdx) {
805        int numActivities = mActivities.size();
806        for ( ; activityNdx < numActivities; ++activityNdx) {
807            final ActivityRecord r = mActivities.get(activityNdx);
808            if (r.finishing) {
809                continue;
810            }
811            if (stack == null) {
812                // Task was restored from persistent storage.
813                r.takeFromHistory();
814                mActivities.remove(activityNdx);
815                --activityNdx;
816                --numActivities;
817            } else if (stack.finishActivityLocked(
818                    r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) {
819                --activityNdx;
820                --numActivities;
821            }
822        }
823    }
824
825    /**
826     * Completely remove all activities associated with an existing task.
827     */
828    final void performClearTaskLocked() {
829        mReuseTask = true;
830        performClearTaskAtIndexLocked(0);
831        mReuseTask = false;
832    }
833
834    ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
835        mReuseTask = true;
836        final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
837        mReuseTask = false;
838        return result;
839    }
840
841    /**
842     * Perform clear operation as requested by
843     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
844     * stack to the given task, then look for
845     * an instance of that activity in the stack and, if found, finish all
846     * activities on top of it and return the instance.
847     *
848     * @param newR Description of the new activity being started.
849     * @return Returns the old activity that should be continued to be used,
850     * or null if none was found.
851     */
852    final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
853        int numActivities = mActivities.size();
854        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
855            ActivityRecord r = mActivities.get(activityNdx);
856            if (r.finishing) {
857                continue;
858            }
859            if (r.realActivity.equals(newR.realActivity)) {
860                // Here it is!  Now finish everything in front...
861                final ActivityRecord ret = r;
862
863                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
864                    r = mActivities.get(activityNdx);
865                    if (r.finishing) {
866                        continue;
867                    }
868                    ActivityOptions opts = r.takeOptionsLocked();
869                    if (opts != null) {
870                        ret.updateOptionsLocked(opts);
871                    }
872                    if (stack != null && stack.finishActivityLocked(
873                            r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
874                        --activityNdx;
875                        --numActivities;
876                    }
877                }
878
879                // Finally, if this is a normal launch mode (that is, not
880                // expecting onNewIntent()), then we will finish the current
881                // instance of the activity so a new fresh one can be started.
882                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
883                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
884                    if (!ret.finishing) {
885                        if (stack != null) {
886                            stack.finishActivityLocked(
887                                    ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
888                        }
889                        return null;
890                    }
891                }
892
893                return ret;
894            }
895        }
896
897        return null;
898    }
899
900    public TaskThumbnail getTaskThumbnailLocked() {
901        if (stack != null) {
902            final ActivityRecord resumedActivity = stack.mResumedActivity;
903            if (resumedActivity != null && resumedActivity.task == this) {
904                final Bitmap thumbnail = stack.screenshotActivitiesLocked(resumedActivity);
905                setLastThumbnailLocked(thumbnail);
906            }
907        }
908        final TaskThumbnail taskThumbnail = new TaskThumbnail();
909        getLastThumbnail(taskThumbnail);
910        return taskThumbnail;
911    }
912
913    public void removeTaskActivitiesLocked() {
914        // Just remove the entire task.
915        performClearTaskAtIndexLocked(0);
916    }
917
918    String lockTaskAuthToString() {
919        switch (mLockTaskAuth) {
920            case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
921            case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
922            case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
923            case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
924            case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
925            default: return "unknown=" + mLockTaskAuth;
926        }
927    }
928
929    void setLockTaskAuth() {
930        if (!mPrivileged &&
931                (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS ||
932                        mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
933            // Non-priv apps are not allowed to use always or never, fall back to default
934            mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
935        }
936        switch (mLockTaskMode) {
937            case LOCK_TASK_LAUNCH_MODE_DEFAULT:
938                mLockTaskAuth = isLockTaskWhitelistedLocked() ?
939                    LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
940                break;
941
942            case LOCK_TASK_LAUNCH_MODE_NEVER:
943                mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
944                break;
945
946            case LOCK_TASK_LAUNCH_MODE_ALWAYS:
947                mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
948                break;
949
950            case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
951                mLockTaskAuth = isLockTaskWhitelistedLocked() ?
952                        LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
953                break;
954        }
955        if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
956                " mLockTaskAuth=" + lockTaskAuthToString());
957    }
958
959    boolean isLockTaskWhitelistedLocked() {
960        String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
961        if (pkg == null) {
962            return false;
963        }
964        String[] packages = mService.mLockTaskPackages.get(userId);
965        if (packages == null) {
966            return false;
967        }
968        for (int i = packages.length - 1; i >= 0; --i) {
969            if (pkg.equals(packages[i])) {
970                return true;
971            }
972        }
973        return false;
974    }
975
976    boolean isHomeTask() {
977        return taskType == HOME_ACTIVITY_TYPE;
978    }
979
980    boolean isRecentsTask() {
981        return taskType == RECENTS_ACTIVITY_TYPE;
982    }
983
984    boolean isApplicationTask() {
985        return taskType == APPLICATION_ACTIVITY_TYPE;
986    }
987
988    boolean isOverHomeStack() {
989        return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
990    }
991
992    boolean isResizeable() {
993        return !isHomeTask() && (mService.mForceResizableActivities
994                || ActivityInfo.isResizeableMode(mResizeMode)) && !mTemporarilyUnresizable;
995    }
996
997    boolean inCropWindowsResizeMode() {
998        return !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
999    }
1000
1001    boolean canGoInDockedStack() {
1002        return isResizeable() || inCropWindowsResizeMode();
1003    }
1004
1005    /**
1006     * Find the activity in the history stack within the given task.  Returns
1007     * the index within the history at which it's found, or < 0 if not found.
1008     */
1009    final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
1010        final ComponentName realActivity = r.realActivity;
1011        for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1012            ActivityRecord candidate = mActivities.get(activityNdx);
1013            if (candidate.finishing) {
1014                continue;
1015            }
1016            if (candidate.realActivity.equals(realActivity)) {
1017                return candidate;
1018            }
1019        }
1020        return null;
1021    }
1022
1023    /** Updates the last task description values. */
1024    void updateTaskDescription() {
1025        // Traverse upwards looking for any break between main task activities and
1026        // utility activities.
1027        int activityNdx;
1028        final int numActivities = mActivities.size();
1029        final boolean relinquish = numActivities == 0 ? false :
1030                (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0;
1031        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
1032                ++activityNdx) {
1033            final ActivityRecord r = mActivities.get(activityNdx);
1034            if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1035                // This will be the top activity for determining taskDescription. Pre-inc to
1036                // overcome initial decrement below.
1037                ++activityNdx;
1038                break;
1039            }
1040            if (r.intent != null &&
1041                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1042                break;
1043            }
1044        }
1045        if (activityNdx > 0) {
1046            // Traverse downwards starting below break looking for set label, icon.
1047            // Note that if there are activities in the task but none of them set the
1048            // recent activity values, then we do not fall back to the last set
1049            // values in the TaskRecord.
1050            String label = null;
1051            String iconFilename = null;
1052            int colorPrimary = 0;
1053            int colorBackground = 0;
1054            for (--activityNdx; activityNdx >= 0; --activityNdx) {
1055                final ActivityRecord r = mActivities.get(activityNdx);
1056                if (r.taskDescription != null) {
1057                    if (label == null) {
1058                        label = r.taskDescription.getLabel();
1059                    }
1060                    if (iconFilename == null) {
1061                        iconFilename = r.taskDescription.getIconFilename();
1062                    }
1063                    if (colorPrimary == 0) {
1064                        colorPrimary = r.taskDescription.getPrimaryColor();
1065                    }
1066                    if (colorBackground == 0) {
1067                        colorBackground = r.taskDescription.getBackgroundColor();
1068                    }
1069                }
1070            }
1071            lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
1072                    colorBackground);
1073            // Update the task affiliation color if we are the parent of the group
1074            if (taskId == mAffiliatedTaskId) {
1075                mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
1076            }
1077        }
1078    }
1079
1080    int findEffectiveRootIndex() {
1081        int effectiveNdx = 0;
1082        final int topActivityNdx = mActivities.size() - 1;
1083        for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
1084            final ActivityRecord r = mActivities.get(activityNdx);
1085            if (r.finishing) {
1086                continue;
1087            }
1088            effectiveNdx = activityNdx;
1089            if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1090                break;
1091            }
1092        }
1093        return effectiveNdx;
1094    }
1095
1096    void updateEffectiveIntent() {
1097        final int effectiveRootIndex = findEffectiveRootIndex();
1098        final ActivityRecord r = mActivities.get(effectiveRootIndex);
1099        setIntent(r);
1100    }
1101
1102    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
1103        if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
1104
1105        out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
1106        if (realActivity != null) {
1107            out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
1108        }
1109        out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
1110        if (origActivity != null) {
1111            out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
1112        }
1113        // Write affinity, and root affinity if it is different from affinity.
1114        // We use the special string "@" for a null root affinity, so we can identify
1115        // later whether we were given a root affinity or should just make it the
1116        // same as the affinity.
1117        if (affinity != null) {
1118            out.attribute(null, ATTR_AFFINITY, affinity);
1119            if (!affinity.equals(rootAffinity)) {
1120                out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
1121            }
1122        } else if (rootAffinity != null) {
1123            out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
1124        }
1125        out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
1126        out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
1127        out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
1128        out.attribute(null, ATTR_USERID, String.valueOf(userId));
1129        out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
1130        out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
1131        out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
1132        out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
1133        out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime));
1134        out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
1135        out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
1136        if (lastDescription != null) {
1137            out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
1138        }
1139        if (lastTaskDescription != null) {
1140            lastTaskDescription.saveToXml(out);
1141        }
1142        mLastThumbnailInfo.saveToXml(out);
1143        out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
1144        out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
1145        out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
1146        out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
1147        out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
1148        out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
1149        out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
1150        out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
1151        if (mLastNonFullscreenBounds != null) {
1152            out.attribute(
1153                    null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
1154        }
1155        out.attribute(null, ATTR_MINIMAL_WIDTH, String.valueOf(mMinimalWidth));
1156        out.attribute(null, ATTR_MINIMAL_HEIGHT, String.valueOf(mMinimalHeight));
1157
1158        if (affinityIntent != null) {
1159            out.startTag(null, TAG_AFFINITYINTENT);
1160            affinityIntent.saveToXml(out);
1161            out.endTag(null, TAG_AFFINITYINTENT);
1162        }
1163
1164        out.startTag(null, TAG_INTENT);
1165        intent.saveToXml(out);
1166        out.endTag(null, TAG_INTENT);
1167
1168        final ArrayList<ActivityRecord> activities = mActivities;
1169        final int numActivities = activities.size();
1170        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
1171            final ActivityRecord r = activities.get(activityNdx);
1172            if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
1173                    ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
1174                            | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
1175                            activityNdx > 0) {
1176                // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
1177                break;
1178            }
1179            out.startTag(null, TAG_ACTIVITY);
1180            r.saveToXml(out);
1181            out.endTag(null, TAG_ACTIVITY);
1182        }
1183    }
1184
1185    static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
1186            throws IOException, XmlPullParserException {
1187        Intent intent = null;
1188        Intent affinityIntent = null;
1189        ArrayList<ActivityRecord> activities = new ArrayList<>();
1190        ComponentName realActivity = null;
1191        boolean realActivitySuspended = false;
1192        ComponentName origActivity = null;
1193        String affinity = null;
1194        String rootAffinity = null;
1195        boolean hasRootAffinity = false;
1196        boolean rootHasReset = false;
1197        boolean autoRemoveRecents = false;
1198        boolean askedCompatMode = false;
1199        int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
1200        int userId = 0;
1201        boolean userSetupComplete = true;
1202        int effectiveUid = -1;
1203        String lastDescription = null;
1204        long firstActiveTime = -1;
1205        long lastActiveTime = -1;
1206        long lastTimeOnTop = 0;
1207        boolean neverRelinquishIdentity = true;
1208        int taskId = INVALID_TASK_ID;
1209        final int outerDepth = in.getDepth();
1210        TaskDescription taskDescription = new TaskDescription();
1211        TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo();
1212        int taskAffiliation = INVALID_TASK_ID;
1213        int taskAffiliationColor = 0;
1214        int prevTaskId = INVALID_TASK_ID;
1215        int nextTaskId = INVALID_TASK_ID;
1216        int callingUid = -1;
1217        String callingPackage = "";
1218        int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
1219        boolean privileged = false;
1220        Rect bounds = null;
1221        int minimalWidth = INVALID_MINIMAL_SIZE;
1222        int minimalHeight = INVALID_MINIMAL_SIZE;
1223
1224        for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
1225            final String attrName = in.getAttributeName(attrNdx);
1226            final String attrValue = in.getAttributeValue(attrNdx);
1227            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
1228                    attrName + " value=" + attrValue);
1229            if (ATTR_TASKID.equals(attrName)) {
1230                if (taskId == INVALID_TASK_ID) taskId = Integer.valueOf(attrValue);
1231            } else if (ATTR_REALACTIVITY.equals(attrName)) {
1232                realActivity = ComponentName.unflattenFromString(attrValue);
1233            } else if (ATTR_REALACTIVITY_SUSPENDED.equals(attrName)) {
1234                realActivitySuspended = Boolean.valueOf(attrValue);
1235            } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
1236                origActivity = ComponentName.unflattenFromString(attrValue);
1237            } else if (ATTR_AFFINITY.equals(attrName)) {
1238                affinity = attrValue;
1239            } else if (ATTR_ROOT_AFFINITY.equals(attrName)) {
1240                rootAffinity = attrValue;
1241                hasRootAffinity = true;
1242            } else if (ATTR_ROOTHASRESET.equals(attrName)) {
1243                rootHasReset = Boolean.valueOf(attrValue);
1244            } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) {
1245                autoRemoveRecents = Boolean.valueOf(attrValue);
1246            } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
1247                askedCompatMode = Boolean.valueOf(attrValue);
1248            } else if (ATTR_USERID.equals(attrName)) {
1249                userId = Integer.valueOf(attrValue);
1250            } else if (ATTR_USER_SETUP_COMPLETE.equals(attrName)) {
1251                userSetupComplete = Boolean.valueOf(attrValue);
1252            } else if (ATTR_EFFECTIVE_UID.equals(attrName)) {
1253                effectiveUid = Integer.valueOf(attrValue);
1254            } else if (ATTR_TASKTYPE.equals(attrName)) {
1255                taskType = Integer.valueOf(attrValue);
1256            } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) {
1257                firstActiveTime = Long.valueOf(attrValue);
1258            } else if (ATTR_LASTACTIVETIME.equals(attrName)) {
1259                lastActiveTime = Long.valueOf(attrValue);
1260            } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
1261                lastDescription = attrValue;
1262            } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
1263                lastTimeOnTop = Long.valueOf(attrValue);
1264            } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
1265                neverRelinquishIdentity = Boolean.valueOf(attrValue);
1266            } else if (attrName.startsWith(TaskThumbnailInfo.ATTR_TASK_THUMBNAILINFO_PREFIX)) {
1267                thumbnailInfo.restoreFromXml(attrName, attrValue);
1268            } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
1269                taskDescription.restoreFromXml(attrName, attrValue);
1270            } else if (ATTR_TASK_AFFILIATION.equals(attrName)) {
1271                taskAffiliation = Integer.valueOf(attrValue);
1272            } else if (ATTR_PREV_AFFILIATION.equals(attrName)) {
1273                prevTaskId = Integer.valueOf(attrValue);
1274            } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) {
1275                nextTaskId = Integer.valueOf(attrValue);
1276            } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) {
1277                taskAffiliationColor = Integer.valueOf(attrValue);
1278            } else if (ATTR_CALLING_UID.equals(attrName)) {
1279                callingUid = Integer.valueOf(attrValue);
1280            } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
1281                callingPackage = attrValue;
1282            } else if (ATTR_RESIZE_MODE.equals(attrName)) {
1283                resizeMode = Integer.valueOf(attrValue);
1284                resizeMode = (resizeMode == RESIZE_MODE_CROP_WINDOWS)
1285                        ? RESIZE_MODE_FORCE_RESIZEABLE : resizeMode;
1286            } else if (ATTR_PRIVILEGED.equals(attrName)) {
1287                privileged = Boolean.valueOf(attrValue);
1288            } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
1289                bounds = Rect.unflattenFromString(attrValue);
1290            } else if (ATTR_MINIMAL_WIDTH.equals(attrName)) {
1291                minimalWidth = Integer.valueOf(attrValue);
1292            } else if (ATTR_MINIMAL_HEIGHT.equals(attrName)) {
1293                minimalHeight = Integer.valueOf(attrValue);
1294            } else {
1295                Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
1296            }
1297        }
1298
1299        int event;
1300        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
1301                (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
1302            if (event == XmlPullParser.START_TAG) {
1303                final String name = in.getName();
1304                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
1305                        name);
1306                if (TAG_AFFINITYINTENT.equals(name)) {
1307                    affinityIntent = Intent.restoreFromXml(in);
1308                } else if (TAG_INTENT.equals(name)) {
1309                    intent = Intent.restoreFromXml(in);
1310                } else if (TAG_ACTIVITY.equals(name)) {
1311                    ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor);
1312                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
1313                            activity);
1314                    if (activity != null) {
1315                        activities.add(activity);
1316                    }
1317                } else {
1318                    Slog.e(TAG, "restoreTask: Unexpected name=" + name);
1319                    XmlUtils.skipCurrentTag(in);
1320                }
1321            }
1322        }
1323        if (!hasRootAffinity) {
1324            rootAffinity = affinity;
1325        } else if ("@".equals(rootAffinity)) {
1326            rootAffinity = null;
1327        }
1328        if (effectiveUid <= 0) {
1329            Intent checkIntent = intent != null ? intent : affinityIntent;
1330            effectiveUid = 0;
1331            if (checkIntent != null) {
1332                IPackageManager pm = AppGlobals.getPackageManager();
1333                try {
1334                    ApplicationInfo ai = pm.getApplicationInfo(
1335                            checkIntent.getComponent().getPackageName(),
1336                            PackageManager.GET_UNINSTALLED_PACKAGES
1337                                    | PackageManager.GET_DISABLED_COMPONENTS, userId);
1338                    if (ai != null) {
1339                        effectiveUid = ai.uid;
1340                    }
1341                } catch (RemoteException e) {
1342                }
1343            }
1344            Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
1345                    + ": effectiveUid=" + effectiveUid);
1346        }
1347
1348        final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
1349                affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
1350                autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
1351                activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
1352                taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
1353                taskAffiliationColor, callingUid, callingPackage, resizeMode, privileged,
1354                realActivitySuspended, userSetupComplete, minimalWidth, minimalHeight);
1355        task.updateOverrideConfiguration(bounds);
1356
1357        for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
1358            activities.get(activityNdx).task = task;
1359        }
1360
1361        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
1362        return task;
1363    }
1364
1365    private void adjustForMinimalTaskDimensions(Rect bounds) {
1366        if (bounds == null) {
1367            return;
1368        }
1369        int minimalWidth = mMinimalWidth;
1370        int minimalHeight = mMinimalHeight;
1371        // If the task has no requested minimal size, we'd like to enforce a minimal size
1372        // so that the user can not render the task too small to manipulate. We don't need
1373        // to do this for the pinned stack as the bounds are controlled by the system.
1374        if (stack.mStackId != PINNED_STACK_ID) {
1375            if (minimalWidth == INVALID_MINIMAL_SIZE) {
1376                minimalWidth = mService.mStackSupervisor.mDefaultMinimalSizeOfResizeableTask;
1377            }
1378            if (minimalHeight == INVALID_MINIMAL_SIZE) {
1379                minimalHeight = mService.mStackSupervisor.mDefaultMinimalSizeOfResizeableTask;
1380            }
1381        }
1382        final boolean adjustWidth = minimalWidth > bounds.width();
1383        final boolean adjustHeight = minimalHeight > bounds.height();
1384        if (!(adjustWidth || adjustHeight)) {
1385            return;
1386        }
1387
1388        if (adjustWidth) {
1389            if (mBounds != null && bounds.right == mBounds.right) {
1390                bounds.left = bounds.right - minimalWidth;
1391            } else {
1392                // Either left bounds match, or neither match, or the previous bounds were
1393                // fullscreen and we default to keeping left.
1394                bounds.right = bounds.left + minimalWidth;
1395            }
1396        }
1397        if (adjustHeight) {
1398            if (mBounds != null && bounds.bottom == mBounds.bottom) {
1399                bounds.top = bounds.bottom - minimalHeight;
1400            } else {
1401                // Either top bounds match, or neither match, or the previous bounds were
1402                // fullscreen and we default to keeping top.
1403                bounds.bottom = bounds.top + minimalHeight;
1404            }
1405        }
1406    }
1407
1408    /**
1409     * Update task's override configuration based on the bounds.
1410     * @param bounds The bounds of the task.
1411     * @return Update configuration or null if there is no change.
1412     */
1413    Configuration updateOverrideConfiguration(Rect bounds) {
1414        return updateOverrideConfiguration(bounds, null /* insetBounds */);
1415    }
1416
1417    /**
1418     * Update task's override configuration based on the bounds.
1419     * @param bounds The bounds of the task.
1420     * @param insetBounds The bounds used to calculate the system insets, which is used here to
1421     *                    subtract the navigation bar/status bar size from the screen size reported
1422     *                    to the application. See {@link IActivityManager#resizeDockedStack}.
1423     * @return Update configuration or null if there is no change.
1424     */
1425    Configuration updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) {
1426        if (Objects.equals(mBounds, bounds)) {
1427            return null;
1428        }
1429        final Configuration oldConfig = mOverrideConfig;
1430        final boolean oldFullscreen = mFullscreen;
1431
1432        mFullscreen = bounds == null;
1433        if (mFullscreen) {
1434            if (mBounds != null && StackId.persistTaskBounds(stack.mStackId)) {
1435                mLastNonFullscreenBounds = mBounds;
1436            }
1437            mBounds = null;
1438            mOverrideConfig = Configuration.EMPTY;
1439        } else {
1440            mTmpRect.set(bounds);
1441            adjustForMinimalTaskDimensions(mTmpRect);
1442            if (mBounds == null) {
1443                mBounds = new Rect(mTmpRect);
1444            } else {
1445                mBounds.set(mTmpRect);
1446            }
1447            if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {
1448                mLastNonFullscreenBounds = mBounds;
1449            }
1450            mOverrideConfig = calculateOverrideConfig(mTmpRect, insetBounds,
1451                    mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom);
1452        }
1453
1454        if (mFullscreen != oldFullscreen) {
1455            mService.mStackSupervisor.scheduleReportMultiWindowModeChanged(this);
1456        }
1457
1458        return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
1459    }
1460
1461    private void subtractNonDecorInsets(Rect inOutBounds, Rect inInsetBounds,
1462                                        boolean overrideWidth, boolean overrideHeight) {
1463        mTmpRect2.set(inInsetBounds);
1464        mService.mWindowManager.subtractNonDecorInsets(mTmpRect2);
1465        int leftInset = mTmpRect2.left - inInsetBounds.left;
1466        int topInset = mTmpRect2.top - inInsetBounds.top;
1467        int rightInset = overrideWidth ? 0 : inInsetBounds.right - mTmpRect2.right;
1468        int bottomInset = overrideHeight ? 0 : inInsetBounds.bottom - mTmpRect2.bottom;
1469        inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
1470    }
1471
1472    private void subtractStableInsets(Rect inOutBounds, Rect inInsetBounds,
1473                                      boolean overrideWidth, boolean overrideHeight) {
1474        mTmpRect2.set(inInsetBounds);
1475        mService.mWindowManager.subtractStableInsets(mTmpRect2);
1476        int leftInset = mTmpRect2.left - inInsetBounds.left;
1477        int topInset = mTmpRect2.top - inInsetBounds.top;
1478        int rightInset = overrideWidth ? 0 : inInsetBounds.right - mTmpRect2.right;
1479        int bottomInset = overrideHeight ? 0 : inInsetBounds.bottom - mTmpRect2.bottom;
1480        inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
1481    }
1482
1483    private Configuration calculateOverrideConfig(Rect bounds, Rect insetBounds,
1484                                                  boolean overrideWidth, boolean overrideHeight) {
1485        mTmpNonDecorBounds.set(bounds);
1486        mTmpStableBounds.set(bounds);
1487        subtractNonDecorInsets(
1488                mTmpNonDecorBounds, insetBounds != null ? insetBounds : bounds,
1489                overrideWidth, overrideHeight);
1490        subtractStableInsets(
1491                mTmpStableBounds, insetBounds != null ? insetBounds : bounds,
1492                overrideWidth, overrideHeight);
1493
1494        // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen area,
1495        // i.e. the screen area without the system bars.
1496        final Configuration serviceConfig = mService.mConfiguration;
1497        final Configuration config = new Configuration(Configuration.EMPTY);
1498        // TODO(multidisplay): Update Dp to that of display stack is on.
1499        final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
1500        config.screenWidthDp =
1501                Math.min((int)(mTmpStableBounds.width() / density), serviceConfig.screenWidthDp);
1502        config.screenHeightDp =
1503                Math.min((int)(mTmpStableBounds.height() / density), serviceConfig.screenHeightDp);
1504
1505        // TODO: Orientation?
1506        config.orientation = (config.screenWidthDp <= config.screenHeightDp)
1507                ? Configuration.ORIENTATION_PORTRAIT
1508                : Configuration.ORIENTATION_LANDSCAPE;
1509
1510        // For calculating screen layout and smallest screen width, we need to use the non-decor
1511        // inset screen area for the calculation for compatibility reasons, i.e. screen area without
1512        // system bars that could never go away in Honeycomb.
1513        final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density);
1514        final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density);
1515        final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
1516        final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
1517        config.smallestScreenWidthDp = Math.min(compatScreenHeightDp, compatScreenWidthDp);
1518        config.screenLayout = Configuration.reduceScreenLayout(sl, longSize,
1519                config.smallestScreenWidthDp);
1520        return config;
1521    }
1522
1523    /**
1524     * Using the existing configuration {@param config}, creates a new task override config such
1525     * that all the fields that are usually set in an override config are set to the ones in
1526     * {@param config}.
1527     */
1528    Configuration extractOverrideConfig(Configuration config) {
1529        final Configuration extracted = new Configuration(Configuration.EMPTY);
1530        extracted.screenWidthDp = config.screenWidthDp;
1531        extracted.screenHeightDp = config.screenHeightDp;
1532        extracted.smallestScreenWidthDp = config.smallestScreenWidthDp;
1533        extracted.orientation = config.orientation;
1534        extracted.screenLayout = config.screenLayout;
1535        return extracted;
1536    }
1537
1538    Rect updateOverrideConfigurationFromLaunchBounds() {
1539        final Rect bounds = validateBounds(getLaunchBounds());
1540        updateOverrideConfiguration(bounds);
1541        if (bounds != null) {
1542            bounds.set(mBounds);
1543        }
1544        return bounds;
1545    }
1546
1547    static Rect validateBounds(Rect bounds) {
1548        if (bounds != null && bounds.isEmpty()) {
1549            Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable());
1550            return null;
1551        }
1552        return bounds;
1553    }
1554
1555    /** Updates the task's bounds and override configuration to match what is expected for the
1556     * input stack. */
1557    void updateOverrideConfigurationForStack(ActivityStack inStack) {
1558        if (stack != null && stack == inStack) {
1559            return;
1560        }
1561
1562        if (inStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
1563            if (!isResizeable()) {
1564                throw new IllegalArgumentException("Can not position non-resizeable task="
1565                        + this + " in stack=" + inStack);
1566            }
1567            if (mBounds != null) {
1568                return;
1569            }
1570            if (mLastNonFullscreenBounds != null) {
1571                updateOverrideConfiguration(mLastNonFullscreenBounds);
1572            } else {
1573                inStack.layoutTaskInStack(this, null);
1574            }
1575        } else {
1576            updateOverrideConfiguration(inStack.mBounds);
1577        }
1578    }
1579
1580    /**
1581     * Returns the correct stack to use based on task type and currently set bounds,
1582     * regardless of the focused stack and current stack association of the task.
1583     * The task will be moved (and stack focus changed) later if necessary.
1584     */
1585    int getLaunchStackId() {
1586        if (!isApplicationTask()) {
1587            return HOME_STACK_ID;
1588        }
1589        if (mBounds != null) {
1590            return FREEFORM_WORKSPACE_STACK_ID;
1591        }
1592        return FULLSCREEN_WORKSPACE_STACK_ID;
1593    }
1594
1595    /** Returns the bounds that should be used to launch this task. */
1596    Rect getLaunchBounds() {
1597        // If we're over lockscreen, forget about stack bounds and use fullscreen.
1598        if (mService.mLockScreenShown == LOCK_SCREEN_SHOWN) {
1599            return null;
1600        }
1601
1602        if (stack == null) {
1603            return null;
1604        }
1605
1606        final int stackId = stack.mStackId;
1607        if (stackId == HOME_STACK_ID
1608                || stackId == FULLSCREEN_WORKSPACE_STACK_ID
1609                || (stackId == DOCKED_STACK_ID && !isResizeable())) {
1610            return isResizeable() ? stack.mBounds : null;
1611        } else if (!StackId.persistTaskBounds(stackId)) {
1612            return stack.mBounds;
1613        }
1614        return mLastNonFullscreenBounds;
1615    }
1616
1617    boolean canMatchRootAffinity() {
1618        // We don't allow root affinity matching on the pinned stack as no other task should
1619        // be launching in it based on affinity.
1620        return rootAffinity != null && (stack == null || stack.mStackId != PINNED_STACK_ID);
1621    }
1622
1623    void dump(PrintWriter pw, String prefix) {
1624        pw.print(prefix); pw.print("userId="); pw.print(userId);
1625                pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
1626                pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
1627                pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
1628                pw.print(" mCallingPackage="); pw.println(mCallingPackage);
1629        if (affinity != null || rootAffinity != null) {
1630            pw.print(prefix); pw.print("affinity="); pw.print(affinity);
1631            if (affinity == null || !affinity.equals(rootAffinity)) {
1632                pw.print(" root="); pw.println(rootAffinity);
1633            } else {
1634                pw.println();
1635            }
1636        }
1637        if (voiceSession != null || voiceInteractor != null) {
1638            pw.print(prefix); pw.print("VOICE: session=0x");
1639            pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
1640            pw.print(" interactor=0x");
1641            pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
1642        }
1643        if (intent != null) {
1644            StringBuilder sb = new StringBuilder(128);
1645            sb.append(prefix); sb.append("intent={");
1646            intent.toShortString(sb, false, true, false, true);
1647            sb.append('}');
1648            pw.println(sb.toString());
1649        }
1650        if (affinityIntent != null) {
1651            StringBuilder sb = new StringBuilder(128);
1652            sb.append(prefix); sb.append("affinityIntent={");
1653            affinityIntent.toShortString(sb, false, true, false, true);
1654            sb.append('}');
1655            pw.println(sb.toString());
1656        }
1657        if (origActivity != null) {
1658            pw.print(prefix); pw.print("origActivity=");
1659            pw.println(origActivity.flattenToShortString());
1660        }
1661        if (realActivity != null) {
1662            pw.print(prefix); pw.print("realActivity=");
1663            pw.println(realActivity.flattenToShortString());
1664        }
1665        if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0
1666                || numFullscreen != 0) {
1667            pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
1668                    pw.print(" isPersistable="); pw.print(isPersistable);
1669                    pw.print(" numFullscreen="); pw.print(numFullscreen);
1670                    pw.print(" taskType="); pw.print(taskType);
1671                    pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
1672        }
1673        if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
1674                || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
1675            pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
1676                    pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
1677                    pw.print(" mReuseTask="); pw.print(mReuseTask);
1678                    pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
1679        }
1680        if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID
1681                || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
1682                || mNextAffiliate != null) {
1683            pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
1684                    pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
1685                    pw.print(" (");
1686                    if (mPrevAffiliate == null) {
1687                        pw.print("null");
1688                    } else {
1689                        pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
1690                    }
1691                    pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
1692                    pw.print(" (");
1693                    if (mNextAffiliate == null) {
1694                        pw.print("null");
1695                    } else {
1696                        pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
1697                    }
1698                    pw.println(")");
1699        }
1700        pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
1701        if (!askedCompatMode || !inRecents || !isAvailable) {
1702            pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
1703                    pw.print(" inRecents="); pw.print(inRecents);
1704                    pw.print(" isAvailable="); pw.println(isAvailable);
1705        }
1706        pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail);
1707                pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile);
1708        if (lastDescription != null) {
1709            pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
1710        }
1711        if (stack != null) {
1712            pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId);
1713        }
1714        pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
1715                pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
1716                pw.print(" isResizeable=" + isResizeable());
1717                pw.print(" firstActiveTime=" + lastActiveTime);
1718                pw.print(" lastActiveTime=" + lastActiveTime);
1719                pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
1720    }
1721
1722    @Override
1723    public String toString() {
1724        StringBuilder sb = new StringBuilder(128);
1725        if (stringName != null) {
1726            sb.append(stringName);
1727            sb.append(" U=");
1728            sb.append(userId);
1729            sb.append(" StackId=");
1730            sb.append(stack != null ? stack.mStackId : INVALID_STACK_ID);
1731            sb.append(" sz=");
1732            sb.append(mActivities.size());
1733            sb.append('}');
1734            return sb.toString();
1735        }
1736        sb.append("TaskRecord{");
1737        sb.append(Integer.toHexString(System.identityHashCode(this)));
1738        sb.append(" #");
1739        sb.append(taskId);
1740        if (affinity != null) {
1741            sb.append(" A=");
1742            sb.append(affinity);
1743        } else if (intent != null) {
1744            sb.append(" I=");
1745            sb.append(intent.getComponent().flattenToShortString());
1746        } else if (affinityIntent != null) {
1747            sb.append(" aI=");
1748            sb.append(affinityIntent.getComponent().flattenToShortString());
1749        } else {
1750            sb.append(" ??");
1751        }
1752        stringName = sb.toString();
1753        return toString();
1754    }
1755}
1756