[go: nahoru, domu]

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