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