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