OSDN Git Service

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