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