blob: 3b16b59a554017d278bbb8714273436f8cdda625 [file] [log] [blame]
Craig Mautnerb1fd65c02013-02-05 13:34:57 -08001/*
Louis Changcdec0802019-11-11 11:45:07 +08002 * Copyright (C) 2006 The Android Open Source Project
Craig Mautnerb1fd65c02013-02-05 13:34:57 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
Wale Ogunwale2322bed2019-10-10 17:24:19 +020019import static android.app.ActivityTaskManager.INVALID_STACK_ID;
Louis Changcdec0802019-11-11 11:45:07 +080020import static android.app.ActivityTaskManager.INVALID_TASK_ID;
21import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
22import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
Wale Ogunwale65ebd952018-04-25 15:41:44 -070023import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
Louis Changcdec0802019-11-11 11:45:07 +080024import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
25import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
26import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
27import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
28import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
29import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
30import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
31import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
32import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
33import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
34import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
35import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
36import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
37import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
38import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
39import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
40import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
41import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
skuhne@google.com322347b2016-12-02 12:54:03 -080042import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
Jason Monkba53d8a2017-04-06 18:28:19 +000043import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020044import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
Louis Changcdec0802019-11-11 11:45:07 +080045import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
46import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
47import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
48import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
Bryce Lee61fbcbc2017-03-10 14:14:03 -080049import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
Wale Ogunwale68278562017-09-23 17:13:55 -070050import static android.content.res.Configuration.EMPTY;
Louis Changcdec0802019-11-11 11:45:07 +080051import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
52import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
53import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
54import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
55import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
56import static android.view.Display.DEFAULT_DISPLAY;
Evan Rosky9020c072018-12-06 14:11:12 -080057import static android.view.SurfaceControl.METADATA_TASK_ID;
chaviw8c9d1f52018-07-25 14:56:07 -070058
Wale Ogunwale2322bed2019-10-10 17:24:19 +020059import static com.android.server.EventLogTags.WM_TASK_CREATED;
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -080060import static com.android.server.EventLogTags.WM_TASK_REMOVED;
Louis Changcdec0802019-11-11 11:45:07 +080061import static com.android.server.am.TaskRecordProto.ACTIVITIES;
62import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
Louis Changcdec0802019-11-11 11:45:07 +080063import static com.android.server.am.TaskRecordProto.FULLSCREEN;
Louis Changcdec0802019-11-11 11:45:07 +080064import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
65import static com.android.server.am.TaskRecordProto.MIN_HEIGHT;
66import static com.android.server.am.TaskRecordProto.MIN_WIDTH;
67import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
68import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
69import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
70import static com.android.server.am.TaskRecordProto.STACK_ID;
71import static com.android.server.am.TaskRecordProto.TASK;
72import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
73import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
74import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
75import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
76import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
77import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
78import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
79import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
80import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
81import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
82import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
83import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
84import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
85import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
86import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
Yunfan Chen0e7aff92018-12-05 16:35:32 -080087import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
Louis Changcdec0802019-11-11 11:45:07 +080088import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070089import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS;
Evan Roskyed6767f2018-10-26 17:21:06 -070090import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070091import static com.android.server.wm.TaskProto.FILLS_PARENT;
Louis Chang7501e332018-08-20 13:08:39 +080092import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
93import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070094import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
lumark9bca6b42019-10-17 18:35:22 +080095import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
96import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
chaviw8c9d1f52018-07-25 14:56:07 -070097import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
chaviw8c9d1f52018-07-25 14:56:07 -070098import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Wale Ogunwale99db1862015-10-23 20:08:22 -070099
Louis Changcdec0802019-11-11 11:45:07 +0800100import static java.lang.Integer.MAX_VALUE;
101
102import android.annotation.IntDef;
103import android.annotation.NonNull;
104import android.annotation.Nullable;
105import android.app.Activity;
Yunfan Chen0e7aff92018-12-05 16:35:32 -0800106import android.app.ActivityManager;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100107import android.app.ActivityManager.TaskDescription;
Louis Changcdec0802019-11-11 11:45:07 +0800108import android.app.ActivityManager.TaskSnapshot;
109import android.app.ActivityOptions;
110import android.app.ActivityTaskManager;
111import android.app.AppGlobals;
112import android.app.TaskInfo;
113import android.app.WindowConfiguration;
114import android.content.ComponentName;
115import android.content.Intent;
Wale Ogunwaleb1faf602016-01-27 09:12:31 -0800116import android.content.pm.ActivityInfo;
Louis Changcdec0802019-11-11 11:45:07 +0800117import android.content.pm.ApplicationInfo;
118import android.content.pm.IPackageManager;
119import android.content.pm.PackageManager;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700120import android.content.res.Configuration;
121import android.graphics.Rect;
Louis Changcdec0802019-11-11 11:45:07 +0800122import android.os.Debug;
Garfield Tan90b04282018-12-11 14:04:42 -0800123import android.os.IBinder;
Louis Changcdec0802019-11-11 11:45:07 +0800124import android.os.RemoteException;
125import android.os.SystemClock;
126import android.os.Trace;
127import android.os.UserHandle;
128import android.provider.Settings;
129import android.service.voice.IVoiceInteractionSession;
130import android.util.DisplayMetrics;
Craig Mautner2c2549c2013-11-12 08:31:15 -0800131import android.util.EventLog;
Craig Mautner42bf39e2014-02-21 16:46:22 -0800132import android.util.Slog;
Steven Timotiusaf03df62017-07-18 16:56:43 -0700133import android.util.proto.ProtoOutputStream;
Garfield Tandec96db2018-10-30 11:28:49 -0700134import android.view.Display;
Louis Changcdec0802019-11-11 11:45:07 +0800135import android.view.DisplayInfo;
lumark19a5d2e2019-10-11 16:19:30 +0800136import android.view.RemoteAnimationTarget;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700137import android.view.Surface;
Winson Chungd41f71d2018-03-16 15:26:07 -0700138import android.view.SurfaceControl;
chaviw8c9d1f52018-07-25 14:56:07 -0700139
Wale Ogunwalec5cc3012017-01-13 13:26:16 -0800140import com.android.internal.annotations.VisibleForTesting;
Louis Changcdec0802019-11-11 11:45:07 +0800141import com.android.internal.app.IVoiceInteractor;
lumarkbc0032a2019-11-01 21:38:13 +0800142import com.android.internal.util.ToBooleanFunction;
Louis Changcdec0802019-11-11 11:45:07 +0800143import com.android.internal.util.XmlUtils;
144import com.android.server.protolog.common.ProtoLog;
145import com.android.server.wm.ActivityStack.ActivityState;
Craig Mautner2c2549c2013-11-12 08:31:15 -0800146
Louis Changcdec0802019-11-11 11:45:07 +0800147import org.xmlpull.v1.XmlPullParser;
148import org.xmlpull.v1.XmlPullParserException;
149import org.xmlpull.v1.XmlSerializer;
150
151import java.io.IOException;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700152import java.io.PrintWriter;
Louis Changcdec0802019-11-11 11:45:07 +0800153import java.lang.annotation.Retention;
154import java.lang.annotation.RetentionPolicy;
155import java.util.ArrayList;
156import java.util.Objects;
Jorim Jaggi51304d72017-05-17 17:25:32 +0200157import java.util.function.Consumer;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700158
Louis Changcdec0802019-11-11 11:45:07 +0800159class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener {
160 private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM;
161 private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
162 private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
163 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
164 private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
165
166 private static final String ATTR_TASKID = "task_id";
167 private static final String TAG_INTENT = "intent";
168 private static final String TAG_AFFINITYINTENT = "affinity_intent";
169 private static final String ATTR_REALACTIVITY = "real_activity";
170 private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
171 private static final String ATTR_ORIGACTIVITY = "orig_activity";
172 private static final String TAG_ACTIVITY = "activity";
173 private static final String ATTR_AFFINITY = "affinity";
174 private static final String ATTR_ROOT_AFFINITY = "root_affinity";
175 private static final String ATTR_ROOTHASRESET = "root_has_reset";
176 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
177 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
178 private static final String ATTR_USERID = "user_id";
179 private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
180 private static final String ATTR_EFFECTIVE_UID = "effective_uid";
181 @Deprecated
182 private static final String ATTR_TASKTYPE = "task_type";
183 private static final String ATTR_LASTDESCRIPTION = "last_description";
184 private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
185 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
186 private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
187 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
188 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
189 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
190 private static final String ATTR_CALLING_UID = "calling_uid";
191 private static final String ATTR_CALLING_PACKAGE = "calling_package";
192 private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
193 private static final String ATTR_RESIZE_MODE = "resize_mode";
194 private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
195 private static final String ATTR_MIN_WIDTH = "min_width";
196 private static final String ATTR_MIN_HEIGHT = "min_height";
197 private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
198
199 // Current version of the task record we persist. Used to check if we need to run any upgrade
200 // code.
201 private static final int PERSIST_TASK_VERSION = 1;
202
203 private static final int INVALID_MIN_SIZE = -1;
204
205 /**
206 * The modes to control how the stack is moved to the front when calling {@link Task#reparent}.
207 */
208 @Retention(RetentionPolicy.SOURCE)
209 @IntDef({
210 REPARENT_MOVE_STACK_TO_FRONT,
211 REPARENT_KEEP_STACK_AT_FRONT,
212 REPARENT_LEAVE_STACK_IN_PLACE
213 })
214 @interface ReparentMoveStackMode {}
215 // Moves the stack to the front if it was not at the front
216 static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
217 // Only moves the stack to the front if it was focused or front most already
218 static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
219 // Do not move the stack as a part of reparenting
220 static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
221
222 /**
223 * The factory used to create {@link Task}. This allows OEM subclass {@link Task}.
224 */
225 private static TaskFactory sTaskFactory;
226
227 String affinity; // The affinity name for this task, or null; may change identity.
228 String rootAffinity; // Initial base affinity, or null; does not change from initial root.
229 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
230 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
231 Intent intent; // The original intent that started the task. Note that this value can
232 // be null.
233 Intent affinityIntent; // Intent of affinity-moved activity that started this task.
234 int effectiveUid; // The current effective uid of the identity of this task.
235 ComponentName origActivity; // The non-alias activity component of the intent.
236 ComponentName realActivity; // The actual activity component that started the task.
237 boolean realActivitySuspended; // True if the actual activity component that started the
238 // task is suspended.
239 boolean inRecents; // Actually in the recents list?
240 long lastActiveTime; // Last time this task was active in the current device session,
241 // including sleep. This time is initialized to the elapsed time when
242 // restored from disk.
243 boolean isAvailable; // Is the activity available to be launched?
244 boolean rootWasReset; // True if the intent at the root of the task had
245 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
246 boolean autoRemoveRecents; // If true, we should automatically remove the task from
247 // recents when activity finishes
248 boolean askedCompatMode;// Have asked the user about compat mode for this task.
249 boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
250
251 String stringName; // caching of toString() result.
252 boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
253 // was changed.
254
Louis Changcdec0802019-11-11 11:45:07 +0800255 /** Can't be put in lockTask mode. */
256 final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
257 /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
258 final static int LOCK_TASK_AUTH_PINNABLE = 1;
259 /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
260 final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
261 /** Can enter lockTask without user approval. Can start over existing lockTask task. */
262 final static int LOCK_TASK_AUTH_WHITELISTED = 3;
263 /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
264 * lockTask task. */
265 final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
266 int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
267
268 int mLockTaskUid = -1; // The uid of the application that called startLockTask().
269
270 /** Current stack. Setter must always be used to update the value. */
271 private ActivityStack mStack;
272
273 /** The process that had previously hosted the root activity of this task.
274 * Used to know that we should try harder to keep this process around, in case the
275 * user wants to return to it. */
276 private WindowProcessController mRootProcess;
277
278 /** Takes on same value as first root activity */
279 boolean isPersistable = false;
280 int maxRecents;
281
282 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
283 * determining the order when restoring. Sign indicates whether last task movement was to front
284 * (positive) or back (negative). Absolute value indicates time. */
285 long mLastTimeMoved;
286
287 /** If original intent did not allow relinquishing task identity, save that information */
288 private boolean mNeverRelinquishIdentity = true;
289
290 // Used in the unique case where we are clearing the task in order to reuse it. In that case we
291 // do not want to delete the stack when the task goes empty.
292 private boolean mReuseTask = false;
293
294 CharSequence lastDescription; // Last description captured for this item.
295
296 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
297 int mAffiliatedTaskColor; // color of the parent task affiliation.
298 Task mPrevAffiliate; // previous task in affiliated chain.
299 int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
300 Task mNextAffiliate; // next task in affiliated chain.
301 int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
302
303 // For relaunching the task from recents as though it was launched by the original launcher.
304 int mCallingUid;
305 String mCallingPackage;
306
307 private final Rect mTmpStableBounds = new Rect();
308 private final Rect mTmpNonDecorBounds = new Rect();
309 private final Rect mTmpBounds = new Rect();
310 private final Rect mTmpInsets = new Rect();
Evan Rosky70213702019-11-05 10:26:24 -0800311 private final Rect mTmpFullBounds = new Rect();
Louis Changcdec0802019-11-11 11:45:07 +0800312
313 // Last non-fullscreen bounds the task was launched in or resized to.
314 // The information is persisted and used to determine the appropriate stack to launch the
315 // task into on restore.
316 Rect mLastNonFullscreenBounds = null;
317 // Minimal width and height of this task when it's resizeable. -1 means it should use the
318 // default minimal width/height.
319 int mMinWidth;
320 int mMinHeight;
321
322 // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
323 // This number will be assigned when we evaluate OOM scores for all visible tasks.
324 int mLayerRank = -1;
325
326 /** Helper object used for updating override configuration. */
327 private Configuration mTmpConfig = new Configuration();
328
329 /** Used by fillTaskInfo */
330 final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
Wale Ogunwale2cc92f52015-09-09 13:12:10 -0700331
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200332 final ActivityTaskManagerService mAtmService;
333
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700334 /* Unique identifier for this task. */
Craig Mautner83162a92015-01-26 14:43:30 -0800335 final int mTaskId;
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700336 /* User for which this task was created. */
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200337 // TODO: Make final
338 int mUserId;
Craig Mautnerb1fd65c02013-02-05 13:34:57 -0800339
Jorim Jaggi0429f352015-12-22 16:29:16 +0100340 final Rect mPreparedFrozenBounds = new Rect();
Jorim Jaggi26c8c422016-05-09 19:57:25 -0700341 final Configuration mPreparedFrozenMergedConfig = new Configuration();
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700342
Evan Roskyed6767f2018-10-26 17:21:06 -0700343 // If non-empty, bounds used to display the task during animations/interactions.
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200344 // TODO(b/119687367): This member is temporary.
Evan Roskyed6767f2018-10-26 17:21:06 -0700345 private final Rect mOverrideDisplayedBounds = new Rect();
Jorim Jaggidc249c42015-12-15 14:57:31 -0800346
Garfield Tandec96db2018-10-30 11:28:49 -0700347 /** ID of the display which rotation {@link #mRotation} has. */
348 private int mLastRotationDisplayId = Display.INVALID_DISPLAY;
349 /**
350 * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was
351 * moved to a new display.
352 */
Wale Ogunwale3eadad72016-10-13 09:16:59 -0700353 private int mRotation;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700354
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700355 // For comparison with DisplayContent bounds.
356 private Rect mTmpRect = new Rect();
357 // For handling display rotations.
358 private Rect mTmpRect2 = new Rect();
359
Wale Ogunwaleb1faf602016-01-27 09:12:31 -0800360 // Resize mode of the task. See {@link ActivityInfo#resizeMode}
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200361 // Based on the {@link ActivityInfo#resizeMode} of the root activity.
362 int mResizeMode;
Chong Zhangb15758a2015-11-17 12:12:03 -0800363
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200364 // Whether or not this task and its activities support PiP. Based on the
365 // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity.
366 boolean mSupportsPictureInPicture;
Winson Chungd3395382016-12-13 11:49:09 -0800367
Chong Zhang3005e752015-09-18 18:46:28 -0700368 // Whether the task is currently being drag-resized
369 private boolean mDragResizing;
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +0100370 private int mDragResizeMode;
Chong Zhang3005e752015-09-18 18:46:28 -0700371
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700372 // This represents the last resolved activity values for this task
373 // NOTE: This value needs to be persisted with each task
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100374 private TaskDescription mTaskDescription;
375
Robert Carr18f622f2017-05-08 11:20:43 -0700376 // If set to true, the task will report that it is not in the floating
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700377 // state regardless of it's stack affiliation. As the floating state drives
Robert Carr18f622f2017-05-08 11:20:43 -0700378 // production of content insets this can be used to preserve them across
379 // stack moves and we in fact do so when moving from full screen to pinned.
380 private boolean mPreserveNonFloatingState = false;
381
Robert Carrf59b8dd2017-10-02 18:58:36 -0700382 private Dimmer mDimmer = new Dimmer(this);
383 private final Rect mTmpDimBoundsRect = new Rect();
384
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100385 /** @see #setCanAffectSystemUiFlags */
386 private boolean mCanAffectSystemUiFlags = true;
387
Louis Changcdec0802019-11-11 11:45:07 +0800388 /**
389 * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
390 * ActivityInfo, Intent, TaskDescription)} instead.
391 */
392 Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
393 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
394 TaskDescription _taskDescription, ActivityStack stack) {
395 this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/,
396 null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
397 false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
398 UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
399 null /*_lastDescription*/, System.currentTimeMillis(),
400 true /*neverRelinquishIdentity*/,
401 _taskDescription != null ? _taskDescription : new TaskDescription(),
402 _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
403 info.applicationInfo.uid, info.packageName, info.resizeMode,
404 info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
405 false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
406 _voiceSession, _voiceInteractor, stack);
407 }
408
409 /** Don't use constructor directly. This is only used by XML parser. */
410 Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
411 Intent _affinityIntent, String _affinity, String _rootAffinity,
412 ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
413 boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
414 int _effectiveUid, String _lastDescription,
415 long lastTimeMoved, boolean neverRelinquishIdentity,
416 TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
417 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
418 int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
419 boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
420 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
421 ActivityStack stack) {
422 super(atmService.mWindowManager);
423
424 EventLog.writeEvent(WM_TASK_CREATED, _taskId,
425 stack != null ? stack.mStackId : INVALID_STACK_ID);
426 mAtmService = atmService;
427 mTaskId = _taskId;
428 mUserId = _userId;
Wale Ogunwale72919d22016-12-08 18:58:50 -0800429 mResizeMode = resizeMode;
Winson Chungd3395382016-12-13 11:49:09 -0800430 mSupportsPictureInPicture = supportsPictureInPicture;
Louis Changcdec0802019-11-11 11:45:07 +0800431 mTaskDescription = _lastTaskDescription;
Riddle Hsu6b76cd32019-10-08 00:37:19 +0800432 // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
433 setOrientation(SCREEN_ORIENTATION_UNSET);
Louis Changcdec0802019-11-11 11:45:07 +0800434 mRemoteToken = new RemoteToken(this);
435 affinityIntent = _affinityIntent;
436 affinity = _affinity;
437 rootAffinity = _rootAffinity;
438 voiceSession = _voiceSession;
439 voiceInteractor = _voiceInteractor;
440 realActivity = _realActivity;
441 realActivitySuspended = _realActivitySuspended;
442 origActivity = _origActivity;
443 rootWasReset = _rootWasReset;
444 isAvailable = true;
445 autoRemoveRecents = _autoRemoveRecents;
446 askedCompatMode = _askedCompatMode;
447 mUserSetupComplete = userSetupComplete;
448 effectiveUid = _effectiveUid;
449 touchActiveTime();
450 lastDescription = _lastDescription;
451 mLastTimeMoved = lastTimeMoved;
452 mNeverRelinquishIdentity = neverRelinquishIdentity;
453 mAffiliatedTaskId = taskAffiliation;
454 mAffiliatedTaskColor = taskAffiliationColor;
455 mPrevAffiliateTaskId = prevTaskId;
456 mNextAffiliateTaskId = nextTaskId;
457 mCallingUid = callingUid;
458 mCallingPackage = callingPackage;
459 mResizeMode = resizeMode;
460 if (info != null) {
461 setIntent(_intent, info);
462 setMinDimensions(info);
463 } else {
464 intent = _intent;
465 mMinWidth = minWidth;
466 mMinHeight = minHeight;
467 }
468 mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
469 }
470
471 void cleanUpResourcesForDestroy() {
472 if (hasChild()) {
473 return;
474 }
475
476 // This task is going away, so save the last state if necessary.
477 saveLaunchingStateIfNeeded();
478
479 // TODO: VI what about activity?
480 final boolean isVoiceSession = voiceSession != null;
481 if (isVoiceSession) {
482 try {
483 voiceSession.taskFinished(intent, mTaskId);
484 } catch (RemoteException e) {
485 }
486 }
487 if (autoRemoveFromRecents() || isVoiceSession) {
488 // Task creator asked to remove this when done, or this task was a voice
489 // interaction, so it should not remain on the recent tasks list.
490 mAtmService.mStackSupervisor.mRecentTasks.remove(this);
491 }
492
493 removeIfPossible();
494 }
495
496 @VisibleForTesting
497 @Override
498 void removeIfPossible() {
499 mAtmService.getLockTaskController().clearLockedTask(this);
500 if (shouldDeferRemoval()) {
501 if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
502 return;
503 }
504 removeImmediately();
505 mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
506 }
507
508 void setResizeMode(int resizeMode) {
509 if (mResizeMode == resizeMode) {
510 return;
511 }
512 mResizeMode = resizeMode;
513 mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
514 mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
515 updateTaskDescription();
516 }
517
518 boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
519 mAtmService.deferWindowLayout();
520
521 try {
522 final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
523
524 if (getParent() == null) {
525 // Task doesn't exist in window manager yet (e.g. was restored from recents).
526 // All we can do for now is update the bounds so it can be used when the task is
527 // added to window manager.
528 setBounds(bounds);
529 if (!inFreeformWindowingMode()) {
530 // re-restore the task so it can have the proper stack association.
531 mAtmService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
532 }
533 return true;
534 }
535
536 if (!canResizeToBounds(bounds)) {
537 throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
538 + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
539 }
540
541 // Do not move the task to another stack here.
542 // This method assumes that the task is already placed in the right stack.
543 // we do not mess with that decision and we only do the resize!
544
545 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId);
546
547 boolean updatedConfig = false;
548 mTmpConfig.setTo(getResolvedOverrideConfiguration());
549 if (setBounds(bounds) != BOUNDS_CHANGE_NONE) {
550 updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration());
551 }
552 // This variable holds information whether the configuration didn't change in a
553 // significant way and the activity was kept the way it was. If it's false, it means
554 // the activity had to be relaunched due to configuration change.
555 boolean kept = true;
556 if (updatedConfig) {
557 final ActivityRecord r = topRunningActivityLocked();
558 if (r != null && !deferResume) {
559 kept = r.ensureActivityConfiguration(0 /* globalChanges */,
560 preserveWindow);
561 // Preserve other windows for resizing because if resizing happens when there
562 // is a dialog activity in the front, the activity that still shows some
563 // content to the user will become black and cause flickers. Note in most cases
564 // this won't cause tons of irrelevant windows being preserved because only
565 // activities in this task may experience a bounds change. Configs for other
566 // activities stay the same.
567 mAtmService.mRootActivityContainer.ensureActivitiesVisible(r, 0,
568 preserveWindow);
569 if (!kept) {
570 mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
571 }
572 }
573 }
574 resize(kept, forced);
575
576 saveLaunchingStateIfNeeded();
577
578 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
579 return kept;
580 } finally {
581 mAtmService.continueWindowLayout();
582 }
583 }
584
585 /** Convenience method to reparent a task to the top or bottom position of the stack. */
586 boolean reparent(ActivityStack preferredStack, boolean toTop,
587 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
588 String reason) {
589 return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
590 true /* schedulePictureInPictureModeChange */, reason);
591 }
592
593 /**
594 * Convenience method to reparent a task to the top or bottom position of the stack, with
595 * an option to skip scheduling the picture-in-picture mode change.
596 */
597 boolean reparent(ActivityStack preferredStack, boolean toTop,
598 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
599 boolean schedulePictureInPictureModeChange, String reason) {
600 return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
601 deferResume, schedulePictureInPictureModeChange, reason);
602 }
603
604 /** Convenience method to reparent a task to a specific position of the stack. */
605 boolean reparent(ActivityStack preferredStack, int position,
606 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
607 String reason) {
608 return reparent(preferredStack, position, moveStackMode, animate, deferResume,
609 true /* schedulePictureInPictureModeChange */, reason);
610 }
611
612 /**
613 * Reparents the task into a preferred stack, creating it if necessary.
614 *
615 * @param preferredStack the target stack to move this task
616 * @param position the position to place this task in the new stack
617 * @param animate whether or not we should wait for the new window created as a part of the
618 * reparenting to be drawn and animated in
619 * @param moveStackMode whether or not to move the stack to the front always, only if it was
620 * previously focused & in front, or never
621 * @param deferResume whether or not to update the visibility of other tasks and stacks that may
622 * have changed as a result of this reparenting
623 * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
624 * change. Callers may set this to false if they are explicitly scheduling PiP mode
625 * changes themselves, like during the PiP animation
626 * @param reason the caller of this reparenting
627 * @return whether the task was reparented
628 */
629 // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
630 // re-parenting the task. Can only be done when we are no longer using static stack Ids.
631 boolean reparent(ActivityStack preferredStack, int position,
632 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
633 boolean schedulePictureInPictureModeChange, String reason) {
634 final ActivityStackSupervisor supervisor = mAtmService.mStackSupervisor;
635 final RootActivityContainer root = mAtmService.mRootActivityContainer;
636 final WindowManagerService windowManager = mAtmService.mWindowManager;
637 final ActivityStack sourceStack = getStack();
638 final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
639 position == MAX_VALUE);
640 if (toStack == sourceStack) {
641 return false;
642 }
643 if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
644 return false;
645 }
646
647 final boolean toTopOfStack = position == MAX_VALUE;
648 if (toTopOfStack && toStack.getResumedActivity() != null
649 && toStack.topRunningActivityLocked() != null) {
650 // Pause the resumed activity on the target stack while re-parenting task on top of it.
651 toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
652 null /* resuming */);
653 }
654
655 final int toStackWindowingMode = toStack.getWindowingMode();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800656 final ActivityRecord topActivity = getTopNonFinishingActivity();
Louis Changcdec0802019-11-11 11:45:07 +0800657
658 final boolean mightReplaceWindow = topActivity != null
659 && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
660 if (mightReplaceWindow) {
661 // We are about to relaunch the activity because its configuration changed due to
662 // being maximized, i.e. size change. The activity will first remove the old window
663 // and then add a new one. This call will tell window manager about this, so it can
664 // preserve the old window until the new one is drawn. This prevents having a gap
665 // between the removal and addition, in which no window is visible. We also want the
666 // entrance of the new window to be properly animated.
667 // Note here we always set the replacing window first, as the flags might be needed
668 // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
669 windowManager.setWillReplaceWindow(topActivity.appToken, animate);
670 }
671
672 mAtmService.deferWindowLayout();
673 boolean kept = true;
674 try {
675 final ActivityRecord r = topRunningActivityLocked();
Louis Changcdec0802019-11-11 11:45:07 +0800676 final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
677 && (topRunningActivityLocked() == r);
678 final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
679 final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
680
681 // In some cases the focused stack isn't the front stack. E.g. pinned stack.
682 // Whenever we are moving the top activity from the front stack we want to make sure to
683 // move the stack to the front.
684 final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
685 && (sourceStack.topRunningActivityLocked() == r);
686
687 final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
688 || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
689
690 reparent(toStack, position, moveStackToFront, reason);
691
692 if (schedulePictureInPictureModeChange) {
693 // Notify of picture-in-picture mode changes
694 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
695 }
696
697 // If the task had focus before (or we're requested to move focus), move focus to the
698 // new stack by moving the stack to the front.
699 if (r != null) {
700 toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
701 wasPaused, reason);
702 }
703 if (!animate) {
704 mAtmService.mStackSupervisor.mNoAnimActivities.add(topActivity);
705 }
706
707 // We might trigger a configuration change. Save the current task bounds for freezing.
708 // TODO: Should this call be moved inside the resize method in WM?
709 toStack.prepareFreezingTaskBounds();
710
711 // Make sure the task has the appropriate bounds/size for the stack it is in.
712 final boolean toStackSplitScreenPrimary =
713 toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
714 final Rect configBounds = getRequestedOverrideBounds();
715 if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
716 || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
717 && !Objects.equals(configBounds, toStack.getRequestedOverrideBounds())) {
718 kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
719 !mightReplaceWindow, deferResume);
720 } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
721 Rect bounds = getLaunchBounds();
722 if (bounds == null) {
723 mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
724 bounds = configBounds;
725 }
726 kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
727 } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
728 if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
729 // Move recents to front so it is not behind home stack when going into docked
730 // mode
731 mAtmService.mStackSupervisor.moveRecentsStackToFront(reason);
732 }
733 kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
734 !mightReplaceWindow, deferResume);
735 }
736 } finally {
737 mAtmService.continueWindowLayout();
738 }
739
740 if (mightReplaceWindow) {
741 // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
742 // window), we need to clear the replace window settings. Otherwise, we schedule a
743 // timeout to remove the old window if the replacing window is not coming in time.
744 windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
745 }
746
747 if (!deferResume) {
748 // The task might have already been running and its visibility needs to be synchronized
749 // with the visibility of the stack / windows.
750 root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
751 root.resumeFocusedStacksTopActivities();
752 }
753
754 // TODO: Handle incorrect request to move before the actual move, not after.
755 supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
756 DEFAULT_DISPLAY, toStack);
757
758 return (preferredStack == toStack);
759 }
760
761 /**
762 * @return {@code true} if the windows of tasks being moved to the target stack from the
763 * source stack should be replaced, meaning that window manager will keep the old window
764 * around until the new is ready.
765 */
766 private static boolean replaceWindowsOnTaskMove(
767 int sourceWindowingMode, int targetWindowingMode) {
768 return sourceWindowingMode == WINDOWING_MODE_FREEFORM
769 || targetWindowingMode == WINDOWING_MODE_FREEFORM;
770 }
771
772 /**
773 * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
774 */
775 TaskSnapshot getSnapshot(boolean reducedResolution, boolean restoreFromDisk) {
776
777 // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
778 // synchronized between AM and WM.
779 return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, reducedResolution,
780 restoreFromDisk);
781 }
782
783 void touchActiveTime() {
784 lastActiveTime = SystemClock.elapsedRealtime();
785 }
786
787 long getInactiveDuration() {
788 return SystemClock.elapsedRealtime() - lastActiveTime;
789 }
790
791 /** Sets the original intent, and the calling uid and package. */
792 void setIntent(ActivityRecord r) {
793 mCallingUid = r.launchedFromUid;
794 mCallingPackage = r.launchedFromPackage;
795 setIntent(r.intent, r.info);
796 setLockTaskAuth(r);
797 }
798
799 /** Sets the original intent, _without_ updating the calling uid or package. */
800 private void setIntent(Intent _intent, ActivityInfo info) {
801 if (intent == null) {
802 mNeverRelinquishIdentity =
803 (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
804 } else if (mNeverRelinquishIdentity) {
805 return;
806 }
807
808 affinity = info.taskAffinity;
809 if (intent == null) {
810 // If this task already has an intent associated with it, don't set the root
811 // affinity -- we don't want it changing after initially set, but the initially
812 // set value may be null.
813 rootAffinity = affinity;
814 }
815 effectiveUid = info.applicationInfo.uid;
816 stringName = null;
817
818 if (info.targetActivity == null) {
819 if (_intent != null) {
820 // If this Intent has a selector, we want to clear it for the
821 // recent task since it is not relevant if the user later wants
822 // to re-launch the app.
823 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
824 _intent = new Intent(_intent);
825 _intent.setSelector(null);
826 _intent.setSourceBounds(null);
827 }
828 }
829 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
830 intent = _intent;
831 realActivity = _intent != null ? _intent.getComponent() : null;
832 origActivity = null;
833 } else {
834 ComponentName targetComponent = new ComponentName(
835 info.packageName, info.targetActivity);
836 if (_intent != null) {
837 Intent targetIntent = new Intent(_intent);
838 targetIntent.setSelector(null);
839 targetIntent.setSourceBounds(null);
840 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
841 "Setting Intent of " + this + " to target " + targetIntent);
842 intent = targetIntent;
843 realActivity = targetComponent;
844 origActivity = _intent.getComponent();
845 } else {
846 intent = null;
847 realActivity = targetComponent;
848 origActivity = new ComponentName(info.packageName, info.name);
849 }
850 }
851
852 final int intentFlags = intent == null ? 0 : intent.getFlags();
853 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
854 // Once we are set to an Intent with this flag, we count this
855 // task as having a true root activity.
856 rootWasReset = true;
857 }
858 mUserId = UserHandle.getUserId(info.applicationInfo.uid);
859 mUserSetupComplete = Settings.Secure.getIntForUser(
860 mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0;
861 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
862 // If the activity itself has requested auto-remove, then just always do it.
863 autoRemoveRecents = true;
864 } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
865 == FLAG_ACTIVITY_NEW_DOCUMENT) {
866 // If the caller has not asked for the document to be retained, then we may
867 // want to turn on auto-remove, depending on whether the target has set its
868 // own document launch mode.
869 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
870 autoRemoveRecents = false;
871 } else {
872 autoRemoveRecents = true;
873 }
874 } else {
875 autoRemoveRecents = false;
876 }
877 if (mResizeMode != info.resizeMode) {
878 mResizeMode = info.resizeMode;
879 updateTaskDescription();
880 }
881 mSupportsPictureInPicture = info.supportsPictureInPicture();
882 }
883
884 /** Sets the original minimal width and height. */
885 private void setMinDimensions(ActivityInfo info) {
886 if (info != null && info.windowLayout != null) {
887 mMinWidth = info.windowLayout.minWidth;
888 mMinHeight = info.windowLayout.minHeight;
889 } else {
890 mMinWidth = INVALID_MIN_SIZE;
891 mMinHeight = INVALID_MIN_SIZE;
892 }
893 }
894
895 /**
896 * Return true if the input activity has the same intent filter as the intent this task
897 * record is based on (normally the root activity intent).
898 */
899 boolean isSameIntentFilter(ActivityRecord r) {
900 final Intent intent = new Intent(r.intent);
901 // Make sure the component are the same if the input activity has the same real activity
902 // as the one in the task because either one of them could be the alias activity.
903 if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
904 intent.setComponent(this.intent.getComponent());
905 }
906 return intent.filterEquals(this.intent);
907 }
908
909 boolean returnsToHomeStack() {
910 final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
911 return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
912 }
913
914 void setPrevAffiliate(Task prevAffiliate) {
915 mPrevAffiliate = prevAffiliate;
916 mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId;
917 }
918
919 void setNextAffiliate(Task nextAffiliate) {
920 mNextAffiliate = nextAffiliate;
921 mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
922 }
923
924 ActivityStack getStack() {
925 return mStack;
926 }
927
928 @Override
929 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
Louis Changcdec0802019-11-11 11:45:07 +0800930 final ActivityStack oldStack = ((ActivityStack) oldParent);
931 final ActivityStack newStack = ((ActivityStack) newParent);
932
933 mStack = newStack;
934
935 super.onParentChanged(newParent, oldParent);
936
937 if (oldStack != null) {
938 for (int i = getChildCount() - 1; i >= 0; --i) {
939 final ActivityRecord activity = getChildAt(i);
940 oldStack.onActivityRemovedFromStack(activity);
941 }
942
943 if (oldStack.inPinnedWindowingMode()
944 && (newStack == null || !newStack.inPinnedWindowingMode())) {
945 // Notify if a task from the pinned stack is being removed
946 // (or moved depending on the mode).
947 mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
948 }
949 }
950
951 if (newStack != null) {
952 for (int i = getChildCount() - 1; i >= 0; --i) {
953 final ActivityRecord activity = getChildAt(i);
954 newStack.onActivityAddedToStack(activity);
955 }
956
957 // TODO: Ensure that this is actually necessary here
958 // Notify the voice session if required
959 if (voiceSession != null) {
960 try {
961 voiceSession.taskStarted(intent, mTaskId);
962 } catch (RemoteException e) {
963 }
964 }
965 }
966
967 // First time we are adding the task to the system.
968 if (oldParent == null && newParent != null) {
969
970 // TODO: Super random place to be doing this, but aligns with what used to be done
971 // before we unified Task level. Look into if this can be done in a better place.
972 updateOverrideConfigurationFromLaunchBounds();
973 }
974
975 // Task is being removed.
976 if (oldParent != null && newParent == null) {
977 cleanUpResourcesForDestroy();
978 }
979
980
981 // Update task bounds if needed.
982 adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
983
984 if (getWindowConfiguration().windowsAreScaleable()) {
985 // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
986 // while a resize is pending.
987 forceWindowsScaleable(true /* force */);
988 } else {
989 forceWindowsScaleable(false /* force */);
990 }
991
992 mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
993 }
994
995 void updateTaskMovement(boolean toFront) {
996 if (isPersistable) {
997 mLastTimeMoved = System.currentTimeMillis();
998 // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
999 // recently will be most negative, tasks sent to the bottom before that will be less
1000 // negative. Similarly for recent tasks moved to the top which will be most positive.
1001 if (!toFront) {
1002 mLastTimeMoved *= -1;
1003 }
1004 }
1005 mAtmService.mRootActivityContainer.invalidateTaskLayers();
1006 }
1007
1008 /**
1009 * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
1010 */
1011 int getStackId() {
1012 return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
1013 }
1014
1015 // Close up recents linked list.
1016 private void closeRecentsChain() {
1017 if (mPrevAffiliate != null) {
1018 mPrevAffiliate.setNextAffiliate(mNextAffiliate);
1019 }
1020 if (mNextAffiliate != null) {
1021 mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
1022 }
1023 setPrevAffiliate(null);
1024 setNextAffiliate(null);
1025 }
1026
1027 void removedFromRecents() {
1028 closeRecentsChain();
1029 if (inRecents) {
1030 inRecents = false;
1031 mAtmService.notifyTaskPersisterLocked(this, false);
1032 }
1033
1034 clearRootProcess();
1035
1036 mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
1037 mTaskId, mUserId);
1038 }
1039
1040 void setTaskToAffiliateWith(Task taskToAffiliateWith) {
1041 closeRecentsChain();
1042 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
1043 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
1044 // Find the end
1045 while (taskToAffiliateWith.mNextAffiliate != null) {
1046 final Task nextRecents = taskToAffiliateWith.mNextAffiliate;
1047 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
1048 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
1049 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
1050 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
1051 nextRecents.setPrevAffiliate(null);
1052 }
1053 taskToAffiliateWith.setNextAffiliate(null);
1054 break;
1055 }
1056 taskToAffiliateWith = nextRecents;
1057 }
1058 taskToAffiliateWith.setNextAffiliate(this);
1059 setPrevAffiliate(taskToAffiliateWith);
1060 setNextAffiliate(null);
1061 }
1062
1063 /** Returns the intent for the root activity for this task */
1064 Intent getBaseIntent() {
1065 return intent != null ? intent : affinityIntent;
1066 }
1067
1068 /** Returns the first non-finishing activity from the bottom. */
1069 ActivityRecord getRootActivity() {
Wale Ogunwaledfbeed72019-11-20 08:57:39 -08001070 // TODO: Figure out why we historical ignore relinquish identity for this case...
1071 return getRootActivity(true /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/);
1072 }
1073
1074 ActivityRecord getRootActivity(boolean setToBottomIfNone) {
1075 return getRootActivity(false /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/);
1076 }
1077
1078 ActivityRecord getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
1079 ActivityRecord root;
1080 if (ignoreRelinquishIdentity) {
1081 root = getActivity((r) -> !r.finishing, false /*traverseTopToBottom*/);
1082 } else {
1083 root = getActivity((r) ->
1084 !r.finishing && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0,
1085 false /*traverseTopToBottom*/);
Louis Changcdec0802019-11-11 11:45:07 +08001086 }
Wale Ogunwaledfbeed72019-11-20 08:57:39 -08001087
1088 if (root == null && setToBottomIfNone) {
1089 // All activities in the task are either finishing or relinquish task identity.
1090 // But we still want to update the intent, so let's use the bottom activity.
1091 root = getActivity((r) -> true, false /*traverseTopToBottom*/);
1092 }
1093 return root;
Louis Changcdec0802019-11-11 11:45:07 +08001094 }
1095
Wale Ogunwale21e06482019-11-18 05:14:15 -08001096 ActivityRecord getTopNonFinishingActivity() {
1097 return getTopNonFinishingActivity(true /* includeOverlays */);
Louis Changcdec0802019-11-11 11:45:07 +08001098 }
1099
Wale Ogunwale21e06482019-11-18 05:14:15 -08001100 ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
Louis Changcdec0802019-11-11 11:45:07 +08001101 for (int i = getChildCount() - 1; i >= 0; --i) {
1102 final ActivityRecord r = getChildAt(i);
1103 if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
1104 continue;
1105 }
1106 return r;
1107 }
1108 return null;
1109 }
1110
1111 ActivityRecord topRunningActivityLocked() {
1112 if (mStack != null) {
1113 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
1114 ActivityRecord r = getChildAt(activityNdx);
1115 if (!r.finishing && r.okToShowLocked()) {
1116 return r;
1117 }
1118 }
1119 }
1120 return null;
1121 }
1122
1123 /**
1124 * Return true if any activities in this task belongs to input uid.
1125 */
1126 boolean containsAppUid(int uid) {
1127 for (int i = getChildCount() - 1; i >= 0; --i) {
1128 final ActivityRecord r = getChildAt(i);
1129 if (r.getUid() == uid) {
1130 return true;
1131 }
1132 }
1133 return false;
1134 }
1135
1136 void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
1137 if (mStack != null) {
1138 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
1139 ActivityRecord r = getChildAt(activityNdx);
1140 if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
1141 outActivities.add(r);
1142 }
1143 }
1144 }
1145 }
1146
1147 ActivityRecord topRunningActivityWithStartingWindowLocked() {
1148 if (mStack != null) {
1149 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
1150 ActivityRecord r = getChildAt(activityNdx);
1151 if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
1152 || r.finishing || !r.okToShowLocked()) {
1153 continue;
1154 }
1155 return r;
1156 }
1157 }
1158 return null;
1159 }
1160
1161 /**
1162 * Return the number of running activities, and the number of non-finishing/initializing
1163 * activities in the provided {@param reportOut} respectively.
1164 */
1165 void getNumRunningActivities(TaskActivitiesReport reportOut) {
1166 reportOut.reset();
1167 for (int i = getChildCount() - 1; i >= 0; --i) {
1168 final ActivityRecord r = getChildAt(i);
1169 if (r.finishing) {
1170 continue;
1171 }
1172
1173 reportOut.base = r;
1174
1175 // Increment the total number of non-finishing activities
1176 reportOut.numActivities++;
1177
1178 if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
1179 reportOut.top = r;
1180 // Reset the number of running activities until we hit the first non-initializing
1181 // activity
1182 reportOut.numRunning = 0;
1183 }
1184 if (r.attachedToProcess()) {
1185 // Increment the number of actually running activities
1186 reportOut.numRunning++;
1187 }
1188 }
1189 }
1190
1191 boolean okToShowLocked() {
1192 // NOTE: If {@link Task#topRunningActivity} return is not null then it is
1193 // okay to show the activity when locked.
1194 return mAtmService.mStackSupervisor.isCurrentProfileLocked(mUserId)
1195 || topRunningActivityLocked() != null;
1196 }
1197
1198 /**
1199 * Reorder the history stack so that the passed activity is brought to the front.
1200 */
1201 final void moveActivityToFrontLocked(ActivityRecord newTop) {
1202 if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
1203 + newTop + " to stack at top callers=" + Debug.getCallers(4));
1204
1205 positionChildAtTop(newTop);
1206 updateEffectiveIntent();
1207 }
1208
1209 @Override
1210 public int getActivityType() {
1211 final int applicationType = super.getActivityType();
1212 if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
1213 return applicationType;
1214 }
1215 return getChildAt(0).getActivityType();
1216 }
1217
1218 @Override
1219 void addChild(ActivityRecord r, int index) {
1220 // If this task had any child before we added this one.
1221 boolean hadChild = hasChild();
1222
1223 index = getAdjustedAddPosition(r, index);
1224 super.addChild(r, index);
1225
1226 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
1227 r.inHistory = true;
1228
Louis Changcdec0802019-11-11 11:45:07 +08001229 // Only set this based on the first activity
1230 if (!hadChild) {
1231 if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
1232 // Normally non-standard activity type for the activity record will be set when the
1233 // object is created, however we delay setting the standard application type until
1234 // this point so that the task can set the type for additional activities added in
1235 // the else condition below.
1236 r.setActivityType(ACTIVITY_TYPE_STANDARD);
1237 }
1238 setActivityType(r.getActivityType());
1239 isPersistable = r.isPersistable();
1240 mCallingUid = r.launchedFromUid;
1241 mCallingPackage = r.launchedFromPackage;
1242 // Clamp to [1, max].
1243 maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
1244 ActivityTaskManager.getMaxAppRecentsLimitStatic());
1245 } else {
1246 // Otherwise make all added activities match this one.
1247 r.setActivityType(getActivityType());
1248 }
1249
1250 updateEffectiveIntent();
1251 if (r.isPersistable()) {
1252 mAtmService.notifyTaskPersisterLocked(this, false);
1253 }
1254
1255 // Make sure the list of display UID whitelists is updated
1256 // now that this record is in a new task.
1257 mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
1258 }
1259
1260 void addChild(ActivityRecord r) {
1261 addChild(r, Integer.MAX_VALUE /* add on top */);
1262 }
1263
1264 @Override
1265 void removeChild(ActivityRecord r) {
1266 if (!mChildren.contains(r)) {
1267 Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
1268 return;
1269 }
1270
1271 super.removeChild(r);
Louis Changcdec0802019-11-11 11:45:07 +08001272 if (r.isPersistable()) {
1273 mAtmService.notifyTaskPersisterLocked(this, false);
1274 }
1275
1276 if (inPinnedWindowingMode()) {
1277 // We normally notify listeners of task stack changes on pause, however pinned stack
1278 // activities are normally in the paused state so no notification will be sent there
1279 // before the activity is removed. We send it here so instead.
1280 mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
1281 }
1282
1283 final String reason = "removeChild";
1284 if (hasChild()) {
1285 updateEffectiveIntent();
1286
1287 // The following block can be executed multiple times if there is more than one overlay.
1288 // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
1289 // of the task by id and exiting early if not found.
1290 if (onlyHasTaskOverlayActivities(false /* excludingFinishing */)) {
1291 // When destroying a task, tell the supervisor to remove it so that any activity it
1292 // has can be cleaned up correctly. This is currently the only place where we remove
1293 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
1294 // state into removeChild(), we just clear the task here before the other residual
1295 // work.
1296 // TODO: If the callers to removeChild() changes such that we have multiple places
1297 // where we are destroying the task, move this back into removeChild()
1298 mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
1299 !REMOVE_FROM_RECENTS, reason);
1300 }
1301 } else if (!mReuseTask) {
1302 // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
1303 mStack.removeChild(this, reason);
1304 EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
1305 "removeChild: last r=" + r + " in t=" + this);
1306 removeIfPossible();
1307 }
1308 }
1309
1310 /**
1311 * @return whether or not there are ONLY task overlay activities in the stack.
1312 * If {@param excludeFinishing} is set, then ignore finishing activities in the check.
1313 * If there are no task overlay activities, this call returns false.
1314 */
1315 boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
1316 int count = 0;
1317 for (int i = getChildCount() - 1; i >= 0; i--) {
1318 final ActivityRecord r = getChildAt(i);
1319 if (excludeFinishing && r.finishing) {
1320 continue;
1321 }
1322 if (!r.mTaskOverlay) {
1323 return false;
1324 }
1325 count++;
1326 }
1327 return count > 0;
1328 }
1329
1330 boolean autoRemoveFromRecents() {
1331 // We will automatically remove the task either if it has explicitly asked for
1332 // this, or it is empty and has never contained an activity that got shown to
1333 // the user.
1334 return autoRemoveRecents || (!hasChild() && !hasBeenVisible);
1335 }
1336
1337 /**
1338 * Completely remove all activities associated with an existing
1339 * task starting at a specified index.
1340 */
Wale Ogunwale21e06482019-11-18 05:14:15 -08001341 private void performClearTaskAtIndexLocked(String reason) {
Louis Changcdec0802019-11-11 11:45:07 +08001342 int numActivities = getChildCount();
Wale Ogunwale21e06482019-11-18 05:14:15 -08001343 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
Louis Changcdec0802019-11-11 11:45:07 +08001344 final ActivityRecord r = getChildAt(activityNdx);
1345 if (r.finishing) {
1346 continue;
1347 }
1348 if (mStack == null) {
1349 // Task was restored from persistent storage.
1350 r.takeFromHistory();
1351 removeChild(r);
1352 --activityNdx;
1353 --numActivities;
1354 } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
1355 false /* oomAdj */)
1356 == FINISH_RESULT_REMOVED) {
1357 --activityNdx;
1358 --numActivities;
1359 }
1360 }
1361 }
1362
1363 /**
1364 * Completely remove all activities associated with an existing task.
1365 */
1366 void performClearTaskLocked() {
1367 mReuseTask = true;
Wale Ogunwale21e06482019-11-18 05:14:15 -08001368 performClearTaskAtIndexLocked("clear-task-all");
Louis Changcdec0802019-11-11 11:45:07 +08001369 mReuseTask = false;
1370 }
1371
1372 ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
1373 mReuseTask = true;
1374 final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
1375 mReuseTask = false;
1376 return result;
1377 }
1378
1379 /**
1380 * Perform clear operation as requested by
1381 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
1382 * stack to the given task, then look for
1383 * an instance of that activity in the stack and, if found, finish all
1384 * activities on top of it and return the instance.
1385 *
1386 * @param newR Description of the new activity being started.
1387 * @return Returns the old activity that should be continued to be used,
1388 * or {@code null} if none was found.
1389 */
1390 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
1391 int numActivities = getChildCount();
1392 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
1393 ActivityRecord r = getChildAt(activityNdx);
1394 if (r.finishing) {
1395 continue;
1396 }
1397 if (r.mActivityComponent.equals(newR.mActivityComponent)) {
1398 // Here it is! Now finish everything in front...
1399 final ActivityRecord ret = r;
1400
1401 for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
1402 r = getChildAt(activityNdx);
1403 if (r.finishing) {
1404 continue;
1405 }
1406 ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
1407 if (opts != null) {
1408 ret.updateOptionsLocked(opts);
1409 }
1410 if (r.finishIfPossible("clear-task-stack", false /* oomAdj */)
1411 == FINISH_RESULT_REMOVED) {
1412 --activityNdx;
1413 --numActivities;
1414 }
1415 }
1416
1417 // Finally, if this is a normal launch mode (that is, not
1418 // expecting onNewIntent()), then we will finish the current
1419 // instance of the activity so a new fresh one can be started.
1420 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
1421 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
1422 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
1423 if (!ret.finishing) {
1424 ret.finishIfPossible("clear-task-top", false /* oomAdj */);
1425 return null;
1426 }
1427 }
1428
1429 return ret;
1430 }
1431 }
1432
1433 return null;
1434 }
1435
1436 void removeTaskActivitiesLocked(String reason) {
1437 // Just remove the entire task.
Wale Ogunwale21e06482019-11-18 05:14:15 -08001438 performClearTaskAtIndexLocked(reason);
Louis Changcdec0802019-11-11 11:45:07 +08001439 }
1440
1441 String lockTaskAuthToString() {
1442 switch (mLockTaskAuth) {
1443 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
1444 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
1445 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
1446 case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
1447 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
1448 default: return "unknown=" + mLockTaskAuth;
1449 }
1450 }
1451
1452 void setLockTaskAuth() {
1453 setLockTaskAuth(getRootActivity());
1454 }
1455
1456 private void setLockTaskAuth(@Nullable ActivityRecord r) {
1457 if (r == null) {
1458 mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
1459 return;
1460 }
1461
1462 final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
1463 final LockTaskController lockTaskController = mAtmService.getLockTaskController();
1464 switch (r.lockTaskLaunchMode) {
1465 case LOCK_TASK_LAUNCH_MODE_DEFAULT:
1466 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
1467 ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
1468 break;
1469
1470 case LOCK_TASK_LAUNCH_MODE_NEVER:
1471 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
1472 break;
1473
1474 case LOCK_TASK_LAUNCH_MODE_ALWAYS:
1475 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
1476 break;
1477
1478 case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
1479 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
1480 ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
1481 break;
1482 }
1483 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
1484 + " mLockTaskAuth=" + lockTaskAuthToString());
1485 }
1486
1487 @Override
1488 public boolean supportsSplitScreenWindowingMode() {
1489 // A task can not be docked even if it is considered resizeable because it only supports
1490 // picture-in-picture mode but has a non-resizeable resizeMode
1491 return super.supportsSplitScreenWindowingMode()
1492 // TODO(task-group): Probably makes sense to move this and associated code into
1493 // WindowContainer so it affects every node.
1494 && mAtmService.mSupportsSplitScreenMultiWindow
1495 && (mAtmService.mForceResizableActivities
1496 || (isResizeable(false /* checkSupportsPip */)
1497 && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
1498 }
1499
1500 /**
1501 * Check whether this task can be launched on the specified display.
1502 *
1503 * @param displayId Target display id.
1504 * @return {@code true} if either it is the default display or this activity can be put on a
1505 * secondary display.
1506 */
1507 boolean canBeLaunchedOnDisplay(int displayId) {
1508 return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
1509 -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
1510 }
1511
1512 /**
1513 * Check that a given bounds matches the application requested orientation.
1514 *
1515 * @param bounds The bounds to be tested.
1516 * @return True if the requested bounds are okay for a resizing request.
1517 */
1518 private boolean canResizeToBounds(Rect bounds) {
1519 if (bounds == null || !inFreeformWindowingMode()) {
1520 // Note: If not on the freeform workspace, we ignore the bounds.
1521 return true;
1522 }
1523 final boolean landscape = bounds.width() > bounds.height();
1524 final Rect configBounds = getRequestedOverrideBounds();
1525 if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
1526 return configBounds.isEmpty()
1527 || landscape == (configBounds.width() > configBounds.height());
1528 }
1529 return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
1530 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
1531 }
1532
1533 /**
1534 * @return {@code true} if the task is being cleared for the purposes of being reused.
1535 */
1536 boolean isClearingToReuseTask() {
1537 return mReuseTask;
1538 }
1539
1540 /**
1541 * Find the activity in the history stack within the given task. Returns
1542 * the index within the history at which it's found, or < 0 if not found.
1543 */
1544 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
1545 final ComponentName realActivity = r.mActivityComponent;
1546 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
1547 ActivityRecord candidate = getChildAt(activityNdx);
1548 if (candidate.finishing) {
1549 continue;
1550 }
1551 if (candidate.mActivityComponent.equals(realActivity)) {
1552 return candidate;
1553 }
1554 }
1555 return null;
1556 }
1557
1558 /** Updates the last task description values. */
1559 void updateTaskDescription() {
1560 // TODO(AM refactor): Cleanup to use findRootIndex()
1561 // Traverse upwards looking for any break between main task activities and
1562 // utility activities.
1563 int activityNdx;
1564 final int numActivities = getChildCount();
1565 final boolean relinquish = numActivities != 0
1566 && (getChildAt(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
1567 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; ++activityNdx) {
1568 final ActivityRecord r = getChildAt(activityNdx);
1569 if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1570 // This will be the top activity for determining taskDescription. Pre-inc to
1571 // overcome initial decrement below.
1572 ++activityNdx;
1573 break;
1574 }
1575 if (r.intent != null
1576 && (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1577 break;
1578 }
1579 }
1580 if (activityNdx > 0) {
1581 // Traverse downwards starting below break looking for set label, icon.
1582 // Note that if there are activities in the task but none of them set the
1583 // recent activity values, then we do not fall back to the last set
1584 // values in the Task.
1585 String label = null;
1586 String iconFilename = null;
1587 int iconResource = -1;
1588 int colorPrimary = 0;
1589 int colorBackground = 0;
1590 int statusBarColor = 0;
1591 int navigationBarColor = 0;
1592 boolean statusBarContrastWhenTransparent = false;
1593 boolean navigationBarContrastWhenTransparent = false;
1594 boolean topActivity = true;
1595 for (--activityNdx; activityNdx >= 0; --activityNdx) {
1596 final ActivityRecord r = getChildAt(activityNdx);
1597 if (r.mTaskOverlay) {
1598 continue;
1599 }
1600 if (r.taskDescription != null) {
1601 if (label == null) {
1602 label = r.taskDescription.getLabel();
1603 }
1604 if (iconResource == -1) {
1605 iconResource = r.taskDescription.getIconResource();
1606 }
1607 if (iconFilename == null) {
1608 iconFilename = r.taskDescription.getIconFilename();
1609 }
1610 if (colorPrimary == 0) {
1611 colorPrimary = r.taskDescription.getPrimaryColor();
1612 }
1613 if (topActivity) {
1614 colorBackground = r.taskDescription.getBackgroundColor();
1615 statusBarColor = r.taskDescription.getStatusBarColor();
1616 navigationBarColor = r.taskDescription.getNavigationBarColor();
1617 statusBarContrastWhenTransparent =
1618 r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
1619 navigationBarContrastWhenTransparent =
1620 r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
1621 }
1622 }
1623 topActivity = false;
1624 }
1625 final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
1626 iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
1627 statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent,
1628 mResizeMode, mMinWidth, mMinHeight);
1629 setTaskDescription(taskDescription);
1630 // Update the task affiliation color if we are the parent of the group
1631 if (mTaskId == mAffiliatedTaskId) {
1632 mAffiliatedTaskColor = taskDescription.getPrimaryColor();
1633 }
1634 mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
1635 getTaskInfo());
1636 }
1637 }
1638
1639 /**
1640 * Find the index of the root activity in the task. It will be the first activity from the
1641 * bottom that is not finishing.
1642 *
1643 * @param effectiveRoot Flag indicating whether 'effective root' should be returned - an
1644 * activity that defines the task identity (its base intent). It's the
1645 * first one that does not have
1646 * {@link ActivityInfo#FLAG_RELINQUISH_TASK_IDENTITY}.
1647 * @return index of the 'root' or 'effective' root in the list of activities, -1 if no eligible
1648 * activity was found.
1649 */
1650 int findRootIndex(boolean effectiveRoot) {
1651 int effectiveNdx = -1;
1652 final int topActivityNdx = getChildCount() - 1;
1653 for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
1654 final ActivityRecord r = getChildAt(activityNdx);
1655 if (r.finishing) {
1656 continue;
1657 }
1658 effectiveNdx = activityNdx;
1659 if (!effectiveRoot || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1660 break;
1661 }
1662 }
1663 return effectiveNdx;
1664 }
1665
1666 // TODO (AM refactor): Invoke automatically when there is a change in children
1667 @VisibleForTesting
1668 void updateEffectiveIntent() {
1669 int effectiveRootIndex = findRootIndex(true /* effectiveRoot */);
1670 if (effectiveRootIndex == -1) {
1671 // All activities in the task are either finishing or relinquish task identity.
1672 // But we still want to update the intent, so let's use the bottom activity.
1673 effectiveRootIndex = 0;
1674 }
1675 final ActivityRecord r = getChildAt(effectiveRootIndex);
1676 setIntent(r);
1677
1678 // Update the task description when the activities change
1679 updateTaskDescription();
1680 }
1681
1682 void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
Evan Rosky70213702019-11-05 10:26:24 -08001683 final Rect parentBounds = getParent() != null ? getParent().getBounds() : null;
1684 if (bounds == null
1685 || (bounds.isEmpty() && (parentBounds == null || parentBounds.isEmpty()))) {
Louis Changcdec0802019-11-11 11:45:07 +08001686 return;
1687 }
1688 int minWidth = mMinWidth;
1689 int minHeight = mMinHeight;
1690 // If the task has no requested minimal size, we'd like to enforce a minimal size
1691 // so that the user can not render the task too small to manipulate. We don't need
1692 // to do this for the pinned stack as the bounds are controlled by the system.
1693 if (!inPinnedWindowingMode() && mStack != null) {
1694 final int defaultMinSizeDp =
1695 mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
1696 final ActivityDisplay display =
1697 mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
1698 final float density =
1699 (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
1700 final int defaultMinSize = (int) (defaultMinSizeDp * density);
1701
1702 if (minWidth == INVALID_MIN_SIZE) {
1703 minWidth = defaultMinSize;
1704 }
1705 if (minHeight == INVALID_MIN_SIZE) {
1706 minHeight = defaultMinSize;
1707 }
1708 }
Evan Rosky70213702019-11-05 10:26:24 -08001709 if (bounds.isEmpty()) {
1710 // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
1711 // do, we can just skip.
1712 if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
1713 return;
1714 }
1715 bounds.set(parentBounds);
1716 }
Louis Changcdec0802019-11-11 11:45:07 +08001717 final boolean adjustWidth = minWidth > bounds.width();
1718 final boolean adjustHeight = minHeight > bounds.height();
1719 if (!(adjustWidth || adjustHeight)) {
1720 return;
1721 }
1722
1723 if (adjustWidth) {
1724 if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
1725 bounds.left = bounds.right - minWidth;
1726 } else {
1727 // Either left bounds match, or neither match, or the previous bounds were
1728 // fullscreen and we default to keeping left.
1729 bounds.right = bounds.left + minWidth;
1730 }
1731 }
1732 if (adjustHeight) {
1733 if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
1734 bounds.top = bounds.bottom - minHeight;
1735 } else {
1736 // Either top bounds match, or neither match, or the previous bounds were
1737 // fullscreen and we default to keeping top.
1738 bounds.bottom = bounds.top + minHeight;
1739 }
1740 }
1741 }
1742
1743 void setLastNonFullscreenBounds(Rect bounds) {
1744 if (mLastNonFullscreenBounds == null) {
1745 mLastNonFullscreenBounds = new Rect(bounds);
1746 } else {
1747 mLastNonFullscreenBounds.set(bounds);
1748 }
1749 }
1750
1751 /**
1752 * This should be called when an child activity changes state. This should only
1753 * be called from
1754 * {@link ActivityRecord#setState(ActivityState, String)} .
1755 * @param record The {@link ActivityRecord} whose state has changed.
1756 * @param state The new state.
1757 * @param reason The reason for the change.
1758 */
1759 void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
1760 final ActivityStack parent = getStack();
1761
1762 if (parent != null) {
1763 parent.onActivityStateChanged(record, state, reason);
1764 }
1765 }
1766
1767 @Override
1768 public void onConfigurationChanged(Configuration newParentConfig) {
1769 // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
1770 // restore the last recorded non-fullscreen bounds.
1771 final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
1772 final boolean nextPersistTaskBounds =
1773 getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
1774 || newParentConfig.windowConfiguration.persistTaskBounds();
1775 if (!prevPersistTaskBounds && nextPersistTaskBounds
1776 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
1777 // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
1778 getRequestedOverrideConfiguration().windowConfiguration
1779 .setBounds(mLastNonFullscreenBounds);
1780 }
1781
1782 final boolean wasInMultiWindowMode = inMultiWindowMode();
1783 super.onConfigurationChanged(newParentConfig);
1784 if (wasInMultiWindowMode != inMultiWindowMode()) {
1785 mAtmService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
1786 }
1787
1788 // If the configuration supports persistent bounds (eg. Freeform), keep track of the
1789 // current (non-fullscreen) bounds for persistence.
1790 if (getWindowConfiguration().persistTaskBounds()) {
1791 final Rect currentBounds = getRequestedOverrideBounds();
1792 if (!currentBounds.isEmpty()) {
1793 setLastNonFullscreenBounds(currentBounds);
1794 }
1795 }
1796 // TODO: Should also take care of Pip mode changes here.
1797
1798 saveLaunchingStateIfNeeded();
1799 }
1800
1801 /**
1802 * Saves launching state if necessary so that we can launch the activity to its latest state.
1803 * It only saves state if this task has been shown to user and it's in fullscreen or freeform
1804 * mode on freeform displays.
1805 */
1806 void saveLaunchingStateIfNeeded() {
1807 if (!hasBeenVisible) {
1808 // Not ever visible to user.
1809 return;
1810 }
1811
1812 final int windowingMode = getWindowingMode();
1813 if (windowingMode != WINDOWING_MODE_FULLSCREEN
1814 && windowingMode != WINDOWING_MODE_FREEFORM) {
1815 return;
1816 }
1817
1818 // Don't persist state if display isn't in freeform mode. Then the task will be launched
1819 // back to its last state in a freeform display when it's launched in a freeform display
1820 // next time.
1821 if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) {
1822 return;
1823 }
1824
1825 // Saves the new state so that we can launch the activity at the same location.
1826 mAtmService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
1827 }
1828
1829 /**
1830 * Adjust bounds to stay within stack bounds.
1831 *
1832 * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
1833 * that keep them unchanged, but be contained within the stack bounds.
1834 *
1835 * @param bounds Bounds to be adjusted.
1836 * @param stackBounds Bounds within which the other bounds should remain.
1837 * @param overlapPxX The amount of px required to be visible in the X dimension.
1838 * @param overlapPxY The amount of px required to be visible in the Y dimension.
1839 */
1840 private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
1841 int overlapPxY) {
1842 if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
1843 return;
1844 }
1845
1846 // For each side of the parent (eg. left), check if the opposing side of the window (eg.
1847 // right) is at least overlap pixels away. If less, offset the window by that difference.
1848 int horizontalDiff = 0;
1849 // If window is smaller than overlap, use it's smallest dimension instead
1850 int overlapLR = Math.min(overlapPxX, bounds.width());
1851 if (bounds.right < (stackBounds.left + overlapLR)) {
1852 horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
1853 } else if (bounds.left > (stackBounds.right - overlapLR)) {
1854 horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
1855 }
1856 int verticalDiff = 0;
1857 int overlapTB = Math.min(overlapPxY, bounds.width());
1858 if (bounds.bottom < (stackBounds.top + overlapTB)) {
1859 verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
1860 } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
1861 verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
1862 }
1863 bounds.offset(horizontalDiff, verticalDiff);
1864 }
1865
1866 /**
1867 * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
1868 * intersectBounds on a side, then the respective side will not be intersected.
1869 *
1870 * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
1871 * inset on that side is no-longer applicable. This scenario happens when a task's minimal
1872 * bounds are larger than the provided parent/display bounds.
1873 *
1874 * @param inOutBounds the bounds to intersect.
1875 * @param intersectBounds the bounds to intersect with.
1876 * @param intersectInsets insets to apply to intersectBounds before intersecting.
1877 */
1878 static void intersectWithInsetsIfFits(
1879 Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
1880 if (inOutBounds.right <= intersectBounds.right) {
1881 inOutBounds.right =
1882 Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
1883 }
1884 if (inOutBounds.bottom <= intersectBounds.bottom) {
1885 inOutBounds.bottom =
1886 Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
1887 }
1888 if (inOutBounds.left >= intersectBounds.left) {
1889 inOutBounds.left =
1890 Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
1891 }
1892 if (inOutBounds.top >= intersectBounds.top) {
1893 inOutBounds.top =
1894 Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
1895 }
1896 }
1897
1898 /**
1899 * Gets bounds with non-decor and stable insets applied respectively.
1900 *
1901 * If bounds overhangs the display, those edges will not get insets. See
1902 * {@link #intersectWithInsetsIfFits}
1903 *
1904 * @param outNonDecorBounds where to place bounds with non-decor insets applied.
1905 * @param outStableBounds where to place bounds with stable insets applied.
1906 * @param bounds the bounds to inset.
1907 */
1908 private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
1909 DisplayInfo displayInfo) {
1910 outNonDecorBounds.set(bounds);
1911 outStableBounds.set(bounds);
1912 if (getStack() == null || getStack().getDisplay() == null) {
1913 return;
1914 }
1915 DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
1916 if (policy == null) {
1917 return;
1918 }
1919 mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
1920
1921 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
1922 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
1923 intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
1924
1925 policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
1926 intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
1927 }
1928
1929 /**
1930 * Asks docked-divider controller for the smallestwidthdp given bounds.
1931 * @param bounds bounds to calculate smallestwidthdp for.
1932 */
1933 private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
1934 DisplayContent dc = mStack.getDisplay().mDisplayContent;
1935 if (dc != null) {
1936 return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
1937 }
1938 return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
1939 }
1940
1941 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1942 @NonNull Configuration parentConfig) {
1943 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
1944 }
1945
1946 /**
1947 * Calculates configuration values used by the client to get resources. This should be run
1948 * using app-facing bounds (bounds unmodified by animations or transient interactions).
1949 *
1950 * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
1951 * configuring an "inherit-bounds" window which means that all configuration settings would
1952 * just be inherited from the parent configuration.
1953 **/
1954 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1955 @NonNull Configuration parentConfig,
1956 @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
1957 int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
1958 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1959 windowingMode = parentConfig.windowConfiguration.getWindowingMode();
1960 }
1961
1962 float density = inOutConfig.densityDpi;
1963 if (density == Configuration.DENSITY_DPI_UNDEFINED) {
1964 density = parentConfig.densityDpi;
1965 }
1966 density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
1967
Evan Rosky70213702019-11-05 10:26:24 -08001968 final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
1969 if (resolvedBounds == null) {
1970 mTmpFullBounds.setEmpty();
1971 } else {
1972 mTmpFullBounds.set(resolvedBounds);
1973 }
1974 if (mTmpFullBounds.isEmpty()) {
1975 mTmpFullBounds.set(parentConfig.windowConfiguration.getBounds());
1976 }
1977
Louis Changcdec0802019-11-11 11:45:07 +08001978 Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
1979 if (outAppBounds == null || outAppBounds.isEmpty()) {
Evan Rosky70213702019-11-05 10:26:24 -08001980 inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds);
Louis Changcdec0802019-11-11 11:45:07 +08001981 outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
1982 }
1983 // Non-null compatibility insets means the activity prefers to keep its original size, so
1984 // the out bounds doesn't need to be restricted by the parent.
1985 final boolean insideParentBounds = compatInsets == null;
1986 if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
1987 final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
1988 if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
1989 outAppBounds.intersect(parentAppBounds);
1990 }
1991 }
1992
1993 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
1994 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
1995 if (insideParentBounds && mStack != null) {
1996 final DisplayInfo di = new DisplayInfo();
1997 mStack.getDisplay().mDisplay.getDisplayInfo(di);
1998
1999 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
2000 // area, i.e. the screen area without the system bars.
2001 // The non decor inset are areas that could never be removed in Honeycomb. See
2002 // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
Evan Rosky70213702019-11-05 10:26:24 -08002003 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);
Louis Changcdec0802019-11-11 11:45:07 +08002004 } else {
2005 // Apply the given non-decor and stable insets to calculate the corresponding bounds
2006 // for screen size of configuration.
2007 int rotation = inOutConfig.windowConfiguration.getRotation();
2008 if (rotation == ROTATION_UNDEFINED) {
2009 rotation = parentConfig.windowConfiguration.getRotation();
2010 }
2011 if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
Evan Rosky70213702019-11-05 10:26:24 -08002012 mTmpNonDecorBounds.set(mTmpFullBounds);
2013 mTmpStableBounds.set(mTmpFullBounds);
Louis Changcdec0802019-11-11 11:45:07 +08002014 compatInsets.getDisplayBoundsByRotation(mTmpBounds, rotation);
2015 intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
2016 compatInsets.mNonDecorInsets[rotation]);
2017 intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
2018 compatInsets.mStableInsets[rotation]);
2019 outAppBounds.set(mTmpNonDecorBounds);
2020 } else {
2021 // Set to app bounds because it excludes decor insets.
2022 mTmpNonDecorBounds.set(outAppBounds);
2023 mTmpStableBounds.set(outAppBounds);
2024 }
2025 }
2026
2027 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
2028 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
2029 inOutConfig.screenWidthDp = insideParentBounds
2030 ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
2031 : overrideScreenWidthDp;
2032 }
2033 if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2034 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
2035 inOutConfig.screenHeightDp = insideParentBounds
2036 ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
2037 : overrideScreenHeightDp;
2038 }
2039
2040 if (inOutConfig.smallestScreenWidthDp
2041 == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
2042 if (WindowConfiguration.isFloating(windowingMode)) {
2043 // For floating tasks, calculate the smallest width from the bounds of the task
2044 inOutConfig.smallestScreenWidthDp = (int) (
Evan Rosky70213702019-11-05 10:26:24 -08002045 Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
Louis Changcdec0802019-11-11 11:45:07 +08002046 } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
2047 // Iterating across all screen orientations, and return the minimum of the task
2048 // width taking into account that the bounds might change because the snap
2049 // algorithm snaps to a different value
2050 inOutConfig.smallestScreenWidthDp =
Evan Rosky70213702019-11-05 10:26:24 -08002051 getSmallestScreenWidthDpForDockedBounds(mTmpFullBounds);
Louis Changcdec0802019-11-11 11:45:07 +08002052 }
2053 // otherwise, it will just inherit
2054 }
2055 }
2056
2057 if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
2058 inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
2059 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
2060 }
2061 if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
2062 // For calculating screen layout, we need to use the non-decor inset screen area for the
2063 // calculation for compatibility reasons, i.e. screen area without system bars that
2064 // could never go away in Honeycomb.
2065 final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
2066 final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
2067 // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start
2068 // override calculation with partial default.
2069 // Reducing the screen layout starting from its parent config.
2070 final int sl = parentConfig.screenLayout
2071 & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
2072 final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
2073 final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
2074 inOutConfig.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
2075 }
2076 }
2077
2078 @Override
2079 void resolveOverrideConfiguration(Configuration newParentConfig) {
2080 mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
2081 super.resolveOverrideConfiguration(newParentConfig);
2082 int windowingMode =
2083 getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
2084 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
2085 windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
2086 }
2087 Rect outOverrideBounds =
2088 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
2089
2090 if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
2091 computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
2092 newParentConfig.windowConfiguration.getBounds(),
2093 newParentConfig.orientation);
2094 }
2095
Louis Changcdec0802019-11-11 11:45:07 +08002096 adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
2097 if (windowingMode == WINDOWING_MODE_FREEFORM) {
2098 // by policy, make sure the window remains within parent somewhere
2099 final float density =
2100 ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
2101 final Rect parentBounds =
2102 new Rect(newParentConfig.windowConfiguration.getBounds());
2103 final ActivityDisplay display = mStack.getDisplay();
2104 if (display != null && display.mDisplayContent != null) {
2105 // If a freeform window moves below system bar, there is no way to move it again
2106 // by touch. Because its caption is covered by system bar. So we exclude them
2107 // from stack bounds. and then caption will be shown inside stable area.
2108 final Rect stableBounds = new Rect();
2109 display.mDisplayContent.getStableRect(stableBounds);
2110 parentBounds.intersect(stableBounds);
2111 }
2112
2113 fitWithinBounds(outOverrideBounds, parentBounds,
2114 (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
2115 (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
2116
2117 // Prevent to overlap caption with stable insets.
2118 final int offsetTop = parentBounds.top - outOverrideBounds.top;
2119 if (offsetTop > 0) {
2120 outOverrideBounds.offset(0, offsetTop);
2121 }
2122 }
2123 computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
2124 }
2125
2126 /**
2127 * Compute bounds (letterbox or pillarbox) for
2128 * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
2129 * orientation change and the requested orientation is different from the parent.
2130 */
2131 void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
2132 @NonNull Rect parentBounds, int parentOrientation) {
2133 // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
2134 outBounds.setEmpty();
2135 if (handlesOrientationChangeFromDescendant()) {
2136 return;
2137 }
2138 if (refActivity == null) {
2139 // Use the top activity as the reference of orientation. Don't include overlays because
2140 // it is usually not the actual content or just temporarily shown.
2141 // E.g. ForcedResizableInfoActivity.
Wale Ogunwale21e06482019-11-18 05:14:15 -08002142 refActivity = getTopNonFinishingActivity(false /* includeOverlays */);
Louis Changcdec0802019-11-11 11:45:07 +08002143 }
2144
2145 // If the task or the reference activity requires a different orientation (either by
2146 // override or activityInfo), make it fit the available bounds by scaling down its bounds.
2147 final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
2148 final int forcedOrientation =
2149 (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
2150 ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
2151 if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
2152 return;
2153 }
2154
2155 final int parentWidth = parentBounds.width();
2156 final int parentHeight = parentBounds.height();
2157 final float aspect = ((float) parentHeight) / parentWidth;
2158 if (forcedOrientation == ORIENTATION_LANDSCAPE) {
2159 final int height = (int) (parentWidth / aspect);
2160 final int top = parentBounds.centerY() - height / 2;
2161 outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
2162 } else {
2163 final int width = (int) (parentHeight * aspect);
2164 final int left = parentBounds.centerX() - width / 2;
2165 outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
2166 }
2167 }
2168
2169 Rect updateOverrideConfigurationFromLaunchBounds() {
2170 final Rect bounds = getLaunchBounds();
2171 setBounds(bounds);
2172 if (bounds != null && !bounds.isEmpty()) {
2173 // TODO: Review if we actually want to do this - we are setting the launch bounds
2174 // directly here.
2175 bounds.set(getRequestedOverrideBounds());
2176 }
2177 return bounds;
2178 }
2179
2180 /** Updates the task's bounds and override configuration to match what is expected for the
2181 * input stack. */
2182 void updateOverrideConfigurationForStack(ActivityStack inStack) {
2183 if (mStack != null && mStack == inStack) {
2184 return;
2185 }
2186
2187 if (inStack.inFreeformWindowingMode()) {
2188 if (!isResizeable()) {
2189 throw new IllegalArgumentException("Can not position non-resizeable task="
2190 + this + " in stack=" + inStack);
2191 }
2192 if (!matchParentBounds()) {
2193 return;
2194 }
2195 if (mLastNonFullscreenBounds != null) {
2196 setBounds(mLastNonFullscreenBounds);
2197 } else {
2198 mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
2199 }
2200 } else {
2201 setBounds(inStack.getRequestedOverrideBounds());
2202 }
2203 }
2204
2205 /** Returns the bounds that should be used to launch this task. */
2206 Rect getLaunchBounds() {
2207 if (mStack == null) {
2208 return null;
2209 }
2210
2211 final int windowingMode = getWindowingMode();
2212 if (!isActivityTypeStandardOrUndefined()
2213 || windowingMode == WINDOWING_MODE_FULLSCREEN
2214 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
2215 return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
2216 } else if (!getWindowConfiguration().persistTaskBounds()) {
2217 return mStack.getRequestedOverrideBounds();
2218 }
2219 return mLastNonFullscreenBounds;
2220 }
2221
2222 void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
2223 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
2224 final ActivityRecord r = getChildAt(activityNdx);
Issei Suzuki1669ea42019-11-06 14:20:59 +01002225 if (r.mVisibleRequested) {
Louis Changcdec0802019-11-11 11:45:07 +08002226 r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
2227 }
2228 }
2229 }
2230
2231 void setRootProcess(WindowProcessController proc) {
2232 clearRootProcess();
2233 if (intent != null
2234 && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
2235 mRootProcess = proc;
2236 mRootProcess.addRecentTask(this);
2237 }
2238 }
2239
2240 void clearRootProcess() {
2241 if (mRootProcess != null) {
2242 mRootProcess.removeRecentTask(this);
2243 mRootProcess = null;
2244 }
2245 }
2246
2247 void clearAllPendingOptions() {
2248 for (int i = getChildCount() - 1; i >= 0; i--) {
2249 getChildAt(i).clearOptionsLocked(false /* withAbort */);
2250 }
Craig Mautnerc00204b2013-03-05 15:02:14 -08002251 }
2252
Tiger Huanged6794e2019-05-07 20:07:59 +08002253 @Override
Craig Mautnerc00204b2013-03-05 15:02:14 -08002254 DisplayContent getDisplayContent() {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002255 return getTaskStack() != null ? getTaskStack().getDisplayContent() : null;
2256 }
2257
Louis Changdc077272019-11-12 16:52:56 +08002258 ActivityStack getTaskStack() {
2259 return (ActivityStack) getParent();
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002260 }
2261
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002262 int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
2263 int maxPosition = mChildren.size();
2264 if (!r.mTaskOverlay) {
2265 // We want to place all non-overlay activities below overlays.
2266 while (maxPosition > 0) {
2267 final ActivityRecord current = mChildren.get(maxPosition - 1);
Wale Ogunwale7a8889a2019-11-16 08:23:42 -08002268 if (current.mTaskOverlay) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002269 --maxPosition;
2270 continue;
2271 }
2272 break;
2273 }
2274 if (maxPosition < 0) {
2275 maxPosition = 0;
2276 }
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002277 }
2278
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002279 return Math.min(maxPosition, suggestedPosition);
Craig Mautnerc00204b2013-03-05 15:02:14 -08002280 }
2281
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002282 @Override
Wale Ogunwale3198da42019-10-10 14:45:03 +02002283 void positionChildAt(int position, ActivityRecord child, boolean includingParents) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002284 position = getAdjustedAddPosition(child, position);
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002285 super.positionChildAt(position, child, includingParents);
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002286 }
2287
Wale Ogunwalee42d0e12016-05-02 16:40:59 -07002288 private boolean hasWindowsAlive() {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002289 for (int i = mChildren.size() - 1; i >= 0; i--) {
2290 if (mChildren.get(i).hasWindowsAlive()) {
Chong Zhang7e8eeb72016-01-06 19:14:47 -08002291 return true;
2292 }
2293 }
2294 return false;
2295 }
2296
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002297 @VisibleForTesting
2298 boolean shouldDeferRemoval() {
Wale Ogunwalec17418e2019-10-13 23:00:40 +02002299 if (mChildren.isEmpty()) {
2300 // No reason to defer removal of a Task that doesn't have any child.
2301 return false;
2302 }
Wale Ogunwale8577a052019-10-26 23:22:34 -07002303 return hasWindowsAlive() && getTaskStack().isAnimating(TRANSITION | CHILDREN);
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002304 }
2305
Wale Ogunwalef6192862016-09-10 13:42:30 -07002306 @Override
Andrii Kulian45a61fe2017-01-05 16:53:19 -08002307 void removeImmediately() {
Wale Ogunwaleb9b16a72016-01-27 12:24:44 -08002308 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -08002309 EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
Andrii Kulian45a61fe2017-01-05 16:53:19 -08002310 super.removeImmediately();
Craig Mautnere3119b72015-01-20 15:02:36 -08002311 }
2312
Louis Changcdec0802019-11-11 11:45:07 +08002313 // TODO: Consolidate this with Task.reparent()
Louis Changdc077272019-11-12 16:52:56 +08002314 void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -08002315 if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
Wale Ogunwale8577a052019-10-26 23:22:34 -07002316 + " from stack=" + getTaskStack());
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -08002317 EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
Andrii Kulian7cd7c2d2017-01-18 12:14:37 -08002318
Louis Changdc077272019-11-12 16:52:56 +08002319 final ActivityStack prevStack = getTaskStack();
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002320 final boolean wasTopFocusedStack =
2321 mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack);
2322 final ActivityDisplay prevStackDisplay = prevStack.getDisplay();
2323
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -07002324 position = stack.findPositionForTask(this, position, showForAllUsers());
2325
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002326 reparent(stack, position);
2327
2328 if (!moveParents) {
2329 // Only move home stack forward if we are not going to move the new parent forward.
2330 prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason);
Robert Carr18f622f2017-05-08 11:20:43 -07002331 }
2332
Louis Changcdec0802019-11-11 11:45:07 +08002333 stack.positionChildAt(position, this, moveParents);
Andrii Kulian7cd7c2d2017-01-18 12:14:37 -08002334
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002335 // If we are moving from the fullscreen stack to the pinned stack then we want to preserve
2336 // our insets so that there will not be a jump in the area covered by system decorations.
2337 // We rely on the pinned animation to later unset this value.
2338 mPreserveNonFloatingState = stack.inPinnedWindowingMode();
Wale Ogunwale53a29a92015-02-23 15:42:52 -08002339 }
2340
Bryce Leef3c6a472017-11-14 14:53:06 -08002341 public int setBounds(Rect bounds, boolean forceResize) {
2342 final int boundsChanged = setBounds(bounds);
2343
2344 if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) {
2345 onResize();
2346 return BOUNDS_CHANGE_SIZE | boundsChanged;
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -07002347 }
Wale Ogunwale68278562017-09-23 17:13:55 -07002348
Bryce Leef3c6a472017-11-14 14:53:06 -08002349 return boundsChanged;
2350 }
2351
2352 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
2353 @Override
2354 public int setBounds(Rect bounds) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002355 int rotation = Surface.ROTATION_0;
Wale Ogunwale8577a052019-10-26 23:22:34 -07002356 final DisplayContent displayContent = getTaskStack() != null
2357 ? getTaskStack().getDisplayContent() : null;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002358 if (displayContent != null) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002359 rotation = displayContent.getDisplayInfo().rotation;
Bryce Leef3c6a472017-11-14 14:53:06 -08002360 } else if (bounds == null) {
Evan Roskye747c3e2018-10-30 20:06:41 -07002361 return super.setBounds(bounds);
Wale Ogunwale2cc92f52015-09-09 13:12:10 -07002362 }
2363
Bryce Leef3c6a472017-11-14 14:53:06 -08002364 final int boundsChange = super.setBounds(bounds);
Chong Zhangf66db432016-01-13 10:39:51 -08002365
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002366 mRotation = rotation;
Robert Carrf59b8dd2017-10-02 18:58:36 -07002367
Evan Rosky89f5c1d2019-01-29 10:04:05 -08002368 updateSurfacePosition();
Wale Ogunwale2cc92f52015-09-09 13:12:10 -07002369 return boundsChange;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002370 }
2371
Garfield Tan90b04282018-12-11 14:04:42 -08002372 @Override
2373 public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
2374 ConfigurationContainer requestingContainer) {
2375 if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
2376 return true;
2377 }
2378
2379 // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
2380 // it if possible.
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002381 if (getParent() != null) {
2382 onConfigurationChanged(getParent().getConfiguration());
Garfield Tan90b04282018-12-11 14:04:42 -08002383 return true;
2384 }
2385 return false;
2386 }
2387
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002388 void resize(boolean relayout, boolean forced) {
2389 if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) {
2390 getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
2391 }
2392 }
2393
Louis Chang7501e332018-08-20 13:08:39 +08002394 @Override
2395 void onDisplayChanged(DisplayContent dc) {
Garfield Tan2f145f22018-11-01 15:27:03 -07002396 adjustBoundsForDisplayChangeIfNeeded(dc);
Louis Chang7501e332018-08-20 13:08:39 +08002397 super.onDisplayChanged(dc);
davidln1ceedb52019-05-30 14:25:01 -07002398 final int displayId = (dc != null) ? dc.getDisplayId() : Display.INVALID_DISPLAY;
2399 mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
2400 mTaskId, displayId);
Louis Chang7501e332018-08-20 13:08:39 +08002401 }
2402
Jorim Jaggidc249c42015-12-15 14:57:31 -08002403 /**
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002404 * Displayed bounds are used to set where the task is drawn at any given time. This is
2405 * separate from its actual bounds so that the app doesn't see any meaningful configuration
2406 * changes during transitionary periods.
Jorim Jaggidc249c42015-12-15 14:57:31 -08002407 */
Evan Roskyed6767f2018-10-26 17:21:06 -07002408 void setOverrideDisplayedBounds(Rect overrideDisplayedBounds) {
2409 if (overrideDisplayedBounds != null) {
2410 mOverrideDisplayedBounds.set(overrideDisplayedBounds);
Jorim Jaggidc249c42015-12-15 14:57:31 -08002411 } else {
Evan Roskyed6767f2018-10-26 17:21:06 -07002412 mOverrideDisplayedBounds.setEmpty();
Jorim Jaggidc249c42015-12-15 14:57:31 -08002413 }
Evan Rosky89f5c1d2019-01-29 10:04:05 -08002414 updateSurfacePosition();
Jorim Jaggidc249c42015-12-15 14:57:31 -08002415 }
2416
2417 /**
Evan Roskyed6767f2018-10-26 17:21:06 -07002418 * Gets the bounds that override where the task is displayed. See
Wale Ogunwale04d9cb52018-04-30 13:55:07 -07002419 * {@link android.app.IActivityTaskManager#resizeDockedStack} why this is needed.
Jorim Jaggidc249c42015-12-15 14:57:31 -08002420 */
Evan Roskyed6767f2018-10-26 17:21:06 -07002421 Rect getOverrideDisplayedBounds() {
2422 return mOverrideDisplayedBounds;
Jorim Jaggidc249c42015-12-15 14:57:31 -08002423 }
2424
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002425 boolean isResizeable(boolean checkSupportsPip) {
2426 return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
2427 || (checkSupportsPip && mSupportsPictureInPicture));
Chong Zhangb15758a2015-11-17 12:12:03 -08002428 }
2429
2430 boolean isResizeable() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002431 return isResizeable(true /* checkSupportsPip */);
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08002432 }
2433
skuhne@google.com322347b2016-12-02 12:54:03 -08002434 /**
2435 * Tests if the orientation should be preserved upon user interactive resizig operations.
2436
2437 * @return true if orientation should not get changed upon resizing operation.
2438 */
2439 boolean preserveOrientationOnResize() {
2440 return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY
2441 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY
2442 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
2443 }
2444
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08002445 boolean cropWindowsToStackBounds() {
Wale Ogunwaledf241e92016-10-13 15:14:21 -07002446 return isResizeable();
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08002447 }
2448
Jorim Jaggi0429f352015-12-22 16:29:16 +01002449 /**
2450 * Prepares the task bounds to be frozen with the current size. See
Garfield Tane8d84ab2019-10-11 09:49:40 -07002451 * {@link ActivityRecord#freezeBounds}.
Jorim Jaggi0429f352015-12-22 16:29:16 +01002452 */
2453 void prepareFreezingBounds() {
Bryce Leef3c6a472017-11-14 14:53:06 -08002454 mPreparedFrozenBounds.set(getBounds());
Andrii Kulian441e4492016-09-29 15:25:00 -07002455 mPreparedFrozenMergedConfig.setTo(getConfiguration());
Jorim Jaggi0429f352015-12-22 16:29:16 +01002456 }
2457
Chong Zhang5117e272016-05-03 12:47:34 -07002458 /**
2459 * Align the task to the adjusted bounds.
2460 *
2461 * @param adjustedBounds Adjusted bounds to which the task should be aligned.
2462 * @param tempInsetBounds Insets bounds for the task.
2463 * @param alignBottom True if the task's bottom should be aligned to the adjusted
2464 * bounds's bottom; false if the task's top should be aligned
2465 * the adjusted bounds's top.
2466 */
Andrii Kulian441e4492016-09-29 15:25:00 -07002467 void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
Evan Roskydfe3da72018-10-26 17:21:06 -07002468 if (!isResizeable() || EMPTY.equals(getRequestedOverrideConfiguration())) {
Chong Zhang5117e272016-05-03 12:47:34 -07002469 return;
2470 }
2471
2472 getBounds(mTmpRect2);
2473 if (alignBottom) {
2474 int offsetY = adjustedBounds.bottom - mTmpRect2.bottom;
2475 mTmpRect2.offset(0, offsetY);
2476 } else {
2477 mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
2478 }
Evan Roskyed6767f2018-10-26 17:21:06 -07002479 if (tempInsetBounds == null || tempInsetBounds.isEmpty()) {
2480 setOverrideDisplayedBounds(null);
2481 setBounds(mTmpRect2);
2482 } else {
2483 setOverrideDisplayedBounds(mTmpRect2);
2484 setBounds(tempInsetBounds);
2485 }
Chong Zhang5117e272016-05-03 12:47:34 -07002486 }
2487
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002488 /**
2489 * Gets the current overridden displayed bounds. These will be empty if the task is not
2490 * currently overriding where it is displayed.
2491 */
Evan Roskyed6767f2018-10-26 17:21:06 -07002492 @Override
2493 public Rect getDisplayedBounds() {
2494 if (mOverrideDisplayedBounds.isEmpty()) {
2495 return super.getDisplayedBounds();
2496 } else {
2497 return mOverrideDisplayedBounds;
2498 }
2499 }
2500
Issei Suzukiad287d02019-10-31 16:19:44 +01002501 @Override
2502 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
2503 Rect outSurfaceInsets) {
2504 final WindowState windowState = getTopVisibleAppMainWindow();
2505 if (windowState != null) {
2506 windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2507 } else {
2508 super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2509 }
2510 }
2511
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002512 /**
2513 * Calculate the maximum visible area of this task. If the task has only one app,
2514 * the result will be visible frame of that app. If the task has more than one apps,
2515 * we search from top down if the next app got different visible area.
2516 *
2517 * This effort is to handle the case where some task (eg. GMail composer) might pop up
2518 * a dialog that's different in size from the activity below, in which case we should
2519 * be dimming the entire task area behind the dialog.
2520 *
2521 * @param out Rect containing the max visible bounds.
2522 * @return true if the task has some visible app windows; false otherwise.
2523 */
chaviw553b0212018-07-12 13:37:01 -07002524 private boolean getMaxVisibleBounds(Rect out) {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002525 boolean foundTop = false;
Wale Ogunwalef6192862016-09-10 13:42:30 -07002526 for (int i = mChildren.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002527 final ActivityRecord token = mChildren.get(i);
Chong Zhangd8ceb852015-11-11 14:53:41 -08002528 // skip hidden (or about to hide) apps
Issei Suzukid4ee1cc2019-11-08 13:20:14 +01002529 if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) {
Chong Zhangd8ceb852015-11-11 14:53:41 -08002530 continue;
2531 }
2532 final WindowState win = token.findMainWindow();
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002533 if (win == null) {
2534 continue;
2535 }
2536 if (!foundTop) {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002537 foundTop = true;
chaviw553b0212018-07-12 13:37:01 -07002538 out.setEmpty();
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002539 }
chaviw553b0212018-07-12 13:37:01 -07002540
2541 win.getMaxVisibleBounds(out);
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002542 }
2543 return foundTop;
2544 }
2545
2546 /** Bounds of the task to be used for dimming, as well as touch related tests. */
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002547 public void getDimBounds(Rect out) {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002548 final DisplayContent displayContent = getTaskStack().getDisplayContent();
Robert Carra86a6bf2016-04-08 17:34:16 -07002549 // It doesn't matter if we in particular are part of the resize, since we couldn't have
2550 // a DimLayer anyway if we weren't visible.
Wale Ogunwalef6192862016-09-10 13:42:30 -07002551 final boolean dockedResizing = displayContent != null
2552 && displayContent.mDividerControllerLocked.isResizing();
Evan Rosky4fb1e912019-03-06 13:54:43 -08002553 if (inFreeformWindowingMode() && getMaxVisibleBounds(out)) {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002554 return;
2555 }
2556
Evan Rosky4fb1e912019-03-06 13:54:43 -08002557 if (!matchParentBounds()) {
2558 // When minimizing the docked stack when going home, we don't adjust the task bounds
2559 // so we need to intersect the task bounds with the stack bounds here.
2560 //
2561 // If we are Docked Resizing with snap points, the task bounds could be smaller than the
2562 // stack bounds and so we don't even want to use them. Even if the app should not be
2563 // resized the Dim should keep up with the divider.
2564 if (dockedResizing) {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002565 getTaskStack().getBounds(out);
Evan Rosky4fb1e912019-03-06 13:54:43 -08002566 } else {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002567 getTaskStack().getBounds(mTmpRect);
Evan Rosky4fb1e912019-03-06 13:54:43 -08002568 mTmpRect.intersect(getBounds());
2569 out.set(mTmpRect);
2570 }
2571 } else {
2572 out.set(getBounds());
Wale Ogunwalef6192862016-09-10 13:42:30 -07002573 }
Evan Rosky4fb1e912019-03-06 13:54:43 -08002574 return;
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002575 }
2576
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002577 void setDragResizing(boolean dragResizing, int dragResizeMode) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -08002578 if (mDragResizing != dragResizing) {
chaviw8c9d1f52018-07-25 14:56:07 -07002579 // No need to check if the mode is allowed if it's leaving dragResize
Wale Ogunwale8577a052019-10-26 23:22:34 -07002580 if (dragResizing && !DragResizeMode.isModeAllowedForStack(getTaskStack(), dragResizeMode)) {
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002581 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
Wale Ogunwale8577a052019-10-26 23:22:34 -07002582 + getTaskStack().mStackId + " dragResizeMode=" + dragResizeMode);
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002583 }
Jorim Jaggic662d8e2016-02-05 16:54:54 -08002584 mDragResizing = dragResizing;
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002585 mDragResizeMode = dragResizeMode;
Jorim Jaggic662d8e2016-02-05 16:54:54 -08002586 resetDragResizingChangeReported();
2587 }
2588 }
2589
Chong Zhang3005e752015-09-18 18:46:28 -07002590 boolean isDragResizing() {
Wale Ogunwaled1c37912016-08-16 03:19:39 -07002591 return mDragResizing;
Chong Zhang3005e752015-09-18 18:46:28 -07002592 }
2593
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002594 int getDragResizeMode() {
2595 return mDragResizeMode;
2596 }
2597
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002598 /**
2599 * Puts this task into docked drag resizing mode. See {@link DragResizeMode}.
2600 *
2601 * @param resizing Whether to put the task into drag resize mode.
2602 */
2603 public void setTaskDockedResizing(boolean resizing) {
2604 setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
2605 }
2606
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002607 void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002608 if (displayContent == null) {
2609 return;
2610 }
Bryce Leef3c6a472017-11-14 14:53:06 -08002611 if (matchParentBounds()) {
Wale Ogunwale68278562017-09-23 17:13:55 -07002612 // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a
2613 // problem once we move mBounds into WindowConfiguration.
Bryce Leef3c6a472017-11-14 14:53:06 -08002614 setBounds(null);
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002615 return;
2616 }
Garfield Tandec96db2018-10-30 11:28:49 -07002617 final int displayId = displayContent.getDisplayId();
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002618 final int newRotation = displayContent.getDisplayInfo().rotation;
Garfield Tandec96db2018-10-30 11:28:49 -07002619 if (displayId != mLastRotationDisplayId) {
2620 // This task is on a display that it wasn't on. There is no point to keep the relative
2621 // position if display rotations for old and new displays are different. Just keep these
2622 // values.
2623 mLastRotationDisplayId = displayId;
2624 mRotation = newRotation;
2625 return;
2626 }
2627
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002628 if (mRotation == newRotation) {
Garfield Tandec96db2018-10-30 11:28:49 -07002629 // Rotation didn't change. We don't need to adjust the bounds to keep the relative
2630 // position.
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002631 return;
2632 }
2633
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002634 // Device rotation changed.
Chong Zhang2e2c81a2016-07-15 11:28:17 -07002635 // - We don't want the task to move around on the screen when this happens, so update the
2636 // task bounds so it stays in the same place.
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002637 // - Rotate the bounds and notify activity manager if the task can be resized independently
Chong Zhang2e2c81a2016-07-15 11:28:17 -07002638 // from its stack. The stack will take care of task rotation for the other case.
Bryce Leef3c6a472017-11-14 14:53:06 -08002639 mTmpRect2.set(getBounds());
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002640
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002641 if (!getWindowConfiguration().canResizeTask()) {
Bryce Leef3c6a472017-11-14 14:53:06 -08002642 setBounds(mTmpRect2);
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002643 return;
2644 }
2645
Wale Ogunwale94744212015-09-21 19:01:47 -07002646 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
Bryce Leef3c6a472017-11-14 14:53:06 -08002647 if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002648 mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
Wale Ogunwale1ed0d892015-09-28 13:27:44 -07002649 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002650 }
2651
Wale Ogunwalef6192862016-09-10 13:42:30 -07002652 /** Cancels any running app transitions associated with the task. */
Winsonc28098f2015-10-30 14:50:19 -07002653 void cancelTaskWindowTransition() {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002654 for (int i = mChildren.size() - 1; i >= 0; --i) {
Jorim Jaggif5f9e122017-10-24 18:21:09 +02002655 mChildren.get(i).cancelAnimation();
Winsonc28098f2015-10-30 14:50:19 -07002656 }
2657 }
2658
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -07002659 boolean showForAllUsers() {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002660 final int tokensCount = mChildren.size();
Wale Ogunwale72919d22016-12-08 18:58:50 -08002661 return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers;
Jorim Jaggiff71d202016-04-14 13:12:36 -07002662 }
2663
Robert Carr7e4c90e2017-02-15 19:52:38 -08002664 /**
2665 * When we are in a floating stack (Freeform, Pinned, ...) we calculate
2666 * insets differently. However if we are animating to the fullscreen stack
2667 * we need to begin calculating insets as if we were fullscreen, otherwise
2668 * we will have a jump at the end.
2669 */
Robert Carre6275582016-02-29 15:45:45 -08002670 boolean isFloating() {
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002671 return getWindowConfiguration().tasksAreFloating()
Wale Ogunwale8577a052019-10-26 23:22:34 -07002672 && !getTaskStack().isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
Robert Carre6275582016-02-29 15:45:45 -08002673 }
2674
Winson Chungd41f71d2018-03-16 15:26:07 -07002675 @Override
2676 public SurfaceControl getAnimationLeashParent() {
Riddle Hsud8302832019-09-23 21:14:07 +08002677 if (WindowManagerService.sHierarchicalAnimations) {
Issei Suzuki71142152019-08-15 14:39:40 +02002678 return super.getAnimationLeashParent();
2679 }
Winson Chung732446a2018-09-19 13:15:17 -07002680 // Currently, only the recents animation will create animation leashes for tasks. In this
2681 // case, reparent the task to the home animation layer while it is being animated to allow
2682 // the home activity to reorder the app windows relative to its own.
2683 return getAppAnimationLayer(ANIMATION_LAYER_HOME);
Winson Chungd41f71d2018-03-16 15:26:07 -07002684 }
2685
lumark19a5d2e2019-10-11 16:19:30 +08002686 boolean shouldAnimate() {
2687 // Don't animate while the task runs recents animation but only if we are in the mode
2688 // where we cancel with deferred screenshot, which means that the controller has
2689 // transformed the task.
2690 final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
2691 if (controller != null && controller.isAnimatingTask(this)
2692 && controller.shouldDeferCancelUntilNextTransition()) {
2693 return false;
2694 }
2695 return true;
2696 }
2697
Evan Rosky9020c072018-12-06 14:11:12 -08002698 @Override
2699 SurfaceControl.Builder makeSurface() {
2700 return super.makeSurface().setMetadata(METADATA_TASK_ID, mTaskId);
2701 }
2702
Winson Chungd41f71d2018-03-16 15:26:07 -07002703 boolean isTaskAnimating() {
Wale Ogunwale8b19de92018-11-29 19:58:26 -08002704 final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController();
Winson Chungd41f71d2018-03-16 15:26:07 -07002705 if (recentsAnim != null) {
2706 if (recentsAnim.isAnimatingTask(this)) {
2707 return true;
2708 }
2709 }
2710 return false;
2711 }
2712
lumark19a5d2e2019-10-11 16:19:30 +08002713 /**
2714 * @return {@code true} if changing app transition is running.
2715 */
2716 @Override
2717 boolean isChangingAppTransition() {
2718 final ActivityRecord activity = getTopVisibleActivity();
2719 return activity != null && getDisplayContent().mChangingApps.contains(activity);
2720 }
2721
2722 @Override
2723 RemoteAnimationTarget createRemoteAnimationTarget(
2724 RemoteAnimationController.RemoteAnimationRecord record) {
2725 final ActivityRecord activity = getTopVisibleActivity();
2726 return activity != null ? activity.createRemoteAnimationTarget(record) : null;
2727 }
2728
Chong Zhangd8ceb852015-11-11 14:53:41 -08002729 WindowState getTopVisibleAppMainWindow() {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002730 final ActivityRecord activity = getTopVisibleActivity();
2731 return activity != null ? activity.findMainWindow() : null;
Chong Zhang9184ec62015-09-24 12:32:21 -07002732 }
2733
Garfield Tane8d84ab2019-10-11 09:49:40 -07002734 ActivityRecord getTopFullscreenActivity() {
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +02002735 for (int i = mChildren.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002736 final ActivityRecord activity = mChildren.get(i);
2737 final WindowState win = activity.findMainWindow();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +02002738 if (win != null && win.mAttrs.isFullscreen()) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002739 return activity;
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +02002740 }
2741 }
2742 return null;
2743 }
2744
Garfield Tane8d84ab2019-10-11 09:49:40 -07002745 ActivityRecord getTopVisibleActivity() {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002746 for (int i = mChildren.size() - 1; i >= 0; i--) {
Issei Suzukid4ee1cc2019-11-08 13:20:14 +01002747 final ActivityRecord activity = mChildren.get(i);
2748 if (!activity.mIsExiting && activity.isClientVisible() && activity.mVisibleRequested) {
2749 return activity;
Chong Zhangd8ceb852015-11-11 14:53:41 -08002750 }
2751 }
2752 return null;
Chong Zhangbef461f2015-10-27 11:38:24 -07002753 }
2754
Wale Ogunwale3198da42019-10-10 14:45:03 +02002755 void positionChildAtTop(ActivityRecord child) {
2756 positionChildAt(child, POSITION_TOP);
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002757 }
2758
Wale Ogunwale3198da42019-10-10 14:45:03 +02002759 void positionChildAt(ActivityRecord child, int position) {
2760 if (child == null) {
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002761 Slog.w(TAG_WM,
2762 "Attempted to position of non-existing app");
2763 return;
2764 }
2765
Wale Ogunwale3198da42019-10-10 14:45:03 +02002766 positionChildAt(position, child, false /* includeParents */);
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002767 }
2768
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002769 void forceWindowsScaleable(boolean force) {
Wale Ogunwale8b19de92018-11-29 19:58:26 -08002770 mWmService.openSurfaceTransaction();
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002771 try {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002772 for (int i = mChildren.size() - 1; i >= 0; i--) {
2773 mChildren.get(i).forceWindowsScaleableInTransaction(force);
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002774 }
2775 } finally {
Wale Ogunwale8b19de92018-11-29 19:58:26 -08002776 mWmService.closeSurfaceTransaction("forceWindowsScaleable");
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002777 }
2778 }
2779
Jorim Jaggi829b9cd2017-01-23 16:20:53 +01002780 void setTaskDescription(TaskDescription taskDescription) {
2781 mTaskDescription = taskDescription;
2782 }
2783
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002784 void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002785 mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
2786 mTaskId, snapshot);
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002787 }
2788
Jorim Jaggi829b9cd2017-01-23 16:20:53 +01002789 TaskDescription getTaskDescription() {
2790 return mTaskDescription;
2791 }
2792
Wale Ogunwalef6192862016-09-10 13:42:30 -07002793 @Override
Wale Ogunwale51362492016-09-08 17:49:17 -07002794 boolean fillsParent() {
Bryce Leef3c6a472017-11-14 14:53:06 -08002795 return matchParentBounds() || !getWindowConfiguration().canResizeTask();
Wale Ogunwale51362492016-09-08 17:49:17 -07002796 }
2797
Jorim Jaggi329a5832017-01-05 18:57:12 +01002798 @Override
Jorim Jaggi51304d72017-05-17 17:25:32 +02002799 void forAllTasks(Consumer<Task> callback) {
2800 callback.accept(this);
2801 }
2802
lumarkbc0032a2019-11-01 21:38:13 +08002803 @Override
2804 boolean forAllTasks(ToBooleanFunction<Task> callback) {
2805 return callback.apply(this);
2806 }
2807
Jorim Jaggi50bf59c2018-03-09 17:29:48 +01002808 /**
2809 * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI
2810 * flags. See {@link WindowState#canAffectSystemUiFlags()}.
2811 */
2812 void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) {
2813 mCanAffectSystemUiFlags = canAffectSystemUiFlags;
2814 }
2815
2816 /**
2817 * @see #setCanAffectSystemUiFlags
2818 */
2819 boolean canAffectSystemUiFlags() {
2820 return mCanAffectSystemUiFlags;
2821 }
2822
chaviw87ca63a2018-03-26 14:06:17 -07002823 void dontAnimateDimExit() {
2824 mDimmer.dontAnimateExit();
2825 }
2826
Wale Ogunwale9adfe572016-09-08 20:43:58 -07002827 String getName() {
Louis Changcdec0802019-11-11 11:45:07 +08002828 return "Task=" + mTaskId;
Wale Ogunwale9adfe572016-09-08 20:43:58 -07002829 }
2830
Robert Carr18f622f2017-05-08 11:20:43 -07002831 void clearPreserveNonFloatingState() {
2832 mPreserveNonFloatingState = false;
2833 }
2834
chaviw2fb06bc2018-01-19 17:09:15 -08002835 @Override
Robert Carrf59b8dd2017-10-02 18:58:36 -07002836 Dimmer getDimmer() {
2837 return mDimmer;
2838 }
2839
Filip Gruszczynski0689ae92015-10-01 12:30:31 -07002840 @Override
Robert Carrf59b8dd2017-10-02 18:58:36 -07002841 void prepareSurfaces() {
2842 mDimmer.resetDimStates();
2843 super.prepareSurfaces();
2844 getDimBounds(mTmpDimBoundsRect);
chaviwe07246a2017-12-12 16:18:29 -08002845
2846 // Bounds need to be relative, as the dim layer is a child.
2847 mTmpDimBoundsRect.offsetTo(0, 0);
Robert Carrf59b8dd2017-10-02 18:58:36 -07002848 if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
2849 scheduleAnimation();
2850 }
Filip Gruszczynski0689ae92015-10-01 12:30:31 -07002851 }
2852
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002853 // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged.
2854 void writeToProtoInnerTaskOnly(ProtoOutputStream proto, long fieldId,
Nataniel Borges023ecb52019-01-16 14:15:43 -08002855 @WindowTraceLogLevel int logLevel) {
2856 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
2857 return;
2858 }
2859
Steven Timotiusaf03df62017-07-18 16:56:43 -07002860 final long token = proto.start(fieldId);
Nataniel Borges023ecb52019-01-16 14:15:43 -08002861 super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
Louis Changcdec0802019-11-11 11:45:07 +08002862 proto.write(TaskProto.ID, mTaskId);
Steven Timotiusaf03df62017-07-18 16:56:43 -07002863 for (int i = mChildren.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002864 final ActivityRecord activity = mChildren.get(i);
2865 activity.writeToProto(proto, APP_WINDOW_TOKENS, logLevel);
Steven Timotiusaf03df62017-07-18 16:56:43 -07002866 }
Bryce Leef3c6a472017-11-14 14:53:06 -08002867 proto.write(FILLS_PARENT, matchParentBounds());
Louis Changcdec0802019-11-11 11:45:07 +08002868 getBounds().writeToProto(proto, TaskProto.BOUNDS);
Evan Roskyed6767f2018-10-26 17:21:06 -07002869 mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS);
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002870 if (mSurfaceControl != null) {
2871 proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
2872 proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
2873 }
Steven Timotiusaf03df62017-07-18 16:56:43 -07002874 proto.end(token);
2875 }
2876
Jorim Jaggif5f9e122017-10-24 18:21:09 +02002877 @Override
2878 public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
2879 super.dump(pw, prefix, dumpAll);
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002880 final String doublePrefix = prefix + " ";
2881
2882 pw.println(prefix + "taskId=" + mTaskId);
Bryce Leef3c6a472017-11-14 14:53:06 -08002883 pw.println(doublePrefix + "mBounds=" + getBounds().toShortString());
Wale Ogunwalef6192862016-09-10 13:42:30 -07002884 pw.println(doublePrefix + "appTokens=" + mChildren);
Evan Roskyed6767f2018-10-26 17:21:06 -07002885 pw.println(doublePrefix + "mDisplayedBounds=" + mOverrideDisplayedBounds.toShortString());
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002886
2887 final String triplePrefix = doublePrefix + " ";
Jorim Jaggi153dc9d2018-02-23 13:28:15 +01002888 final String quadruplePrefix = triplePrefix + " ";
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002889
Wale Ogunwalef6192862016-09-10 13:42:30 -07002890 for (int i = mChildren.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002891 final ActivityRecord activity = mChildren.get(i);
2892 pw.println(triplePrefix + "Activity #" + i + " " + activity);
2893 activity.dump(pw, quadruplePrefix, dumpAll);
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002894 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002895 }
Robert Carrf59b8dd2017-10-02 18:58:36 -07002896
Louis Changcdec0802019-11-11 11:45:07 +08002897 /**
2898 * Fills in a {@link TaskInfo} with information from this task.
2899 * @param info the {@link TaskInfo} to fill in
2900 */
2901 void fillTaskInfo(TaskInfo info) {
2902 getNumRunningActivities(mReuseActivitiesReport);
2903 info.userId = mUserId;
2904 info.stackId = getStackId();
2905 info.taskId = mTaskId;
2906 info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
Wale Ogunwale21e06482019-11-18 05:14:15 -08002907 info.isRunning = getTopNonFinishingActivity() != null;
Louis Changcdec0802019-11-11 11:45:07 +08002908 info.baseIntent = new Intent(getBaseIntent());
2909 info.baseActivity = mReuseActivitiesReport.base != null
2910 ? mReuseActivitiesReport.base.intent.getComponent()
2911 : null;
2912 info.topActivity = mReuseActivitiesReport.top != null
2913 ? mReuseActivitiesReport.top.mActivityComponent
2914 : null;
2915 info.origActivity = origActivity;
2916 info.realActivity = realActivity;
2917 info.numActivities = mReuseActivitiesReport.numActivities;
2918 info.lastActiveTime = lastActiveTime;
2919 info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
2920 info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
2921 info.resizeMode = mResizeMode;
2922 info.configuration.setTo(getConfiguration());
2923 }
2924
2925 /**
2926 * Returns a {@link TaskInfo} with information from this task.
2927 */
2928 ActivityManager.RunningTaskInfo getTaskInfo() {
2929 ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
2930 fillTaskInfo(info);
2931 return info;
2932 }
2933
2934 void dump(PrintWriter pw, String prefix) {
2935 pw.print(prefix); pw.print("userId="); pw.print(mUserId);
2936 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
2937 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
2938 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
2939 pw.print(" mCallingPackage="); pw.println(mCallingPackage);
2940 if (affinity != null || rootAffinity != null) {
2941 pw.print(prefix); pw.print("affinity="); pw.print(affinity);
2942 if (affinity == null || !affinity.equals(rootAffinity)) {
2943 pw.print(" root="); pw.println(rootAffinity);
2944 } else {
2945 pw.println();
2946 }
2947 }
2948 if (voiceSession != null || voiceInteractor != null) {
2949 pw.print(prefix); pw.print("VOICE: session=0x");
2950 pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
2951 pw.print(" interactor=0x");
2952 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
2953 }
2954 if (intent != null) {
2955 StringBuilder sb = new StringBuilder(128);
2956 sb.append(prefix); sb.append("intent={");
2957 intent.toShortString(sb, false, true, false, false);
2958 sb.append('}');
2959 pw.println(sb.toString());
2960 }
2961 if (affinityIntent != null) {
2962 StringBuilder sb = new StringBuilder(128);
2963 sb.append(prefix); sb.append("affinityIntent={");
2964 affinityIntent.toShortString(sb, false, true, false, false);
2965 sb.append('}');
2966 pw.println(sb.toString());
2967 }
2968 if (origActivity != null) {
2969 pw.print(prefix); pw.print("origActivity=");
2970 pw.println(origActivity.flattenToShortString());
2971 }
2972 if (realActivity != null) {
2973 pw.print(prefix); pw.print("mActivityComponent=");
2974 pw.println(realActivity.flattenToShortString());
2975 }
Wale Ogunwale7a8889a2019-11-16 08:23:42 -08002976 if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) {
Louis Changcdec0802019-11-11 11:45:07 +08002977 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
2978 pw.print(" isPersistable="); pw.print(isPersistable);
Louis Changcdec0802019-11-11 11:45:07 +08002979 pw.print(" activityType="); pw.println(getActivityType());
2980 }
2981 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
2982 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
2983 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
2984 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
2985 pw.print(" mReuseTask="); pw.print(mReuseTask);
2986 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
2987 }
2988 if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
2989 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
2990 || mNextAffiliate != null) {
2991 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
2992 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
2993 pw.print(" (");
2994 if (mPrevAffiliate == null) {
2995 pw.print("null");
2996 } else {
2997 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
2998 }
2999 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
3000 pw.print(" (");
3001 if (mNextAffiliate == null) {
3002 pw.print("null");
3003 } else {
3004 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
3005 }
3006 pw.println(")");
3007 }
3008 pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
3009 if (!askedCompatMode || !inRecents || !isAvailable) {
3010 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
3011 pw.print(" inRecents="); pw.print(inRecents);
3012 pw.print(" isAvailable="); pw.println(isAvailable);
3013 }
3014 if (lastDescription != null) {
3015 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
3016 }
3017 if (mRootProcess != null) {
3018 pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
3019 }
3020 pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
3021 pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
3022 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
3023 pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
3024 pw.print(" isResizeable=" + isResizeable());
3025 pw.print(" lastActiveTime=" + lastActiveTime);
3026 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
3027 }
3028
3029 @Override
3030 public String toString() {
3031 StringBuilder sb = new StringBuilder(128);
3032 if (stringName != null) {
3033 sb.append(stringName);
3034 sb.append(" U=");
3035 sb.append(mUserId);
3036 sb.append(" StackId=");
3037 sb.append(getStackId());
3038 sb.append(" sz=");
3039 sb.append(getChildCount());
3040 sb.append('}');
3041 return sb.toString();
3042 }
3043 sb.append("Task{");
3044 sb.append(Integer.toHexString(System.identityHashCode(this)));
3045 sb.append(" #");
3046 sb.append(mTaskId);
3047 if (affinity != null) {
3048 sb.append(" A=");
3049 sb.append(affinity);
3050 } else if (intent != null) {
3051 sb.append(" I=");
3052 sb.append(intent.getComponent().flattenToShortString());
3053 } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
3054 sb.append(" aI=");
3055 sb.append(affinityIntent.getComponent().flattenToShortString());
3056 } else {
3057 sb.append(" ??");
3058 }
3059 stringName = sb.toString();
3060 return toString();
3061 }
3062
3063 @Override
3064 public void writeToProto(ProtoOutputStream proto, long fieldId,
3065 @WindowTraceLogLevel int logLevel) {
3066 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
3067 return;
3068 }
3069
3070 final long token = proto.start(fieldId);
3071 writeToProtoInnerTaskOnly(proto, TASK, logLevel);
3072 proto.write(com.android.server.am.TaskRecordProto.ID, mTaskId);
3073 for (int i = getChildCount() - 1; i >= 0; i--) {
3074 final ActivityRecord activity = getChildAt(i);
3075 activity.writeToProto(proto, ACTIVITIES);
3076 }
3077 proto.write(STACK_ID, getStackId());
3078 if (mLastNonFullscreenBounds != null) {
3079 mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
3080 }
3081 if (realActivity != null) {
3082 proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
3083 }
3084 if (origActivity != null) {
3085 proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
3086 }
3087 proto.write(ACTIVITY_TYPE, getActivityType());
3088 proto.write(RESIZE_MODE, mResizeMode);
3089 // TODO: Remove, no longer needed with windowingMode.
3090 proto.write(FULLSCREEN, matchParentBounds());
3091
3092 if (!matchParentBounds()) {
3093 final Rect bounds = getRequestedOverrideBounds();
3094 bounds.writeToProto(proto, com.android.server.am.TaskRecordProto.BOUNDS);
3095 }
3096 proto.write(MIN_WIDTH, mMinWidth);
3097 proto.write(MIN_HEIGHT, mMinHeight);
3098 proto.end(token);
3099 }
3100
3101 /** @see #getNumRunningActivities(TaskActivitiesReport) */
3102 static class TaskActivitiesReport {
3103 int numRunning;
3104 int numActivities;
3105 ActivityRecord top;
3106 ActivityRecord base;
3107
3108 void reset() {
3109 numRunning = numActivities = 0;
3110 top = base = null;
3111 }
3112 }
3113
3114 /**
3115 * Saves this {@link Task} to XML using given serializer.
3116 */
3117 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
3118 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
3119
3120 out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
3121 if (realActivity != null) {
3122 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
3123 }
3124 out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
3125 if (origActivity != null) {
3126 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
3127 }
3128 // Write affinity, and root affinity if it is different from affinity.
3129 // We use the special string "@" for a null root affinity, so we can identify
3130 // later whether we were given a root affinity or should just make it the
3131 // same as the affinity.
3132 if (affinity != null) {
3133 out.attribute(null, ATTR_AFFINITY, affinity);
3134 if (!affinity.equals(rootAffinity)) {
3135 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
3136 }
3137 } else if (rootAffinity != null) {
3138 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
3139 }
3140 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
3141 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
3142 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
3143 out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
3144 out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
3145 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
3146 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
3147 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
3148 if (lastDescription != null) {
3149 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
3150 }
3151 if (getTaskDescription() != null) {
3152 getTaskDescription().saveToXml(out);
3153 }
3154 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
3155 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
3156 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
3157 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
3158 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
3159 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
3160 out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
3161 out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
3162 String.valueOf(mSupportsPictureInPicture));
3163 if (mLastNonFullscreenBounds != null) {
3164 out.attribute(
3165 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
3166 }
3167 out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
3168 out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
3169 out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
3170
3171 if (affinityIntent != null) {
3172 out.startTag(null, TAG_AFFINITYINTENT);
3173 affinityIntent.saveToXml(out);
3174 out.endTag(null, TAG_AFFINITYINTENT);
3175 }
3176
3177 if (intent != null) {
3178 out.startTag(null, TAG_INTENT);
3179 intent.saveToXml(out);
3180 out.endTag(null, TAG_INTENT);
3181 }
3182
3183 final int numActivities = getChildCount();
3184 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
3185 final ActivityRecord r = getChildAt(activityNdx);
3186 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
3187 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
3188 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
3189 && activityNdx > 0) {
3190 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
3191 break;
3192 }
3193 out.startTag(null, TAG_ACTIVITY);
3194 r.saveToXml(out);
3195 out.endTag(null, TAG_ACTIVITY);
3196 }
3197 }
3198
3199 @VisibleForTesting
3200 static TaskFactory getTaskFactory() {
3201 if (sTaskFactory == null) {
3202 setTaskFactory(new TaskFactory());
3203 }
3204 return sTaskFactory;
3205 }
3206
3207 static void setTaskFactory(TaskFactory factory) {
3208 sTaskFactory = factory;
3209 }
3210
3211 static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3212 Intent intent, IVoiceInteractionSession voiceSession,
3213 IVoiceInteractor voiceInteractor, ActivityStack stack) {
3214 return getTaskFactory().create(
3215 service, taskId, info, intent, voiceSession, voiceInteractor, stack);
3216 }
3217
3218 static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3219 Intent intent, TaskDescription taskDescription, ActivityStack stack) {
3220 return getTaskFactory().create(service, taskId, info, intent, taskDescription, stack);
3221 }
3222
3223 static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
3224 throws IOException, XmlPullParserException {
3225 return getTaskFactory().restoreFromXml(in, stackSupervisor);
3226 }
3227
3228 /**
3229 * A factory class used to create {@link Task} or its subclass if any. This can be
3230 * specified when system boots by setting it with
3231 * {@link #setTaskFactory(TaskFactory)}.
3232 */
3233 static class TaskFactory {
3234
3235 Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3236 Intent intent, IVoiceInteractionSession voiceSession,
3237 IVoiceInteractor voiceInteractor, ActivityStack stack) {
3238 return new Task(service, taskId, info, intent, voiceSession, voiceInteractor,
3239 null /*taskDescription*/, stack);
3240 }
3241
3242 Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3243 Intent intent, TaskDescription taskDescription, ActivityStack stack) {
3244 return new Task(service, taskId, info, intent, null /*voiceSession*/,
3245 null /*voiceInteractor*/, taskDescription, stack);
3246 }
3247
3248 /**
3249 * Should only be used when we're restoring {@link Task} from storage.
3250 */
3251 Task create(ActivityTaskManagerService service, int taskId, Intent intent,
3252 Intent affinityIntent, String affinity, String rootAffinity,
3253 ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
3254 boolean autoRemoveRecents, boolean askedCompatMode, int userId,
3255 int effectiveUid, String lastDescription,
3256 long lastTimeMoved, boolean neverRelinquishIdentity,
3257 TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
3258 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
3259 int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
3260 boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
3261 return new Task(service, taskId, intent, affinityIntent, affinity,
3262 rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
3263 askedCompatMode, userId, effectiveUid, lastDescription,
3264 lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
3265 prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
3266 resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
3267 minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
3268 null /*_voiceInteractor*/, stack);
3269 }
3270
3271 Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
3272 throws IOException, XmlPullParserException {
3273 Intent intent = null;
3274 Intent affinityIntent = null;
3275 ArrayList<ActivityRecord> activities = new ArrayList<>();
3276 ComponentName realActivity = null;
3277 boolean realActivitySuspended = false;
3278 ComponentName origActivity = null;
3279 String affinity = null;
3280 String rootAffinity = null;
3281 boolean hasRootAffinity = false;
3282 boolean rootHasReset = false;
3283 boolean autoRemoveRecents = false;
3284 boolean askedCompatMode = false;
3285 int taskType = 0;
3286 int userId = 0;
3287 boolean userSetupComplete = true;
3288 int effectiveUid = -1;
3289 String lastDescription = null;
3290 long lastTimeOnTop = 0;
3291 boolean neverRelinquishIdentity = true;
3292 int taskId = INVALID_TASK_ID;
3293 final int outerDepth = in.getDepth();
3294 TaskDescription taskDescription = new TaskDescription();
3295 int taskAffiliation = INVALID_TASK_ID;
3296 int taskAffiliationColor = 0;
3297 int prevTaskId = INVALID_TASK_ID;
3298 int nextTaskId = INVALID_TASK_ID;
3299 int callingUid = -1;
3300 String callingPackage = "";
3301 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
3302 boolean supportsPictureInPicture = false;
3303 Rect lastNonFullscreenBounds = null;
3304 int minWidth = INVALID_MIN_SIZE;
3305 int minHeight = INVALID_MIN_SIZE;
3306 int persistTaskVersion = 0;
3307
3308 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
3309 final String attrName = in.getAttributeName(attrNdx);
3310 final String attrValue = in.getAttributeValue(attrNdx);
3311 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: attribute name="
3312 + attrName + " value=" + attrValue);
3313 switch (attrName) {
3314 case ATTR_TASKID:
3315 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
3316 break;
3317 case ATTR_REALACTIVITY:
3318 realActivity = ComponentName.unflattenFromString(attrValue);
3319 break;
3320 case ATTR_REALACTIVITY_SUSPENDED:
3321 realActivitySuspended = Boolean.valueOf(attrValue);
3322 break;
3323 case ATTR_ORIGACTIVITY:
3324 origActivity = ComponentName.unflattenFromString(attrValue);
3325 break;
3326 case ATTR_AFFINITY:
3327 affinity = attrValue;
3328 break;
3329 case ATTR_ROOT_AFFINITY:
3330 rootAffinity = attrValue;
3331 hasRootAffinity = true;
3332 break;
3333 case ATTR_ROOTHASRESET:
3334 rootHasReset = Boolean.parseBoolean(attrValue);
3335 break;
3336 case ATTR_AUTOREMOVERECENTS:
3337 autoRemoveRecents = Boolean.parseBoolean(attrValue);
3338 break;
3339 case ATTR_ASKEDCOMPATMODE:
3340 askedCompatMode = Boolean.parseBoolean(attrValue);
3341 break;
3342 case ATTR_USERID:
3343 userId = Integer.parseInt(attrValue);
3344 break;
3345 case ATTR_USER_SETUP_COMPLETE:
3346 userSetupComplete = Boolean.parseBoolean(attrValue);
3347 break;
3348 case ATTR_EFFECTIVE_UID:
3349 effectiveUid = Integer.parseInt(attrValue);
3350 break;
3351 case ATTR_TASKTYPE:
3352 taskType = Integer.parseInt(attrValue);
3353 break;
3354 case ATTR_LASTDESCRIPTION:
3355 lastDescription = attrValue;
3356 break;
3357 case ATTR_LASTTIMEMOVED:
3358 lastTimeOnTop = Long.parseLong(attrValue);
3359 break;
3360 case ATTR_NEVERRELINQUISH:
3361 neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
3362 break;
3363 case ATTR_TASK_AFFILIATION:
3364 taskAffiliation = Integer.parseInt(attrValue);
3365 break;
3366 case ATTR_PREV_AFFILIATION:
3367 prevTaskId = Integer.parseInt(attrValue);
3368 break;
3369 case ATTR_NEXT_AFFILIATION:
3370 nextTaskId = Integer.parseInt(attrValue);
3371 break;
3372 case ATTR_TASK_AFFILIATION_COLOR:
3373 taskAffiliationColor = Integer.parseInt(attrValue);
3374 break;
3375 case ATTR_CALLING_UID:
3376 callingUid = Integer.parseInt(attrValue);
3377 break;
3378 case ATTR_CALLING_PACKAGE:
3379 callingPackage = attrValue;
3380 break;
3381 case ATTR_RESIZE_MODE:
3382 resizeMode = Integer.parseInt(attrValue);
3383 break;
3384 case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
3385 supportsPictureInPicture = Boolean.parseBoolean(attrValue);
3386 break;
3387 case ATTR_NON_FULLSCREEN_BOUNDS:
3388 lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
3389 break;
3390 case ATTR_MIN_WIDTH:
3391 minWidth = Integer.parseInt(attrValue);
3392 break;
3393 case ATTR_MIN_HEIGHT:
3394 minHeight = Integer.parseInt(attrValue);
3395 break;
3396 case ATTR_PERSIST_TASK_VERSION:
3397 persistTaskVersion = Integer.parseInt(attrValue);
3398 break;
3399 default:
3400 if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
3401 taskDescription.restoreFromXml(attrName, attrValue);
3402 } else {
3403 Slog.w(TAG, "Task: Unknown attribute=" + attrName);
3404 }
3405 }
3406 }
3407
3408 int event;
3409 while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
3410 && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
3411 if (event == XmlPullParser.START_TAG) {
3412 final String name = in.getName();
3413 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
3414 "Task: START_TAG name=" + name);
3415 if (TAG_AFFINITYINTENT.equals(name)) {
3416 affinityIntent = Intent.restoreFromXml(in);
3417 } else if (TAG_INTENT.equals(name)) {
3418 intent = Intent.restoreFromXml(in);
3419 } else if (TAG_ACTIVITY.equals(name)) {
3420 ActivityRecord activity =
3421 ActivityRecord.restoreFromXml(in, stackSupervisor);
3422 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: activity="
3423 + activity);
3424 if (activity != null) {
3425 activities.add(activity);
3426 }
3427 } else {
3428 handleUnknownTag(name, in);
3429 }
3430 }
3431 }
3432 if (!hasRootAffinity) {
3433 rootAffinity = affinity;
3434 } else if ("@".equals(rootAffinity)) {
3435 rootAffinity = null;
3436 }
3437 if (effectiveUid <= 0) {
3438 Intent checkIntent = intent != null ? intent : affinityIntent;
3439 effectiveUid = 0;
3440 if (checkIntent != null) {
3441 IPackageManager pm = AppGlobals.getPackageManager();
3442 try {
3443 ApplicationInfo ai = pm.getApplicationInfo(
3444 checkIntent.getComponent().getPackageName(),
3445 PackageManager.MATCH_UNINSTALLED_PACKAGES
3446 | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
3447 if (ai != null) {
3448 effectiveUid = ai.uid;
3449 }
3450 } catch (RemoteException e) {
3451 }
3452 }
3453 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
3454 + ": effectiveUid=" + effectiveUid);
3455 }
3456
3457 if (persistTaskVersion < 1) {
3458 // We need to convert the resize mode of home activities saved before version one if
3459 // they are marked as RESIZE_MODE_RESIZEABLE to
3460 // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
3461 // before version 1 and the system didn't resize home activities before then.
3462 if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
3463 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
3464 }
3465 } else {
3466 // This activity has previously marked itself explicitly as both resizeable and
3467 // supporting picture-in-picture. Since there is no longer a requirement for
3468 // picture-in-picture activities to be resizeable, we can mark this simply as
3469 // resizeable and supporting picture-in-picture separately.
3470 if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
3471 resizeMode = RESIZE_MODE_RESIZEABLE;
3472 supportsPictureInPicture = true;
3473 }
3474 }
3475
3476 final Task task = create(stackSupervisor.mService,
3477 taskId, intent, affinityIntent,
3478 affinity, rootAffinity, realActivity, origActivity, rootHasReset,
3479 autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
3480 lastTimeOnTop, neverRelinquishIdentity, taskDescription,
3481 taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
3482 callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
3483 userSetupComplete, minWidth, minHeight, null /*stack*/);
3484 task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
3485 task.setBounds(lastNonFullscreenBounds);
3486
3487 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
3488 task.addChild(activities.get(activityNdx));
3489 }
3490
3491 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
3492 return task;
3493 }
3494
3495 void handleUnknownTag(String name, XmlPullParser in)
3496 throws IOException, XmlPullParserException {
3497 Slog.e(TAG, "restoreTask: Unexpected name=" + name);
3498 XmlUtils.skipCurrentTag(in);
3499 }
Robert Carrf59b8dd2017-10-02 18:58:36 -07003500 }
Craig Mautnerb1fd65c02013-02-05 13:34:57 -08003501}