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