blob: 6ddd943dcf68f5e8afd26b556843cdd0ea9101d4 [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() {
1070 final int rootActivityIndex = findRootIndex(false /* effectiveRoot */);
1071 if (rootActivityIndex == -1) {
1072 // There are no non-finishing activities in the task.
1073 return null;
1074 }
1075 return getChildAt(rootActivityIndex);
1076 }
1077
Wale Ogunwale21e06482019-11-18 05:14:15 -08001078 ActivityRecord getTopNonFinishingActivity() {
1079 return getTopNonFinishingActivity(true /* includeOverlays */);
Louis Changcdec0802019-11-11 11:45:07 +08001080 }
1081
Wale Ogunwale21e06482019-11-18 05:14:15 -08001082 ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
Louis Changcdec0802019-11-11 11:45:07 +08001083 for (int i = getChildCount() - 1; i >= 0; --i) {
1084 final ActivityRecord r = getChildAt(i);
1085 if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
1086 continue;
1087 }
1088 return r;
1089 }
1090 return null;
1091 }
1092
1093 ActivityRecord topRunningActivityLocked() {
1094 if (mStack != null) {
1095 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
1096 ActivityRecord r = getChildAt(activityNdx);
1097 if (!r.finishing && r.okToShowLocked()) {
1098 return r;
1099 }
1100 }
1101 }
1102 return null;
1103 }
1104
1105 /**
1106 * Return true if any activities in this task belongs to input uid.
1107 */
1108 boolean containsAppUid(int uid) {
1109 for (int i = getChildCount() - 1; i >= 0; --i) {
1110 final ActivityRecord r = getChildAt(i);
1111 if (r.getUid() == uid) {
1112 return true;
1113 }
1114 }
1115 return false;
1116 }
1117
1118 void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
1119 if (mStack != null) {
1120 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
1121 ActivityRecord r = getChildAt(activityNdx);
1122 if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
1123 outActivities.add(r);
1124 }
1125 }
1126 }
1127 }
1128
1129 ActivityRecord topRunningActivityWithStartingWindowLocked() {
1130 if (mStack != null) {
1131 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
1132 ActivityRecord r = getChildAt(activityNdx);
1133 if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
1134 || r.finishing || !r.okToShowLocked()) {
1135 continue;
1136 }
1137 return r;
1138 }
1139 }
1140 return null;
1141 }
1142
1143 /**
1144 * Return the number of running activities, and the number of non-finishing/initializing
1145 * activities in the provided {@param reportOut} respectively.
1146 */
1147 void getNumRunningActivities(TaskActivitiesReport reportOut) {
1148 reportOut.reset();
1149 for (int i = getChildCount() - 1; i >= 0; --i) {
1150 final ActivityRecord r = getChildAt(i);
1151 if (r.finishing) {
1152 continue;
1153 }
1154
1155 reportOut.base = r;
1156
1157 // Increment the total number of non-finishing activities
1158 reportOut.numActivities++;
1159
1160 if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
1161 reportOut.top = r;
1162 // Reset the number of running activities until we hit the first non-initializing
1163 // activity
1164 reportOut.numRunning = 0;
1165 }
1166 if (r.attachedToProcess()) {
1167 // Increment the number of actually running activities
1168 reportOut.numRunning++;
1169 }
1170 }
1171 }
1172
1173 boolean okToShowLocked() {
1174 // NOTE: If {@link Task#topRunningActivity} return is not null then it is
1175 // okay to show the activity when locked.
1176 return mAtmService.mStackSupervisor.isCurrentProfileLocked(mUserId)
1177 || topRunningActivityLocked() != null;
1178 }
1179
1180 /**
1181 * Reorder the history stack so that the passed activity is brought to the front.
1182 */
1183 final void moveActivityToFrontLocked(ActivityRecord newTop) {
1184 if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
1185 + newTop + " to stack at top callers=" + Debug.getCallers(4));
1186
1187 positionChildAtTop(newTop);
1188 updateEffectiveIntent();
1189 }
1190
1191 @Override
1192 public int getActivityType() {
1193 final int applicationType = super.getActivityType();
1194 if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
1195 return applicationType;
1196 }
1197 return getChildAt(0).getActivityType();
1198 }
1199
1200 @Override
1201 void addChild(ActivityRecord r, int index) {
1202 // If this task had any child before we added this one.
1203 boolean hadChild = hasChild();
1204
1205 index = getAdjustedAddPosition(r, index);
1206 super.addChild(r, index);
1207
1208 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
1209 r.inHistory = true;
1210
Louis Changcdec0802019-11-11 11:45:07 +08001211 // Only set this based on the first activity
1212 if (!hadChild) {
1213 if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
1214 // Normally non-standard activity type for the activity record will be set when the
1215 // object is created, however we delay setting the standard application type until
1216 // this point so that the task can set the type for additional activities added in
1217 // the else condition below.
1218 r.setActivityType(ACTIVITY_TYPE_STANDARD);
1219 }
1220 setActivityType(r.getActivityType());
1221 isPersistable = r.isPersistable();
1222 mCallingUid = r.launchedFromUid;
1223 mCallingPackage = r.launchedFromPackage;
1224 // Clamp to [1, max].
1225 maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
1226 ActivityTaskManager.getMaxAppRecentsLimitStatic());
1227 } else {
1228 // Otherwise make all added activities match this one.
1229 r.setActivityType(getActivityType());
1230 }
1231
1232 updateEffectiveIntent();
1233 if (r.isPersistable()) {
1234 mAtmService.notifyTaskPersisterLocked(this, false);
1235 }
1236
1237 // Make sure the list of display UID whitelists is updated
1238 // now that this record is in a new task.
1239 mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
1240 }
1241
1242 void addChild(ActivityRecord r) {
1243 addChild(r, Integer.MAX_VALUE /* add on top */);
1244 }
1245
1246 @Override
1247 void removeChild(ActivityRecord r) {
1248 if (!mChildren.contains(r)) {
1249 Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
1250 return;
1251 }
1252
1253 super.removeChild(r);
Louis Changcdec0802019-11-11 11:45:07 +08001254 if (r.isPersistable()) {
1255 mAtmService.notifyTaskPersisterLocked(this, false);
1256 }
1257
1258 if (inPinnedWindowingMode()) {
1259 // We normally notify listeners of task stack changes on pause, however pinned stack
1260 // activities are normally in the paused state so no notification will be sent there
1261 // before the activity is removed. We send it here so instead.
1262 mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
1263 }
1264
1265 final String reason = "removeChild";
1266 if (hasChild()) {
1267 updateEffectiveIntent();
1268
1269 // The following block can be executed multiple times if there is more than one overlay.
1270 // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
1271 // of the task by id and exiting early if not found.
1272 if (onlyHasTaskOverlayActivities(false /* excludingFinishing */)) {
1273 // When destroying a task, tell the supervisor to remove it so that any activity it
1274 // has can be cleaned up correctly. This is currently the only place where we remove
1275 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
1276 // state into removeChild(), we just clear the task here before the other residual
1277 // work.
1278 // TODO: If the callers to removeChild() changes such that we have multiple places
1279 // where we are destroying the task, move this back into removeChild()
1280 mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
1281 !REMOVE_FROM_RECENTS, reason);
1282 }
1283 } else if (!mReuseTask) {
1284 // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
1285 mStack.removeChild(this, reason);
1286 EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
1287 "removeChild: last r=" + r + " in t=" + this);
1288 removeIfPossible();
1289 }
1290 }
1291
1292 /**
1293 * @return whether or not there are ONLY task overlay activities in the stack.
1294 * If {@param excludeFinishing} is set, then ignore finishing activities in the check.
1295 * If there are no task overlay activities, this call returns false.
1296 */
1297 boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
1298 int count = 0;
1299 for (int i = getChildCount() - 1; i >= 0; i--) {
1300 final ActivityRecord r = getChildAt(i);
1301 if (excludeFinishing && r.finishing) {
1302 continue;
1303 }
1304 if (!r.mTaskOverlay) {
1305 return false;
1306 }
1307 count++;
1308 }
1309 return count > 0;
1310 }
1311
1312 boolean autoRemoveFromRecents() {
1313 // We will automatically remove the task either if it has explicitly asked for
1314 // this, or it is empty and has never contained an activity that got shown to
1315 // the user.
1316 return autoRemoveRecents || (!hasChild() && !hasBeenVisible);
1317 }
1318
1319 /**
1320 * Completely remove all activities associated with an existing
1321 * task starting at a specified index.
1322 */
Wale Ogunwale21e06482019-11-18 05:14:15 -08001323 private void performClearTaskAtIndexLocked(String reason) {
Louis Changcdec0802019-11-11 11:45:07 +08001324 int numActivities = getChildCount();
Wale Ogunwale21e06482019-11-18 05:14:15 -08001325 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
Louis Changcdec0802019-11-11 11:45:07 +08001326 final ActivityRecord r = getChildAt(activityNdx);
1327 if (r.finishing) {
1328 continue;
1329 }
1330 if (mStack == null) {
1331 // Task was restored from persistent storage.
1332 r.takeFromHistory();
1333 removeChild(r);
1334 --activityNdx;
1335 --numActivities;
1336 } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
1337 false /* oomAdj */)
1338 == FINISH_RESULT_REMOVED) {
1339 --activityNdx;
1340 --numActivities;
1341 }
1342 }
1343 }
1344
1345 /**
1346 * Completely remove all activities associated with an existing task.
1347 */
1348 void performClearTaskLocked() {
1349 mReuseTask = true;
Wale Ogunwale21e06482019-11-18 05:14:15 -08001350 performClearTaskAtIndexLocked("clear-task-all");
Louis Changcdec0802019-11-11 11:45:07 +08001351 mReuseTask = false;
1352 }
1353
1354 ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
1355 mReuseTask = true;
1356 final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
1357 mReuseTask = false;
1358 return result;
1359 }
1360
1361 /**
1362 * Perform clear operation as requested by
1363 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
1364 * stack to the given task, then look for
1365 * an instance of that activity in the stack and, if found, finish all
1366 * activities on top of it and return the instance.
1367 *
1368 * @param newR Description of the new activity being started.
1369 * @return Returns the old activity that should be continued to be used,
1370 * or {@code null} if none was found.
1371 */
1372 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
1373 int numActivities = getChildCount();
1374 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
1375 ActivityRecord r = getChildAt(activityNdx);
1376 if (r.finishing) {
1377 continue;
1378 }
1379 if (r.mActivityComponent.equals(newR.mActivityComponent)) {
1380 // Here it is! Now finish everything in front...
1381 final ActivityRecord ret = r;
1382
1383 for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
1384 r = getChildAt(activityNdx);
1385 if (r.finishing) {
1386 continue;
1387 }
1388 ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
1389 if (opts != null) {
1390 ret.updateOptionsLocked(opts);
1391 }
1392 if (r.finishIfPossible("clear-task-stack", false /* oomAdj */)
1393 == FINISH_RESULT_REMOVED) {
1394 --activityNdx;
1395 --numActivities;
1396 }
1397 }
1398
1399 // Finally, if this is a normal launch mode (that is, not
1400 // expecting onNewIntent()), then we will finish the current
1401 // instance of the activity so a new fresh one can be started.
1402 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
1403 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
1404 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
1405 if (!ret.finishing) {
1406 ret.finishIfPossible("clear-task-top", false /* oomAdj */);
1407 return null;
1408 }
1409 }
1410
1411 return ret;
1412 }
1413 }
1414
1415 return null;
1416 }
1417
1418 void removeTaskActivitiesLocked(String reason) {
1419 // Just remove the entire task.
Wale Ogunwale21e06482019-11-18 05:14:15 -08001420 performClearTaskAtIndexLocked(reason);
Louis Changcdec0802019-11-11 11:45:07 +08001421 }
1422
1423 String lockTaskAuthToString() {
1424 switch (mLockTaskAuth) {
1425 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
1426 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
1427 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
1428 case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
1429 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
1430 default: return "unknown=" + mLockTaskAuth;
1431 }
1432 }
1433
1434 void setLockTaskAuth() {
1435 setLockTaskAuth(getRootActivity());
1436 }
1437
1438 private void setLockTaskAuth(@Nullable ActivityRecord r) {
1439 if (r == null) {
1440 mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
1441 return;
1442 }
1443
1444 final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
1445 final LockTaskController lockTaskController = mAtmService.getLockTaskController();
1446 switch (r.lockTaskLaunchMode) {
1447 case LOCK_TASK_LAUNCH_MODE_DEFAULT:
1448 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
1449 ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
1450 break;
1451
1452 case LOCK_TASK_LAUNCH_MODE_NEVER:
1453 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
1454 break;
1455
1456 case LOCK_TASK_LAUNCH_MODE_ALWAYS:
1457 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
1458 break;
1459
1460 case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
1461 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
1462 ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
1463 break;
1464 }
1465 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
1466 + " mLockTaskAuth=" + lockTaskAuthToString());
1467 }
1468
1469 @Override
1470 public boolean supportsSplitScreenWindowingMode() {
1471 // A task can not be docked even if it is considered resizeable because it only supports
1472 // picture-in-picture mode but has a non-resizeable resizeMode
1473 return super.supportsSplitScreenWindowingMode()
1474 // TODO(task-group): Probably makes sense to move this and associated code into
1475 // WindowContainer so it affects every node.
1476 && mAtmService.mSupportsSplitScreenMultiWindow
1477 && (mAtmService.mForceResizableActivities
1478 || (isResizeable(false /* checkSupportsPip */)
1479 && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
1480 }
1481
1482 /**
1483 * Check whether this task can be launched on the specified display.
1484 *
1485 * @param displayId Target display id.
1486 * @return {@code true} if either it is the default display or this activity can be put on a
1487 * secondary display.
1488 */
1489 boolean canBeLaunchedOnDisplay(int displayId) {
1490 return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
1491 -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
1492 }
1493
1494 /**
1495 * Check that a given bounds matches the application requested orientation.
1496 *
1497 * @param bounds The bounds to be tested.
1498 * @return True if the requested bounds are okay for a resizing request.
1499 */
1500 private boolean canResizeToBounds(Rect bounds) {
1501 if (bounds == null || !inFreeformWindowingMode()) {
1502 // Note: If not on the freeform workspace, we ignore the bounds.
1503 return true;
1504 }
1505 final boolean landscape = bounds.width() > bounds.height();
1506 final Rect configBounds = getRequestedOverrideBounds();
1507 if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
1508 return configBounds.isEmpty()
1509 || landscape == (configBounds.width() > configBounds.height());
1510 }
1511 return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
1512 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
1513 }
1514
1515 /**
1516 * @return {@code true} if the task is being cleared for the purposes of being reused.
1517 */
1518 boolean isClearingToReuseTask() {
1519 return mReuseTask;
1520 }
1521
1522 /**
1523 * Find the activity in the history stack within the given task. Returns
1524 * the index within the history at which it's found, or < 0 if not found.
1525 */
1526 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
1527 final ComponentName realActivity = r.mActivityComponent;
1528 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
1529 ActivityRecord candidate = getChildAt(activityNdx);
1530 if (candidate.finishing) {
1531 continue;
1532 }
1533 if (candidate.mActivityComponent.equals(realActivity)) {
1534 return candidate;
1535 }
1536 }
1537 return null;
1538 }
1539
1540 /** Updates the last task description values. */
1541 void updateTaskDescription() {
1542 // TODO(AM refactor): Cleanup to use findRootIndex()
1543 // Traverse upwards looking for any break between main task activities and
1544 // utility activities.
1545 int activityNdx;
1546 final int numActivities = getChildCount();
1547 final boolean relinquish = numActivities != 0
1548 && (getChildAt(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
1549 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; ++activityNdx) {
1550 final ActivityRecord r = getChildAt(activityNdx);
1551 if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1552 // This will be the top activity for determining taskDescription. Pre-inc to
1553 // overcome initial decrement below.
1554 ++activityNdx;
1555 break;
1556 }
1557 if (r.intent != null
1558 && (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1559 break;
1560 }
1561 }
1562 if (activityNdx > 0) {
1563 // Traverse downwards starting below break looking for set label, icon.
1564 // Note that if there are activities in the task but none of them set the
1565 // recent activity values, then we do not fall back to the last set
1566 // values in the Task.
1567 String label = null;
1568 String iconFilename = null;
1569 int iconResource = -1;
1570 int colorPrimary = 0;
1571 int colorBackground = 0;
1572 int statusBarColor = 0;
1573 int navigationBarColor = 0;
1574 boolean statusBarContrastWhenTransparent = false;
1575 boolean navigationBarContrastWhenTransparent = false;
1576 boolean topActivity = true;
1577 for (--activityNdx; activityNdx >= 0; --activityNdx) {
1578 final ActivityRecord r = getChildAt(activityNdx);
1579 if (r.mTaskOverlay) {
1580 continue;
1581 }
1582 if (r.taskDescription != null) {
1583 if (label == null) {
1584 label = r.taskDescription.getLabel();
1585 }
1586 if (iconResource == -1) {
1587 iconResource = r.taskDescription.getIconResource();
1588 }
1589 if (iconFilename == null) {
1590 iconFilename = r.taskDescription.getIconFilename();
1591 }
1592 if (colorPrimary == 0) {
1593 colorPrimary = r.taskDescription.getPrimaryColor();
1594 }
1595 if (topActivity) {
1596 colorBackground = r.taskDescription.getBackgroundColor();
1597 statusBarColor = r.taskDescription.getStatusBarColor();
1598 navigationBarColor = r.taskDescription.getNavigationBarColor();
1599 statusBarContrastWhenTransparent =
1600 r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
1601 navigationBarContrastWhenTransparent =
1602 r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
1603 }
1604 }
1605 topActivity = false;
1606 }
1607 final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
1608 iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
1609 statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent,
1610 mResizeMode, mMinWidth, mMinHeight);
1611 setTaskDescription(taskDescription);
1612 // Update the task affiliation color if we are the parent of the group
1613 if (mTaskId == mAffiliatedTaskId) {
1614 mAffiliatedTaskColor = taskDescription.getPrimaryColor();
1615 }
1616 mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
1617 getTaskInfo());
1618 }
1619 }
1620
1621 /**
1622 * Find the index of the root activity in the task. It will be the first activity from the
1623 * bottom that is not finishing.
1624 *
1625 * @param effectiveRoot Flag indicating whether 'effective root' should be returned - an
1626 * activity that defines the task identity (its base intent). It's the
1627 * first one that does not have
1628 * {@link ActivityInfo#FLAG_RELINQUISH_TASK_IDENTITY}.
1629 * @return index of the 'root' or 'effective' root in the list of activities, -1 if no eligible
1630 * activity was found.
1631 */
1632 int findRootIndex(boolean effectiveRoot) {
1633 int effectiveNdx = -1;
1634 final int topActivityNdx = getChildCount() - 1;
1635 for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
1636 final ActivityRecord r = getChildAt(activityNdx);
1637 if (r.finishing) {
1638 continue;
1639 }
1640 effectiveNdx = activityNdx;
1641 if (!effectiveRoot || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1642 break;
1643 }
1644 }
1645 return effectiveNdx;
1646 }
1647
1648 // TODO (AM refactor): Invoke automatically when there is a change in children
1649 @VisibleForTesting
1650 void updateEffectiveIntent() {
1651 int effectiveRootIndex = findRootIndex(true /* effectiveRoot */);
1652 if (effectiveRootIndex == -1) {
1653 // All activities in the task are either finishing or relinquish task identity.
1654 // But we still want to update the intent, so let's use the bottom activity.
1655 effectiveRootIndex = 0;
1656 }
1657 final ActivityRecord r = getChildAt(effectiveRootIndex);
1658 setIntent(r);
1659
1660 // Update the task description when the activities change
1661 updateTaskDescription();
1662 }
1663
1664 void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
Evan Rosky70213702019-11-05 10:26:24 -08001665 final Rect parentBounds = getParent() != null ? getParent().getBounds() : null;
1666 if (bounds == null
1667 || (bounds.isEmpty() && (parentBounds == null || parentBounds.isEmpty()))) {
Louis Changcdec0802019-11-11 11:45:07 +08001668 return;
1669 }
1670 int minWidth = mMinWidth;
1671 int minHeight = mMinHeight;
1672 // If the task has no requested minimal size, we'd like to enforce a minimal size
1673 // so that the user can not render the task too small to manipulate. We don't need
1674 // to do this for the pinned stack as the bounds are controlled by the system.
1675 if (!inPinnedWindowingMode() && mStack != null) {
1676 final int defaultMinSizeDp =
1677 mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
1678 final ActivityDisplay display =
1679 mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
1680 final float density =
1681 (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
1682 final int defaultMinSize = (int) (defaultMinSizeDp * density);
1683
1684 if (minWidth == INVALID_MIN_SIZE) {
1685 minWidth = defaultMinSize;
1686 }
1687 if (minHeight == INVALID_MIN_SIZE) {
1688 minHeight = defaultMinSize;
1689 }
1690 }
Evan Rosky70213702019-11-05 10:26:24 -08001691 if (bounds.isEmpty()) {
1692 // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
1693 // do, we can just skip.
1694 if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
1695 return;
1696 }
1697 bounds.set(parentBounds);
1698 }
Louis Changcdec0802019-11-11 11:45:07 +08001699 final boolean adjustWidth = minWidth > bounds.width();
1700 final boolean adjustHeight = minHeight > bounds.height();
1701 if (!(adjustWidth || adjustHeight)) {
1702 return;
1703 }
1704
1705 if (adjustWidth) {
1706 if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
1707 bounds.left = bounds.right - minWidth;
1708 } else {
1709 // Either left bounds match, or neither match, or the previous bounds were
1710 // fullscreen and we default to keeping left.
1711 bounds.right = bounds.left + minWidth;
1712 }
1713 }
1714 if (adjustHeight) {
1715 if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
1716 bounds.top = bounds.bottom - minHeight;
1717 } else {
1718 // Either top bounds match, or neither match, or the previous bounds were
1719 // fullscreen and we default to keeping top.
1720 bounds.bottom = bounds.top + minHeight;
1721 }
1722 }
1723 }
1724
1725 void setLastNonFullscreenBounds(Rect bounds) {
1726 if (mLastNonFullscreenBounds == null) {
1727 mLastNonFullscreenBounds = new Rect(bounds);
1728 } else {
1729 mLastNonFullscreenBounds.set(bounds);
1730 }
1731 }
1732
1733 /**
1734 * This should be called when an child activity changes state. This should only
1735 * be called from
1736 * {@link ActivityRecord#setState(ActivityState, String)} .
1737 * @param record The {@link ActivityRecord} whose state has changed.
1738 * @param state The new state.
1739 * @param reason The reason for the change.
1740 */
1741 void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
1742 final ActivityStack parent = getStack();
1743
1744 if (parent != null) {
1745 parent.onActivityStateChanged(record, state, reason);
1746 }
1747 }
1748
1749 @Override
1750 public void onConfigurationChanged(Configuration newParentConfig) {
1751 // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
1752 // restore the last recorded non-fullscreen bounds.
1753 final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
1754 final boolean nextPersistTaskBounds =
1755 getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
1756 || newParentConfig.windowConfiguration.persistTaskBounds();
1757 if (!prevPersistTaskBounds && nextPersistTaskBounds
1758 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
1759 // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
1760 getRequestedOverrideConfiguration().windowConfiguration
1761 .setBounds(mLastNonFullscreenBounds);
1762 }
1763
1764 final boolean wasInMultiWindowMode = inMultiWindowMode();
1765 super.onConfigurationChanged(newParentConfig);
1766 if (wasInMultiWindowMode != inMultiWindowMode()) {
1767 mAtmService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
1768 }
1769
1770 // If the configuration supports persistent bounds (eg. Freeform), keep track of the
1771 // current (non-fullscreen) bounds for persistence.
1772 if (getWindowConfiguration().persistTaskBounds()) {
1773 final Rect currentBounds = getRequestedOverrideBounds();
1774 if (!currentBounds.isEmpty()) {
1775 setLastNonFullscreenBounds(currentBounds);
1776 }
1777 }
1778 // TODO: Should also take care of Pip mode changes here.
1779
1780 saveLaunchingStateIfNeeded();
1781 }
1782
1783 /**
1784 * Saves launching state if necessary so that we can launch the activity to its latest state.
1785 * It only saves state if this task has been shown to user and it's in fullscreen or freeform
1786 * mode on freeform displays.
1787 */
1788 void saveLaunchingStateIfNeeded() {
1789 if (!hasBeenVisible) {
1790 // Not ever visible to user.
1791 return;
1792 }
1793
1794 final int windowingMode = getWindowingMode();
1795 if (windowingMode != WINDOWING_MODE_FULLSCREEN
1796 && windowingMode != WINDOWING_MODE_FREEFORM) {
1797 return;
1798 }
1799
1800 // Don't persist state if display isn't in freeform mode. Then the task will be launched
1801 // back to its last state in a freeform display when it's launched in a freeform display
1802 // next time.
1803 if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) {
1804 return;
1805 }
1806
1807 // Saves the new state so that we can launch the activity at the same location.
1808 mAtmService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
1809 }
1810
1811 /**
1812 * Adjust bounds to stay within stack bounds.
1813 *
1814 * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
1815 * that keep them unchanged, but be contained within the stack bounds.
1816 *
1817 * @param bounds Bounds to be adjusted.
1818 * @param stackBounds Bounds within which the other bounds should remain.
1819 * @param overlapPxX The amount of px required to be visible in the X dimension.
1820 * @param overlapPxY The amount of px required to be visible in the Y dimension.
1821 */
1822 private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
1823 int overlapPxY) {
1824 if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
1825 return;
1826 }
1827
1828 // For each side of the parent (eg. left), check if the opposing side of the window (eg.
1829 // right) is at least overlap pixels away. If less, offset the window by that difference.
1830 int horizontalDiff = 0;
1831 // If window is smaller than overlap, use it's smallest dimension instead
1832 int overlapLR = Math.min(overlapPxX, bounds.width());
1833 if (bounds.right < (stackBounds.left + overlapLR)) {
1834 horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
1835 } else if (bounds.left > (stackBounds.right - overlapLR)) {
1836 horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
1837 }
1838 int verticalDiff = 0;
1839 int overlapTB = Math.min(overlapPxY, bounds.width());
1840 if (bounds.bottom < (stackBounds.top + overlapTB)) {
1841 verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
1842 } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
1843 verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
1844 }
1845 bounds.offset(horizontalDiff, verticalDiff);
1846 }
1847
1848 /**
1849 * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
1850 * intersectBounds on a side, then the respective side will not be intersected.
1851 *
1852 * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
1853 * inset on that side is no-longer applicable. This scenario happens when a task's minimal
1854 * bounds are larger than the provided parent/display bounds.
1855 *
1856 * @param inOutBounds the bounds to intersect.
1857 * @param intersectBounds the bounds to intersect with.
1858 * @param intersectInsets insets to apply to intersectBounds before intersecting.
1859 */
1860 static void intersectWithInsetsIfFits(
1861 Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
1862 if (inOutBounds.right <= intersectBounds.right) {
1863 inOutBounds.right =
1864 Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
1865 }
1866 if (inOutBounds.bottom <= intersectBounds.bottom) {
1867 inOutBounds.bottom =
1868 Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
1869 }
1870 if (inOutBounds.left >= intersectBounds.left) {
1871 inOutBounds.left =
1872 Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
1873 }
1874 if (inOutBounds.top >= intersectBounds.top) {
1875 inOutBounds.top =
1876 Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
1877 }
1878 }
1879
1880 /**
1881 * Gets bounds with non-decor and stable insets applied respectively.
1882 *
1883 * If bounds overhangs the display, those edges will not get insets. See
1884 * {@link #intersectWithInsetsIfFits}
1885 *
1886 * @param outNonDecorBounds where to place bounds with non-decor insets applied.
1887 * @param outStableBounds where to place bounds with stable insets applied.
1888 * @param bounds the bounds to inset.
1889 */
1890 private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
1891 DisplayInfo displayInfo) {
1892 outNonDecorBounds.set(bounds);
1893 outStableBounds.set(bounds);
1894 if (getStack() == null || getStack().getDisplay() == null) {
1895 return;
1896 }
1897 DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
1898 if (policy == null) {
1899 return;
1900 }
1901 mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
1902
1903 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
1904 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
1905 intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
1906
1907 policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
1908 intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
1909 }
1910
1911 /**
1912 * Asks docked-divider controller for the smallestwidthdp given bounds.
1913 * @param bounds bounds to calculate smallestwidthdp for.
1914 */
1915 private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
1916 DisplayContent dc = mStack.getDisplay().mDisplayContent;
1917 if (dc != null) {
1918 return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
1919 }
1920 return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
1921 }
1922
1923 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1924 @NonNull Configuration parentConfig) {
1925 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
1926 }
1927
1928 /**
1929 * Calculates configuration values used by the client to get resources. This should be run
1930 * using app-facing bounds (bounds unmodified by animations or transient interactions).
1931 *
1932 * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
1933 * configuring an "inherit-bounds" window which means that all configuration settings would
1934 * just be inherited from the parent configuration.
1935 **/
1936 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1937 @NonNull Configuration parentConfig,
1938 @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
1939 int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
1940 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1941 windowingMode = parentConfig.windowConfiguration.getWindowingMode();
1942 }
1943
1944 float density = inOutConfig.densityDpi;
1945 if (density == Configuration.DENSITY_DPI_UNDEFINED) {
1946 density = parentConfig.densityDpi;
1947 }
1948 density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
1949
Evan Rosky70213702019-11-05 10:26:24 -08001950 final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
1951 if (resolvedBounds == null) {
1952 mTmpFullBounds.setEmpty();
1953 } else {
1954 mTmpFullBounds.set(resolvedBounds);
1955 }
1956 if (mTmpFullBounds.isEmpty()) {
1957 mTmpFullBounds.set(parentConfig.windowConfiguration.getBounds());
1958 }
1959
Louis Changcdec0802019-11-11 11:45:07 +08001960 Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
1961 if (outAppBounds == null || outAppBounds.isEmpty()) {
Evan Rosky70213702019-11-05 10:26:24 -08001962 inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds);
Louis Changcdec0802019-11-11 11:45:07 +08001963 outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
1964 }
1965 // Non-null compatibility insets means the activity prefers to keep its original size, so
1966 // the out bounds doesn't need to be restricted by the parent.
1967 final boolean insideParentBounds = compatInsets == null;
1968 if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
1969 final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
1970 if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
1971 outAppBounds.intersect(parentAppBounds);
1972 }
1973 }
1974
1975 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
1976 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
1977 if (insideParentBounds && mStack != null) {
1978 final DisplayInfo di = new DisplayInfo();
1979 mStack.getDisplay().mDisplay.getDisplayInfo(di);
1980
1981 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
1982 // area, i.e. the screen area without the system bars.
1983 // The non decor inset are areas that could never be removed in Honeycomb. See
1984 // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
Evan Rosky70213702019-11-05 10:26:24 -08001985 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);
Louis Changcdec0802019-11-11 11:45:07 +08001986 } else {
1987 // Apply the given non-decor and stable insets to calculate the corresponding bounds
1988 // for screen size of configuration.
1989 int rotation = inOutConfig.windowConfiguration.getRotation();
1990 if (rotation == ROTATION_UNDEFINED) {
1991 rotation = parentConfig.windowConfiguration.getRotation();
1992 }
1993 if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
Evan Rosky70213702019-11-05 10:26:24 -08001994 mTmpNonDecorBounds.set(mTmpFullBounds);
1995 mTmpStableBounds.set(mTmpFullBounds);
Louis Changcdec0802019-11-11 11:45:07 +08001996 compatInsets.getDisplayBoundsByRotation(mTmpBounds, rotation);
1997 intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
1998 compatInsets.mNonDecorInsets[rotation]);
1999 intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
2000 compatInsets.mStableInsets[rotation]);
2001 outAppBounds.set(mTmpNonDecorBounds);
2002 } else {
2003 // Set to app bounds because it excludes decor insets.
2004 mTmpNonDecorBounds.set(outAppBounds);
2005 mTmpStableBounds.set(outAppBounds);
2006 }
2007 }
2008
2009 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
2010 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
2011 inOutConfig.screenWidthDp = insideParentBounds
2012 ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
2013 : overrideScreenWidthDp;
2014 }
2015 if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2016 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
2017 inOutConfig.screenHeightDp = insideParentBounds
2018 ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
2019 : overrideScreenHeightDp;
2020 }
2021
2022 if (inOutConfig.smallestScreenWidthDp
2023 == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
2024 if (WindowConfiguration.isFloating(windowingMode)) {
2025 // For floating tasks, calculate the smallest width from the bounds of the task
2026 inOutConfig.smallestScreenWidthDp = (int) (
Evan Rosky70213702019-11-05 10:26:24 -08002027 Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
Louis Changcdec0802019-11-11 11:45:07 +08002028 } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
2029 // Iterating across all screen orientations, and return the minimum of the task
2030 // width taking into account that the bounds might change because the snap
2031 // algorithm snaps to a different value
2032 inOutConfig.smallestScreenWidthDp =
Evan Rosky70213702019-11-05 10:26:24 -08002033 getSmallestScreenWidthDpForDockedBounds(mTmpFullBounds);
Louis Changcdec0802019-11-11 11:45:07 +08002034 }
2035 // otherwise, it will just inherit
2036 }
2037 }
2038
2039 if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
2040 inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
2041 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
2042 }
2043 if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
2044 // For calculating screen layout, we need to use the non-decor inset screen area for the
2045 // calculation for compatibility reasons, i.e. screen area without system bars that
2046 // could never go away in Honeycomb.
2047 final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
2048 final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
2049 // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start
2050 // override calculation with partial default.
2051 // Reducing the screen layout starting from its parent config.
2052 final int sl = parentConfig.screenLayout
2053 & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
2054 final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
2055 final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
2056 inOutConfig.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
2057 }
2058 }
2059
2060 @Override
2061 void resolveOverrideConfiguration(Configuration newParentConfig) {
2062 mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
2063 super.resolveOverrideConfiguration(newParentConfig);
2064 int windowingMode =
2065 getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
2066 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
2067 windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
2068 }
2069 Rect outOverrideBounds =
2070 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
2071
2072 if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
2073 computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
2074 newParentConfig.windowConfiguration.getBounds(),
2075 newParentConfig.orientation);
2076 }
2077
Louis Changcdec0802019-11-11 11:45:07 +08002078 adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
2079 if (windowingMode == WINDOWING_MODE_FREEFORM) {
2080 // by policy, make sure the window remains within parent somewhere
2081 final float density =
2082 ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
2083 final Rect parentBounds =
2084 new Rect(newParentConfig.windowConfiguration.getBounds());
2085 final ActivityDisplay display = mStack.getDisplay();
2086 if (display != null && display.mDisplayContent != null) {
2087 // If a freeform window moves below system bar, there is no way to move it again
2088 // by touch. Because its caption is covered by system bar. So we exclude them
2089 // from stack bounds. and then caption will be shown inside stable area.
2090 final Rect stableBounds = new Rect();
2091 display.mDisplayContent.getStableRect(stableBounds);
2092 parentBounds.intersect(stableBounds);
2093 }
2094
2095 fitWithinBounds(outOverrideBounds, parentBounds,
2096 (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
2097 (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
2098
2099 // Prevent to overlap caption with stable insets.
2100 final int offsetTop = parentBounds.top - outOverrideBounds.top;
2101 if (offsetTop > 0) {
2102 outOverrideBounds.offset(0, offsetTop);
2103 }
2104 }
2105 computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
2106 }
2107
2108 /**
2109 * Compute bounds (letterbox or pillarbox) for
2110 * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
2111 * orientation change and the requested orientation is different from the parent.
2112 */
2113 void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
2114 @NonNull Rect parentBounds, int parentOrientation) {
2115 // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
2116 outBounds.setEmpty();
2117 if (handlesOrientationChangeFromDescendant()) {
2118 return;
2119 }
2120 if (refActivity == null) {
2121 // Use the top activity as the reference of orientation. Don't include overlays because
2122 // it is usually not the actual content or just temporarily shown.
2123 // E.g. ForcedResizableInfoActivity.
Wale Ogunwale21e06482019-11-18 05:14:15 -08002124 refActivity = getTopNonFinishingActivity(false /* includeOverlays */);
Louis Changcdec0802019-11-11 11:45:07 +08002125 }
2126
2127 // If the task or the reference activity requires a different orientation (either by
2128 // override or activityInfo), make it fit the available bounds by scaling down its bounds.
2129 final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
2130 final int forcedOrientation =
2131 (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
2132 ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
2133 if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
2134 return;
2135 }
2136
2137 final int parentWidth = parentBounds.width();
2138 final int parentHeight = parentBounds.height();
2139 final float aspect = ((float) parentHeight) / parentWidth;
2140 if (forcedOrientation == ORIENTATION_LANDSCAPE) {
2141 final int height = (int) (parentWidth / aspect);
2142 final int top = parentBounds.centerY() - height / 2;
2143 outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
2144 } else {
2145 final int width = (int) (parentHeight * aspect);
2146 final int left = parentBounds.centerX() - width / 2;
2147 outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
2148 }
2149 }
2150
2151 Rect updateOverrideConfigurationFromLaunchBounds() {
2152 final Rect bounds = getLaunchBounds();
2153 setBounds(bounds);
2154 if (bounds != null && !bounds.isEmpty()) {
2155 // TODO: Review if we actually want to do this - we are setting the launch bounds
2156 // directly here.
2157 bounds.set(getRequestedOverrideBounds());
2158 }
2159 return bounds;
2160 }
2161
2162 /** Updates the task's bounds and override configuration to match what is expected for the
2163 * input stack. */
2164 void updateOverrideConfigurationForStack(ActivityStack inStack) {
2165 if (mStack != null && mStack == inStack) {
2166 return;
2167 }
2168
2169 if (inStack.inFreeformWindowingMode()) {
2170 if (!isResizeable()) {
2171 throw new IllegalArgumentException("Can not position non-resizeable task="
2172 + this + " in stack=" + inStack);
2173 }
2174 if (!matchParentBounds()) {
2175 return;
2176 }
2177 if (mLastNonFullscreenBounds != null) {
2178 setBounds(mLastNonFullscreenBounds);
2179 } else {
2180 mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
2181 }
2182 } else {
2183 setBounds(inStack.getRequestedOverrideBounds());
2184 }
2185 }
2186
2187 /** Returns the bounds that should be used to launch this task. */
2188 Rect getLaunchBounds() {
2189 if (mStack == null) {
2190 return null;
2191 }
2192
2193 final int windowingMode = getWindowingMode();
2194 if (!isActivityTypeStandardOrUndefined()
2195 || windowingMode == WINDOWING_MODE_FULLSCREEN
2196 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
2197 return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
2198 } else if (!getWindowConfiguration().persistTaskBounds()) {
2199 return mStack.getRequestedOverrideBounds();
2200 }
2201 return mLastNonFullscreenBounds;
2202 }
2203
2204 void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
2205 for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
2206 final ActivityRecord r = getChildAt(activityNdx);
Issei Suzuki1669ea42019-11-06 14:20:59 +01002207 if (r.mVisibleRequested) {
Louis Changcdec0802019-11-11 11:45:07 +08002208 r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
2209 }
2210 }
2211 }
2212
2213 void setRootProcess(WindowProcessController proc) {
2214 clearRootProcess();
2215 if (intent != null
2216 && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
2217 mRootProcess = proc;
2218 mRootProcess.addRecentTask(this);
2219 }
2220 }
2221
2222 void clearRootProcess() {
2223 if (mRootProcess != null) {
2224 mRootProcess.removeRecentTask(this);
2225 mRootProcess = null;
2226 }
2227 }
2228
2229 void clearAllPendingOptions() {
2230 for (int i = getChildCount() - 1; i >= 0; i--) {
2231 getChildAt(i).clearOptionsLocked(false /* withAbort */);
2232 }
Craig Mautnerc00204b2013-03-05 15:02:14 -08002233 }
2234
Tiger Huanged6794e2019-05-07 20:07:59 +08002235 @Override
Craig Mautnerc00204b2013-03-05 15:02:14 -08002236 DisplayContent getDisplayContent() {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002237 return getTaskStack() != null ? getTaskStack().getDisplayContent() : null;
2238 }
2239
Louis Changdc077272019-11-12 16:52:56 +08002240 ActivityStack getTaskStack() {
2241 return (ActivityStack) getParent();
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002242 }
2243
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002244 int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
2245 int maxPosition = mChildren.size();
2246 if (!r.mTaskOverlay) {
2247 // We want to place all non-overlay activities below overlays.
2248 while (maxPosition > 0) {
2249 final ActivityRecord current = mChildren.get(maxPosition - 1);
Wale Ogunwale7a8889a2019-11-16 08:23:42 -08002250 if (current.mTaskOverlay) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002251 --maxPosition;
2252 continue;
2253 }
2254 break;
2255 }
2256 if (maxPosition < 0) {
2257 maxPosition = 0;
2258 }
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002259 }
2260
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002261 return Math.min(maxPosition, suggestedPosition);
Craig Mautnerc00204b2013-03-05 15:02:14 -08002262 }
2263
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002264 @Override
Wale Ogunwale3198da42019-10-10 14:45:03 +02002265 void positionChildAt(int position, ActivityRecord child, boolean includingParents) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002266 position = getAdjustedAddPosition(child, position);
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002267 super.positionChildAt(position, child, includingParents);
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002268 }
2269
Wale Ogunwalee42d0e12016-05-02 16:40:59 -07002270 private boolean hasWindowsAlive() {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002271 for (int i = mChildren.size() - 1; i >= 0; i--) {
2272 if (mChildren.get(i).hasWindowsAlive()) {
Chong Zhang7e8eeb72016-01-06 19:14:47 -08002273 return true;
2274 }
2275 }
2276 return false;
2277 }
2278
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002279 @VisibleForTesting
2280 boolean shouldDeferRemoval() {
Wale Ogunwalec17418e2019-10-13 23:00:40 +02002281 if (mChildren.isEmpty()) {
2282 // No reason to defer removal of a Task that doesn't have any child.
2283 return false;
2284 }
Wale Ogunwale8577a052019-10-26 23:22:34 -07002285 return hasWindowsAlive() && getTaskStack().isAnimating(TRANSITION | CHILDREN);
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002286 }
2287
Wale Ogunwalef6192862016-09-10 13:42:30 -07002288 @Override
Andrii Kulian45a61fe2017-01-05 16:53:19 -08002289 void removeImmediately() {
Wale Ogunwaleb9b16a72016-01-27 12:24:44 -08002290 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -08002291 EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
Andrii Kulian45a61fe2017-01-05 16:53:19 -08002292 super.removeImmediately();
Craig Mautnere3119b72015-01-20 15:02:36 -08002293 }
2294
Louis Changcdec0802019-11-11 11:45:07 +08002295 // TODO: Consolidate this with Task.reparent()
Louis Changdc077272019-11-12 16:52:56 +08002296 void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -08002297 if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
Wale Ogunwale8577a052019-10-26 23:22:34 -07002298 + " from stack=" + getTaskStack());
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -08002299 EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
Andrii Kulian7cd7c2d2017-01-18 12:14:37 -08002300
Louis Changdc077272019-11-12 16:52:56 +08002301 final ActivityStack prevStack = getTaskStack();
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002302 final boolean wasTopFocusedStack =
2303 mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack);
2304 final ActivityDisplay prevStackDisplay = prevStack.getDisplay();
2305
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -07002306 position = stack.findPositionForTask(this, position, showForAllUsers());
2307
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002308 reparent(stack, position);
2309
2310 if (!moveParents) {
2311 // Only move home stack forward if we are not going to move the new parent forward.
2312 prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason);
Robert Carr18f622f2017-05-08 11:20:43 -07002313 }
2314
Louis Changcdec0802019-11-11 11:45:07 +08002315 stack.positionChildAt(position, this, moveParents);
Andrii Kulian7cd7c2d2017-01-18 12:14:37 -08002316
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002317 // If we are moving from the fullscreen stack to the pinned stack then we want to preserve
2318 // our insets so that there will not be a jump in the area covered by system decorations.
2319 // We rely on the pinned animation to later unset this value.
2320 mPreserveNonFloatingState = stack.inPinnedWindowingMode();
Wale Ogunwale53a29a92015-02-23 15:42:52 -08002321 }
2322
Bryce Leef3c6a472017-11-14 14:53:06 -08002323 public int setBounds(Rect bounds, boolean forceResize) {
2324 final int boundsChanged = setBounds(bounds);
2325
2326 if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) {
2327 onResize();
2328 return BOUNDS_CHANGE_SIZE | boundsChanged;
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -07002329 }
Wale Ogunwale68278562017-09-23 17:13:55 -07002330
Bryce Leef3c6a472017-11-14 14:53:06 -08002331 return boundsChanged;
2332 }
2333
2334 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
2335 @Override
2336 public int setBounds(Rect bounds) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002337 int rotation = Surface.ROTATION_0;
Wale Ogunwale8577a052019-10-26 23:22:34 -07002338 final DisplayContent displayContent = getTaskStack() != null
2339 ? getTaskStack().getDisplayContent() : null;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002340 if (displayContent != null) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002341 rotation = displayContent.getDisplayInfo().rotation;
Bryce Leef3c6a472017-11-14 14:53:06 -08002342 } else if (bounds == null) {
Evan Roskye747c3e2018-10-30 20:06:41 -07002343 return super.setBounds(bounds);
Wale Ogunwale2cc92f52015-09-09 13:12:10 -07002344 }
2345
Bryce Leef3c6a472017-11-14 14:53:06 -08002346 final int boundsChange = super.setBounds(bounds);
Chong Zhangf66db432016-01-13 10:39:51 -08002347
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002348 mRotation = rotation;
Robert Carrf59b8dd2017-10-02 18:58:36 -07002349
Evan Rosky89f5c1d2019-01-29 10:04:05 -08002350 updateSurfacePosition();
Wale Ogunwale2cc92f52015-09-09 13:12:10 -07002351 return boundsChange;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002352 }
2353
Garfield Tan90b04282018-12-11 14:04:42 -08002354 @Override
2355 public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
2356 ConfigurationContainer requestingContainer) {
2357 if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
2358 return true;
2359 }
2360
2361 // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
2362 // it if possible.
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002363 if (getParent() != null) {
2364 onConfigurationChanged(getParent().getConfiguration());
Garfield Tan90b04282018-12-11 14:04:42 -08002365 return true;
2366 }
2367 return false;
2368 }
2369
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002370 void resize(boolean relayout, boolean forced) {
2371 if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) {
2372 getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
2373 }
2374 }
2375
Louis Chang7501e332018-08-20 13:08:39 +08002376 @Override
2377 void onDisplayChanged(DisplayContent dc) {
Garfield Tan2f145f22018-11-01 15:27:03 -07002378 adjustBoundsForDisplayChangeIfNeeded(dc);
Louis Chang7501e332018-08-20 13:08:39 +08002379 super.onDisplayChanged(dc);
davidln1ceedb52019-05-30 14:25:01 -07002380 final int displayId = (dc != null) ? dc.getDisplayId() : Display.INVALID_DISPLAY;
2381 mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
2382 mTaskId, displayId);
Louis Chang7501e332018-08-20 13:08:39 +08002383 }
2384
Jorim Jaggidc249c42015-12-15 14:57:31 -08002385 /**
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002386 * Displayed bounds are used to set where the task is drawn at any given time. This is
2387 * separate from its actual bounds so that the app doesn't see any meaningful configuration
2388 * changes during transitionary periods.
Jorim Jaggidc249c42015-12-15 14:57:31 -08002389 */
Evan Roskyed6767f2018-10-26 17:21:06 -07002390 void setOverrideDisplayedBounds(Rect overrideDisplayedBounds) {
2391 if (overrideDisplayedBounds != null) {
2392 mOverrideDisplayedBounds.set(overrideDisplayedBounds);
Jorim Jaggidc249c42015-12-15 14:57:31 -08002393 } else {
Evan Roskyed6767f2018-10-26 17:21:06 -07002394 mOverrideDisplayedBounds.setEmpty();
Jorim Jaggidc249c42015-12-15 14:57:31 -08002395 }
Evan Rosky89f5c1d2019-01-29 10:04:05 -08002396 updateSurfacePosition();
Jorim Jaggidc249c42015-12-15 14:57:31 -08002397 }
2398
2399 /**
Evan Roskyed6767f2018-10-26 17:21:06 -07002400 * Gets the bounds that override where the task is displayed. See
Wale Ogunwale04d9cb52018-04-30 13:55:07 -07002401 * {@link android.app.IActivityTaskManager#resizeDockedStack} why this is needed.
Jorim Jaggidc249c42015-12-15 14:57:31 -08002402 */
Evan Roskyed6767f2018-10-26 17:21:06 -07002403 Rect getOverrideDisplayedBounds() {
2404 return mOverrideDisplayedBounds;
Jorim Jaggidc249c42015-12-15 14:57:31 -08002405 }
2406
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002407 boolean isResizeable(boolean checkSupportsPip) {
2408 return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
2409 || (checkSupportsPip && mSupportsPictureInPicture));
Chong Zhangb15758a2015-11-17 12:12:03 -08002410 }
2411
2412 boolean isResizeable() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002413 return isResizeable(true /* checkSupportsPip */);
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08002414 }
2415
skuhne@google.com322347b2016-12-02 12:54:03 -08002416 /**
2417 * Tests if the orientation should be preserved upon user interactive resizig operations.
2418
2419 * @return true if orientation should not get changed upon resizing operation.
2420 */
2421 boolean preserveOrientationOnResize() {
2422 return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY
2423 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY
2424 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
2425 }
2426
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08002427 boolean cropWindowsToStackBounds() {
Wale Ogunwaledf241e92016-10-13 15:14:21 -07002428 return isResizeable();
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08002429 }
2430
Jorim Jaggi0429f352015-12-22 16:29:16 +01002431 /**
2432 * Prepares the task bounds to be frozen with the current size. See
Garfield Tane8d84ab2019-10-11 09:49:40 -07002433 * {@link ActivityRecord#freezeBounds}.
Jorim Jaggi0429f352015-12-22 16:29:16 +01002434 */
2435 void prepareFreezingBounds() {
Bryce Leef3c6a472017-11-14 14:53:06 -08002436 mPreparedFrozenBounds.set(getBounds());
Andrii Kulian441e4492016-09-29 15:25:00 -07002437 mPreparedFrozenMergedConfig.setTo(getConfiguration());
Jorim Jaggi0429f352015-12-22 16:29:16 +01002438 }
2439
Chong Zhang5117e272016-05-03 12:47:34 -07002440 /**
2441 * Align the task to the adjusted bounds.
2442 *
2443 * @param adjustedBounds Adjusted bounds to which the task should be aligned.
2444 * @param tempInsetBounds Insets bounds for the task.
2445 * @param alignBottom True if the task's bottom should be aligned to the adjusted
2446 * bounds's bottom; false if the task's top should be aligned
2447 * the adjusted bounds's top.
2448 */
Andrii Kulian441e4492016-09-29 15:25:00 -07002449 void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
Evan Roskydfe3da72018-10-26 17:21:06 -07002450 if (!isResizeable() || EMPTY.equals(getRequestedOverrideConfiguration())) {
Chong Zhang5117e272016-05-03 12:47:34 -07002451 return;
2452 }
2453
2454 getBounds(mTmpRect2);
2455 if (alignBottom) {
2456 int offsetY = adjustedBounds.bottom - mTmpRect2.bottom;
2457 mTmpRect2.offset(0, offsetY);
2458 } else {
2459 mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
2460 }
Evan Roskyed6767f2018-10-26 17:21:06 -07002461 if (tempInsetBounds == null || tempInsetBounds.isEmpty()) {
2462 setOverrideDisplayedBounds(null);
2463 setBounds(mTmpRect2);
2464 } else {
2465 setOverrideDisplayedBounds(mTmpRect2);
2466 setBounds(tempInsetBounds);
2467 }
Chong Zhang5117e272016-05-03 12:47:34 -07002468 }
2469
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002470 /**
2471 * Gets the current overridden displayed bounds. These will be empty if the task is not
2472 * currently overriding where it is displayed.
2473 */
Evan Roskyed6767f2018-10-26 17:21:06 -07002474 @Override
2475 public Rect getDisplayedBounds() {
2476 if (mOverrideDisplayedBounds.isEmpty()) {
2477 return super.getDisplayedBounds();
2478 } else {
2479 return mOverrideDisplayedBounds;
2480 }
2481 }
2482
Issei Suzukiad287d02019-10-31 16:19:44 +01002483 @Override
2484 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
2485 Rect outSurfaceInsets) {
2486 final WindowState windowState = getTopVisibleAppMainWindow();
2487 if (windowState != null) {
2488 windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2489 } else {
2490 super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2491 }
2492 }
2493
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002494 /**
2495 * Calculate the maximum visible area of this task. If the task has only one app,
2496 * the result will be visible frame of that app. If the task has more than one apps,
2497 * we search from top down if the next app got different visible area.
2498 *
2499 * This effort is to handle the case where some task (eg. GMail composer) might pop up
2500 * a dialog that's different in size from the activity below, in which case we should
2501 * be dimming the entire task area behind the dialog.
2502 *
2503 * @param out Rect containing the max visible bounds.
2504 * @return true if the task has some visible app windows; false otherwise.
2505 */
chaviw553b0212018-07-12 13:37:01 -07002506 private boolean getMaxVisibleBounds(Rect out) {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002507 boolean foundTop = false;
Wale Ogunwalef6192862016-09-10 13:42:30 -07002508 for (int i = mChildren.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002509 final ActivityRecord token = mChildren.get(i);
Chong Zhangd8ceb852015-11-11 14:53:41 -08002510 // skip hidden (or about to hide) apps
Issei Suzuki1669ea42019-11-06 14:20:59 +01002511 if (token.mIsExiting || token.isClientHidden() || !token.mVisibleRequested) {
Chong Zhangd8ceb852015-11-11 14:53:41 -08002512 continue;
2513 }
2514 final WindowState win = token.findMainWindow();
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002515 if (win == null) {
2516 continue;
2517 }
2518 if (!foundTop) {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002519 foundTop = true;
chaviw553b0212018-07-12 13:37:01 -07002520 out.setEmpty();
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002521 }
chaviw553b0212018-07-12 13:37:01 -07002522
2523 win.getMaxVisibleBounds(out);
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002524 }
2525 return foundTop;
2526 }
2527
2528 /** Bounds of the task to be used for dimming, as well as touch related tests. */
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002529 public void getDimBounds(Rect out) {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002530 final DisplayContent displayContent = getTaskStack().getDisplayContent();
Robert Carra86a6bf2016-04-08 17:34:16 -07002531 // It doesn't matter if we in particular are part of the resize, since we couldn't have
2532 // a DimLayer anyway if we weren't visible.
Wale Ogunwalef6192862016-09-10 13:42:30 -07002533 final boolean dockedResizing = displayContent != null
2534 && displayContent.mDividerControllerLocked.isResizing();
Evan Rosky4fb1e912019-03-06 13:54:43 -08002535 if (inFreeformWindowingMode() && getMaxVisibleBounds(out)) {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002536 return;
2537 }
2538
Evan Rosky4fb1e912019-03-06 13:54:43 -08002539 if (!matchParentBounds()) {
2540 // When minimizing the docked stack when going home, we don't adjust the task bounds
2541 // so we need to intersect the task bounds with the stack bounds here.
2542 //
2543 // If we are Docked Resizing with snap points, the task bounds could be smaller than the
2544 // stack bounds and so we don't even want to use them. Even if the app should not be
2545 // resized the Dim should keep up with the divider.
2546 if (dockedResizing) {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002547 getTaskStack().getBounds(out);
Evan Rosky4fb1e912019-03-06 13:54:43 -08002548 } else {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002549 getTaskStack().getBounds(mTmpRect);
Evan Rosky4fb1e912019-03-06 13:54:43 -08002550 mTmpRect.intersect(getBounds());
2551 out.set(mTmpRect);
2552 }
2553 } else {
2554 out.set(getBounds());
Wale Ogunwalef6192862016-09-10 13:42:30 -07002555 }
Evan Rosky4fb1e912019-03-06 13:54:43 -08002556 return;
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002557 }
2558
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002559 void setDragResizing(boolean dragResizing, int dragResizeMode) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -08002560 if (mDragResizing != dragResizing) {
chaviw8c9d1f52018-07-25 14:56:07 -07002561 // No need to check if the mode is allowed if it's leaving dragResize
Wale Ogunwale8577a052019-10-26 23:22:34 -07002562 if (dragResizing && !DragResizeMode.isModeAllowedForStack(getTaskStack(), dragResizeMode)) {
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002563 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
Wale Ogunwale8577a052019-10-26 23:22:34 -07002564 + getTaskStack().mStackId + " dragResizeMode=" + dragResizeMode);
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002565 }
Jorim Jaggic662d8e2016-02-05 16:54:54 -08002566 mDragResizing = dragResizing;
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002567 mDragResizeMode = dragResizeMode;
Jorim Jaggic662d8e2016-02-05 16:54:54 -08002568 resetDragResizingChangeReported();
2569 }
2570 }
2571
Chong Zhang3005e752015-09-18 18:46:28 -07002572 boolean isDragResizing() {
Wale Ogunwaled1c37912016-08-16 03:19:39 -07002573 return mDragResizing;
Chong Zhang3005e752015-09-18 18:46:28 -07002574 }
2575
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002576 int getDragResizeMode() {
2577 return mDragResizeMode;
2578 }
2579
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002580 /**
2581 * Puts this task into docked drag resizing mode. See {@link DragResizeMode}.
2582 *
2583 * @param resizing Whether to put the task into drag resize mode.
2584 */
2585 public void setTaskDockedResizing(boolean resizing) {
2586 setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
2587 }
2588
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002589 void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002590 if (displayContent == null) {
2591 return;
2592 }
Bryce Leef3c6a472017-11-14 14:53:06 -08002593 if (matchParentBounds()) {
Wale Ogunwale68278562017-09-23 17:13:55 -07002594 // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a
2595 // problem once we move mBounds into WindowConfiguration.
Bryce Leef3c6a472017-11-14 14:53:06 -08002596 setBounds(null);
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002597 return;
2598 }
Garfield Tandec96db2018-10-30 11:28:49 -07002599 final int displayId = displayContent.getDisplayId();
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002600 final int newRotation = displayContent.getDisplayInfo().rotation;
Garfield Tandec96db2018-10-30 11:28:49 -07002601 if (displayId != mLastRotationDisplayId) {
2602 // This task is on a display that it wasn't on. There is no point to keep the relative
2603 // position if display rotations for old and new displays are different. Just keep these
2604 // values.
2605 mLastRotationDisplayId = displayId;
2606 mRotation = newRotation;
2607 return;
2608 }
2609
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002610 if (mRotation == newRotation) {
Garfield Tandec96db2018-10-30 11:28:49 -07002611 // Rotation didn't change. We don't need to adjust the bounds to keep the relative
2612 // position.
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002613 return;
2614 }
2615
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002616 // Device rotation changed.
Chong Zhang2e2c81a2016-07-15 11:28:17 -07002617 // - We don't want the task to move around on the screen when this happens, so update the
2618 // task bounds so it stays in the same place.
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002619 // - Rotate the bounds and notify activity manager if the task can be resized independently
Chong Zhang2e2c81a2016-07-15 11:28:17 -07002620 // from its stack. The stack will take care of task rotation for the other case.
Bryce Leef3c6a472017-11-14 14:53:06 -08002621 mTmpRect2.set(getBounds());
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002622
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002623 if (!getWindowConfiguration().canResizeTask()) {
Bryce Leef3c6a472017-11-14 14:53:06 -08002624 setBounds(mTmpRect2);
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002625 return;
2626 }
2627
Wale Ogunwale94744212015-09-21 19:01:47 -07002628 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
Bryce Leef3c6a472017-11-14 14:53:06 -08002629 if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002630 mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
Wale Ogunwale1ed0d892015-09-28 13:27:44 -07002631 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002632 }
2633
Wale Ogunwalef6192862016-09-10 13:42:30 -07002634 /** Cancels any running app transitions associated with the task. */
Winsonc28098f2015-10-30 14:50:19 -07002635 void cancelTaskWindowTransition() {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002636 for (int i = mChildren.size() - 1; i >= 0; --i) {
Jorim Jaggif5f9e122017-10-24 18:21:09 +02002637 mChildren.get(i).cancelAnimation();
Winsonc28098f2015-10-30 14:50:19 -07002638 }
2639 }
2640
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -07002641 boolean showForAllUsers() {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002642 final int tokensCount = mChildren.size();
Wale Ogunwale72919d22016-12-08 18:58:50 -08002643 return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers;
Jorim Jaggiff71d202016-04-14 13:12:36 -07002644 }
2645
Robert Carr7e4c90e2017-02-15 19:52:38 -08002646 /**
2647 * When we are in a floating stack (Freeform, Pinned, ...) we calculate
2648 * insets differently. However if we are animating to the fullscreen stack
2649 * we need to begin calculating insets as if we were fullscreen, otherwise
2650 * we will have a jump at the end.
2651 */
Robert Carre6275582016-02-29 15:45:45 -08002652 boolean isFloating() {
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002653 return getWindowConfiguration().tasksAreFloating()
Wale Ogunwale8577a052019-10-26 23:22:34 -07002654 && !getTaskStack().isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
Robert Carre6275582016-02-29 15:45:45 -08002655 }
2656
Winson Chungd41f71d2018-03-16 15:26:07 -07002657 @Override
2658 public SurfaceControl getAnimationLeashParent() {
Riddle Hsud8302832019-09-23 21:14:07 +08002659 if (WindowManagerService.sHierarchicalAnimations) {
Issei Suzuki71142152019-08-15 14:39:40 +02002660 return super.getAnimationLeashParent();
2661 }
Winson Chung732446a2018-09-19 13:15:17 -07002662 // Currently, only the recents animation will create animation leashes for tasks. In this
2663 // case, reparent the task to the home animation layer while it is being animated to allow
2664 // the home activity to reorder the app windows relative to its own.
2665 return getAppAnimationLayer(ANIMATION_LAYER_HOME);
Winson Chungd41f71d2018-03-16 15:26:07 -07002666 }
2667
lumark19a5d2e2019-10-11 16:19:30 +08002668 boolean shouldAnimate() {
2669 // Don't animate while the task runs recents animation but only if we are in the mode
2670 // where we cancel with deferred screenshot, which means that the controller has
2671 // transformed the task.
2672 final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
2673 if (controller != null && controller.isAnimatingTask(this)
2674 && controller.shouldDeferCancelUntilNextTransition()) {
2675 return false;
2676 }
2677 return true;
2678 }
2679
Evan Rosky9020c072018-12-06 14:11:12 -08002680 @Override
2681 SurfaceControl.Builder makeSurface() {
2682 return super.makeSurface().setMetadata(METADATA_TASK_ID, mTaskId);
2683 }
2684
Winson Chungd41f71d2018-03-16 15:26:07 -07002685 boolean isTaskAnimating() {
Wale Ogunwale8b19de92018-11-29 19:58:26 -08002686 final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController();
Winson Chungd41f71d2018-03-16 15:26:07 -07002687 if (recentsAnim != null) {
2688 if (recentsAnim.isAnimatingTask(this)) {
2689 return true;
2690 }
2691 }
2692 return false;
2693 }
2694
lumark19a5d2e2019-10-11 16:19:30 +08002695 /**
2696 * @return {@code true} if changing app transition is running.
2697 */
2698 @Override
2699 boolean isChangingAppTransition() {
2700 final ActivityRecord activity = getTopVisibleActivity();
2701 return activity != null && getDisplayContent().mChangingApps.contains(activity);
2702 }
2703
2704 @Override
2705 RemoteAnimationTarget createRemoteAnimationTarget(
2706 RemoteAnimationController.RemoteAnimationRecord record) {
2707 final ActivityRecord activity = getTopVisibleActivity();
2708 return activity != null ? activity.createRemoteAnimationTarget(record) : null;
2709 }
2710
Chong Zhangd8ceb852015-11-11 14:53:41 -08002711 WindowState getTopVisibleAppMainWindow() {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002712 final ActivityRecord activity = getTopVisibleActivity();
2713 return activity != null ? activity.findMainWindow() : null;
Chong Zhang9184ec62015-09-24 12:32:21 -07002714 }
2715
Garfield Tane8d84ab2019-10-11 09:49:40 -07002716 ActivityRecord getTopFullscreenActivity() {
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +02002717 for (int i = mChildren.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002718 final ActivityRecord activity = mChildren.get(i);
2719 final WindowState win = activity.findMainWindow();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +02002720 if (win != null && win.mAttrs.isFullscreen()) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002721 return activity;
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +02002722 }
2723 }
2724 return null;
2725 }
2726
Garfield Tane8d84ab2019-10-11 09:49:40 -07002727 ActivityRecord getTopVisibleActivity() {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002728 for (int i = mChildren.size() - 1; i >= 0; i--) {
Issei Suzukie63eac72019-11-14 15:59:15 +01002729 final ActivityRecord token = mChildren.get(i);
2730 // skip hidden (or about to hide) apps
Issei Suzuki1669ea42019-11-06 14:20:59 +01002731 if (!token.mIsExiting && !token.isClientHidden() && token.mVisibleRequested) {
Issei Suzukie63eac72019-11-14 15:59:15 +01002732 return token;
Chong Zhangd8ceb852015-11-11 14:53:41 -08002733 }
2734 }
2735 return null;
Chong Zhangbef461f2015-10-27 11:38:24 -07002736 }
2737
Wale Ogunwale3198da42019-10-10 14:45:03 +02002738 void positionChildAtTop(ActivityRecord child) {
2739 positionChildAt(child, POSITION_TOP);
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002740 }
2741
Wale Ogunwale3198da42019-10-10 14:45:03 +02002742 void positionChildAt(ActivityRecord child, int position) {
2743 if (child == null) {
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002744 Slog.w(TAG_WM,
2745 "Attempted to position of non-existing app");
2746 return;
2747 }
2748
Wale Ogunwale3198da42019-10-10 14:45:03 +02002749 positionChildAt(position, child, false /* includeParents */);
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002750 }
2751
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002752 void forceWindowsScaleable(boolean force) {
Wale Ogunwale8b19de92018-11-29 19:58:26 -08002753 mWmService.openSurfaceTransaction();
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002754 try {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002755 for (int i = mChildren.size() - 1; i >= 0; i--) {
2756 mChildren.get(i).forceWindowsScaleableInTransaction(force);
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002757 }
2758 } finally {
Wale Ogunwale8b19de92018-11-29 19:58:26 -08002759 mWmService.closeSurfaceTransaction("forceWindowsScaleable");
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002760 }
2761 }
2762
Jorim Jaggi829b9cd2017-01-23 16:20:53 +01002763 void setTaskDescription(TaskDescription taskDescription) {
2764 mTaskDescription = taskDescription;
2765 }
2766
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002767 void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002768 mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
2769 mTaskId, snapshot);
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002770 }
2771
Jorim Jaggi829b9cd2017-01-23 16:20:53 +01002772 TaskDescription getTaskDescription() {
2773 return mTaskDescription;
2774 }
2775
Wale Ogunwalef6192862016-09-10 13:42:30 -07002776 @Override
Wale Ogunwale51362492016-09-08 17:49:17 -07002777 boolean fillsParent() {
Bryce Leef3c6a472017-11-14 14:53:06 -08002778 return matchParentBounds() || !getWindowConfiguration().canResizeTask();
Wale Ogunwale51362492016-09-08 17:49:17 -07002779 }
2780
Jorim Jaggi329a5832017-01-05 18:57:12 +01002781 @Override
Jorim Jaggi51304d72017-05-17 17:25:32 +02002782 void forAllTasks(Consumer<Task> callback) {
2783 callback.accept(this);
2784 }
2785
lumarkbc0032a2019-11-01 21:38:13 +08002786 @Override
2787 boolean forAllTasks(ToBooleanFunction<Task> callback) {
2788 return callback.apply(this);
2789 }
2790
Jorim Jaggi50bf59c2018-03-09 17:29:48 +01002791 /**
2792 * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI
2793 * flags. See {@link WindowState#canAffectSystemUiFlags()}.
2794 */
2795 void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) {
2796 mCanAffectSystemUiFlags = canAffectSystemUiFlags;
2797 }
2798
2799 /**
2800 * @see #setCanAffectSystemUiFlags
2801 */
2802 boolean canAffectSystemUiFlags() {
2803 return mCanAffectSystemUiFlags;
2804 }
2805
chaviw87ca63a2018-03-26 14:06:17 -07002806 void dontAnimateDimExit() {
2807 mDimmer.dontAnimateExit();
2808 }
2809
Wale Ogunwale9adfe572016-09-08 20:43:58 -07002810 String getName() {
Louis Changcdec0802019-11-11 11:45:07 +08002811 return "Task=" + mTaskId;
Wale Ogunwale9adfe572016-09-08 20:43:58 -07002812 }
2813
Robert Carr18f622f2017-05-08 11:20:43 -07002814 void clearPreserveNonFloatingState() {
2815 mPreserveNonFloatingState = false;
2816 }
2817
chaviw2fb06bc2018-01-19 17:09:15 -08002818 @Override
Robert Carrf59b8dd2017-10-02 18:58:36 -07002819 Dimmer getDimmer() {
2820 return mDimmer;
2821 }
2822
Filip Gruszczynski0689ae92015-10-01 12:30:31 -07002823 @Override
Robert Carrf59b8dd2017-10-02 18:58:36 -07002824 void prepareSurfaces() {
2825 mDimmer.resetDimStates();
2826 super.prepareSurfaces();
2827 getDimBounds(mTmpDimBoundsRect);
chaviwe07246a2017-12-12 16:18:29 -08002828
2829 // Bounds need to be relative, as the dim layer is a child.
2830 mTmpDimBoundsRect.offsetTo(0, 0);
Robert Carrf59b8dd2017-10-02 18:58:36 -07002831 if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
2832 scheduleAnimation();
2833 }
Filip Gruszczynski0689ae92015-10-01 12:30:31 -07002834 }
2835
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002836 // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged.
2837 void writeToProtoInnerTaskOnly(ProtoOutputStream proto, long fieldId,
Nataniel Borges023ecb52019-01-16 14:15:43 -08002838 @WindowTraceLogLevel int logLevel) {
2839 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
2840 return;
2841 }
2842
Steven Timotiusaf03df62017-07-18 16:56:43 -07002843 final long token = proto.start(fieldId);
Nataniel Borges023ecb52019-01-16 14:15:43 -08002844 super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
Louis Changcdec0802019-11-11 11:45:07 +08002845 proto.write(TaskProto.ID, mTaskId);
Steven Timotiusaf03df62017-07-18 16:56:43 -07002846 for (int i = mChildren.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002847 final ActivityRecord activity = mChildren.get(i);
2848 activity.writeToProto(proto, APP_WINDOW_TOKENS, logLevel);
Steven Timotiusaf03df62017-07-18 16:56:43 -07002849 }
Bryce Leef3c6a472017-11-14 14:53:06 -08002850 proto.write(FILLS_PARENT, matchParentBounds());
Louis Changcdec0802019-11-11 11:45:07 +08002851 getBounds().writeToProto(proto, TaskProto.BOUNDS);
Evan Roskyed6767f2018-10-26 17:21:06 -07002852 mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS);
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002853 if (mSurfaceControl != null) {
2854 proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
2855 proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
2856 }
Steven Timotiusaf03df62017-07-18 16:56:43 -07002857 proto.end(token);
2858 }
2859
Jorim Jaggif5f9e122017-10-24 18:21:09 +02002860 @Override
2861 public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
2862 super.dump(pw, prefix, dumpAll);
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002863 final String doublePrefix = prefix + " ";
2864
2865 pw.println(prefix + "taskId=" + mTaskId);
Bryce Leef3c6a472017-11-14 14:53:06 -08002866 pw.println(doublePrefix + "mBounds=" + getBounds().toShortString());
Wale Ogunwalef6192862016-09-10 13:42:30 -07002867 pw.println(doublePrefix + "appTokens=" + mChildren);
Evan Roskyed6767f2018-10-26 17:21:06 -07002868 pw.println(doublePrefix + "mDisplayedBounds=" + mOverrideDisplayedBounds.toShortString());
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002869
2870 final String triplePrefix = doublePrefix + " ";
Jorim Jaggi153dc9d2018-02-23 13:28:15 +01002871 final String quadruplePrefix = triplePrefix + " ";
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002872
Wale Ogunwalef6192862016-09-10 13:42:30 -07002873 for (int i = mChildren.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002874 final ActivityRecord activity = mChildren.get(i);
2875 pw.println(triplePrefix + "Activity #" + i + " " + activity);
2876 activity.dump(pw, quadruplePrefix, dumpAll);
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002877 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002878 }
Robert Carrf59b8dd2017-10-02 18:58:36 -07002879
Louis Changcdec0802019-11-11 11:45:07 +08002880 /**
2881 * Fills in a {@link TaskInfo} with information from this task.
2882 * @param info the {@link TaskInfo} to fill in
2883 */
2884 void fillTaskInfo(TaskInfo info) {
2885 getNumRunningActivities(mReuseActivitiesReport);
2886 info.userId = mUserId;
2887 info.stackId = getStackId();
2888 info.taskId = mTaskId;
2889 info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
Wale Ogunwale21e06482019-11-18 05:14:15 -08002890 info.isRunning = getTopNonFinishingActivity() != null;
Louis Changcdec0802019-11-11 11:45:07 +08002891 info.baseIntent = new Intent(getBaseIntent());
2892 info.baseActivity = mReuseActivitiesReport.base != null
2893 ? mReuseActivitiesReport.base.intent.getComponent()
2894 : null;
2895 info.topActivity = mReuseActivitiesReport.top != null
2896 ? mReuseActivitiesReport.top.mActivityComponent
2897 : null;
2898 info.origActivity = origActivity;
2899 info.realActivity = realActivity;
2900 info.numActivities = mReuseActivitiesReport.numActivities;
2901 info.lastActiveTime = lastActiveTime;
2902 info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
2903 info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
2904 info.resizeMode = mResizeMode;
2905 info.configuration.setTo(getConfiguration());
2906 }
2907
2908 /**
2909 * Returns a {@link TaskInfo} with information from this task.
2910 */
2911 ActivityManager.RunningTaskInfo getTaskInfo() {
2912 ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
2913 fillTaskInfo(info);
2914 return info;
2915 }
2916
2917 void dump(PrintWriter pw, String prefix) {
2918 pw.print(prefix); pw.print("userId="); pw.print(mUserId);
2919 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
2920 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
2921 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
2922 pw.print(" mCallingPackage="); pw.println(mCallingPackage);
2923 if (affinity != null || rootAffinity != null) {
2924 pw.print(prefix); pw.print("affinity="); pw.print(affinity);
2925 if (affinity == null || !affinity.equals(rootAffinity)) {
2926 pw.print(" root="); pw.println(rootAffinity);
2927 } else {
2928 pw.println();
2929 }
2930 }
2931 if (voiceSession != null || voiceInteractor != null) {
2932 pw.print(prefix); pw.print("VOICE: session=0x");
2933 pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
2934 pw.print(" interactor=0x");
2935 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
2936 }
2937 if (intent != null) {
2938 StringBuilder sb = new StringBuilder(128);
2939 sb.append(prefix); sb.append("intent={");
2940 intent.toShortString(sb, false, true, false, false);
2941 sb.append('}');
2942 pw.println(sb.toString());
2943 }
2944 if (affinityIntent != null) {
2945 StringBuilder sb = new StringBuilder(128);
2946 sb.append(prefix); sb.append("affinityIntent={");
2947 affinityIntent.toShortString(sb, false, true, false, false);
2948 sb.append('}');
2949 pw.println(sb.toString());
2950 }
2951 if (origActivity != null) {
2952 pw.print(prefix); pw.print("origActivity=");
2953 pw.println(origActivity.flattenToShortString());
2954 }
2955 if (realActivity != null) {
2956 pw.print(prefix); pw.print("mActivityComponent=");
2957 pw.println(realActivity.flattenToShortString());
2958 }
Wale Ogunwale7a8889a2019-11-16 08:23:42 -08002959 if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) {
Louis Changcdec0802019-11-11 11:45:07 +08002960 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
2961 pw.print(" isPersistable="); pw.print(isPersistable);
Louis Changcdec0802019-11-11 11:45:07 +08002962 pw.print(" activityType="); pw.println(getActivityType());
2963 }
2964 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
2965 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
2966 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
2967 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
2968 pw.print(" mReuseTask="); pw.print(mReuseTask);
2969 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
2970 }
2971 if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
2972 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
2973 || mNextAffiliate != null) {
2974 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
2975 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
2976 pw.print(" (");
2977 if (mPrevAffiliate == null) {
2978 pw.print("null");
2979 } else {
2980 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
2981 }
2982 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
2983 pw.print(" (");
2984 if (mNextAffiliate == null) {
2985 pw.print("null");
2986 } else {
2987 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
2988 }
2989 pw.println(")");
2990 }
2991 pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
2992 if (!askedCompatMode || !inRecents || !isAvailable) {
2993 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
2994 pw.print(" inRecents="); pw.print(inRecents);
2995 pw.print(" isAvailable="); pw.println(isAvailable);
2996 }
2997 if (lastDescription != null) {
2998 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
2999 }
3000 if (mRootProcess != null) {
3001 pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
3002 }
3003 pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
3004 pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
3005 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
3006 pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
3007 pw.print(" isResizeable=" + isResizeable());
3008 pw.print(" lastActiveTime=" + lastActiveTime);
3009 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
3010 }
3011
3012 @Override
3013 public String toString() {
3014 StringBuilder sb = new StringBuilder(128);
3015 if (stringName != null) {
3016 sb.append(stringName);
3017 sb.append(" U=");
3018 sb.append(mUserId);
3019 sb.append(" StackId=");
3020 sb.append(getStackId());
3021 sb.append(" sz=");
3022 sb.append(getChildCount());
3023 sb.append('}');
3024 return sb.toString();
3025 }
3026 sb.append("Task{");
3027 sb.append(Integer.toHexString(System.identityHashCode(this)));
3028 sb.append(" #");
3029 sb.append(mTaskId);
3030 if (affinity != null) {
3031 sb.append(" A=");
3032 sb.append(affinity);
3033 } else if (intent != null) {
3034 sb.append(" I=");
3035 sb.append(intent.getComponent().flattenToShortString());
3036 } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
3037 sb.append(" aI=");
3038 sb.append(affinityIntent.getComponent().flattenToShortString());
3039 } else {
3040 sb.append(" ??");
3041 }
3042 stringName = sb.toString();
3043 return toString();
3044 }
3045
3046 @Override
3047 public void writeToProto(ProtoOutputStream proto, long fieldId,
3048 @WindowTraceLogLevel int logLevel) {
3049 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
3050 return;
3051 }
3052
3053 final long token = proto.start(fieldId);
3054 writeToProtoInnerTaskOnly(proto, TASK, logLevel);
3055 proto.write(com.android.server.am.TaskRecordProto.ID, mTaskId);
3056 for (int i = getChildCount() - 1; i >= 0; i--) {
3057 final ActivityRecord activity = getChildAt(i);
3058 activity.writeToProto(proto, ACTIVITIES);
3059 }
3060 proto.write(STACK_ID, getStackId());
3061 if (mLastNonFullscreenBounds != null) {
3062 mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
3063 }
3064 if (realActivity != null) {
3065 proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
3066 }
3067 if (origActivity != null) {
3068 proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
3069 }
3070 proto.write(ACTIVITY_TYPE, getActivityType());
3071 proto.write(RESIZE_MODE, mResizeMode);
3072 // TODO: Remove, no longer needed with windowingMode.
3073 proto.write(FULLSCREEN, matchParentBounds());
3074
3075 if (!matchParentBounds()) {
3076 final Rect bounds = getRequestedOverrideBounds();
3077 bounds.writeToProto(proto, com.android.server.am.TaskRecordProto.BOUNDS);
3078 }
3079 proto.write(MIN_WIDTH, mMinWidth);
3080 proto.write(MIN_HEIGHT, mMinHeight);
3081 proto.end(token);
3082 }
3083
3084 /** @see #getNumRunningActivities(TaskActivitiesReport) */
3085 static class TaskActivitiesReport {
3086 int numRunning;
3087 int numActivities;
3088 ActivityRecord top;
3089 ActivityRecord base;
3090
3091 void reset() {
3092 numRunning = numActivities = 0;
3093 top = base = null;
3094 }
3095 }
3096
3097 /**
3098 * Saves this {@link Task} to XML using given serializer.
3099 */
3100 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
3101 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
3102
3103 out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
3104 if (realActivity != null) {
3105 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
3106 }
3107 out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
3108 if (origActivity != null) {
3109 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
3110 }
3111 // Write affinity, and root affinity if it is different from affinity.
3112 // We use the special string "@" for a null root affinity, so we can identify
3113 // later whether we were given a root affinity or should just make it the
3114 // same as the affinity.
3115 if (affinity != null) {
3116 out.attribute(null, ATTR_AFFINITY, affinity);
3117 if (!affinity.equals(rootAffinity)) {
3118 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
3119 }
3120 } else if (rootAffinity != null) {
3121 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
3122 }
3123 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
3124 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
3125 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
3126 out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
3127 out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
3128 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
3129 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
3130 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
3131 if (lastDescription != null) {
3132 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
3133 }
3134 if (getTaskDescription() != null) {
3135 getTaskDescription().saveToXml(out);
3136 }
3137 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
3138 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
3139 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
3140 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
3141 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
3142 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
3143 out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
3144 out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
3145 String.valueOf(mSupportsPictureInPicture));
3146 if (mLastNonFullscreenBounds != null) {
3147 out.attribute(
3148 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
3149 }
3150 out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
3151 out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
3152 out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
3153
3154 if (affinityIntent != null) {
3155 out.startTag(null, TAG_AFFINITYINTENT);
3156 affinityIntent.saveToXml(out);
3157 out.endTag(null, TAG_AFFINITYINTENT);
3158 }
3159
3160 if (intent != null) {
3161 out.startTag(null, TAG_INTENT);
3162 intent.saveToXml(out);
3163 out.endTag(null, TAG_INTENT);
3164 }
3165
3166 final int numActivities = getChildCount();
3167 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
3168 final ActivityRecord r = getChildAt(activityNdx);
3169 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
3170 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
3171 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
3172 && activityNdx > 0) {
3173 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
3174 break;
3175 }
3176 out.startTag(null, TAG_ACTIVITY);
3177 r.saveToXml(out);
3178 out.endTag(null, TAG_ACTIVITY);
3179 }
3180 }
3181
3182 @VisibleForTesting
3183 static TaskFactory getTaskFactory() {
3184 if (sTaskFactory == null) {
3185 setTaskFactory(new TaskFactory());
3186 }
3187 return sTaskFactory;
3188 }
3189
3190 static void setTaskFactory(TaskFactory factory) {
3191 sTaskFactory = factory;
3192 }
3193
3194 static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3195 Intent intent, IVoiceInteractionSession voiceSession,
3196 IVoiceInteractor voiceInteractor, ActivityStack stack) {
3197 return getTaskFactory().create(
3198 service, taskId, info, intent, voiceSession, voiceInteractor, stack);
3199 }
3200
3201 static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3202 Intent intent, TaskDescription taskDescription, ActivityStack stack) {
3203 return getTaskFactory().create(service, taskId, info, intent, taskDescription, stack);
3204 }
3205
3206 static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
3207 throws IOException, XmlPullParserException {
3208 return getTaskFactory().restoreFromXml(in, stackSupervisor);
3209 }
3210
3211 /**
3212 * A factory class used to create {@link Task} or its subclass if any. This can be
3213 * specified when system boots by setting it with
3214 * {@link #setTaskFactory(TaskFactory)}.
3215 */
3216 static class TaskFactory {
3217
3218 Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3219 Intent intent, IVoiceInteractionSession voiceSession,
3220 IVoiceInteractor voiceInteractor, ActivityStack stack) {
3221 return new Task(service, taskId, info, intent, voiceSession, voiceInteractor,
3222 null /*taskDescription*/, stack);
3223 }
3224
3225 Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3226 Intent intent, TaskDescription taskDescription, ActivityStack stack) {
3227 return new Task(service, taskId, info, intent, null /*voiceSession*/,
3228 null /*voiceInteractor*/, taskDescription, stack);
3229 }
3230
3231 /**
3232 * Should only be used when we're restoring {@link Task} from storage.
3233 */
3234 Task create(ActivityTaskManagerService service, int taskId, Intent intent,
3235 Intent affinityIntent, String affinity, String rootAffinity,
3236 ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
3237 boolean autoRemoveRecents, boolean askedCompatMode, int userId,
3238 int effectiveUid, String lastDescription,
3239 long lastTimeMoved, boolean neverRelinquishIdentity,
3240 TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
3241 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
3242 int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
3243 boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
3244 return new Task(service, taskId, intent, affinityIntent, affinity,
3245 rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
3246 askedCompatMode, userId, effectiveUid, lastDescription,
3247 lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
3248 prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
3249 resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
3250 minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
3251 null /*_voiceInteractor*/, stack);
3252 }
3253
3254 Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
3255 throws IOException, XmlPullParserException {
3256 Intent intent = null;
3257 Intent affinityIntent = null;
3258 ArrayList<ActivityRecord> activities = new ArrayList<>();
3259 ComponentName realActivity = null;
3260 boolean realActivitySuspended = false;
3261 ComponentName origActivity = null;
3262 String affinity = null;
3263 String rootAffinity = null;
3264 boolean hasRootAffinity = false;
3265 boolean rootHasReset = false;
3266 boolean autoRemoveRecents = false;
3267 boolean askedCompatMode = false;
3268 int taskType = 0;
3269 int userId = 0;
3270 boolean userSetupComplete = true;
3271 int effectiveUid = -1;
3272 String lastDescription = null;
3273 long lastTimeOnTop = 0;
3274 boolean neverRelinquishIdentity = true;
3275 int taskId = INVALID_TASK_ID;
3276 final int outerDepth = in.getDepth();
3277 TaskDescription taskDescription = new TaskDescription();
3278 int taskAffiliation = INVALID_TASK_ID;
3279 int taskAffiliationColor = 0;
3280 int prevTaskId = INVALID_TASK_ID;
3281 int nextTaskId = INVALID_TASK_ID;
3282 int callingUid = -1;
3283 String callingPackage = "";
3284 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
3285 boolean supportsPictureInPicture = false;
3286 Rect lastNonFullscreenBounds = null;
3287 int minWidth = INVALID_MIN_SIZE;
3288 int minHeight = INVALID_MIN_SIZE;
3289 int persistTaskVersion = 0;
3290
3291 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
3292 final String attrName = in.getAttributeName(attrNdx);
3293 final String attrValue = in.getAttributeValue(attrNdx);
3294 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: attribute name="
3295 + attrName + " value=" + attrValue);
3296 switch (attrName) {
3297 case ATTR_TASKID:
3298 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
3299 break;
3300 case ATTR_REALACTIVITY:
3301 realActivity = ComponentName.unflattenFromString(attrValue);
3302 break;
3303 case ATTR_REALACTIVITY_SUSPENDED:
3304 realActivitySuspended = Boolean.valueOf(attrValue);
3305 break;
3306 case ATTR_ORIGACTIVITY:
3307 origActivity = ComponentName.unflattenFromString(attrValue);
3308 break;
3309 case ATTR_AFFINITY:
3310 affinity = attrValue;
3311 break;
3312 case ATTR_ROOT_AFFINITY:
3313 rootAffinity = attrValue;
3314 hasRootAffinity = true;
3315 break;
3316 case ATTR_ROOTHASRESET:
3317 rootHasReset = Boolean.parseBoolean(attrValue);
3318 break;
3319 case ATTR_AUTOREMOVERECENTS:
3320 autoRemoveRecents = Boolean.parseBoolean(attrValue);
3321 break;
3322 case ATTR_ASKEDCOMPATMODE:
3323 askedCompatMode = Boolean.parseBoolean(attrValue);
3324 break;
3325 case ATTR_USERID:
3326 userId = Integer.parseInt(attrValue);
3327 break;
3328 case ATTR_USER_SETUP_COMPLETE:
3329 userSetupComplete = Boolean.parseBoolean(attrValue);
3330 break;
3331 case ATTR_EFFECTIVE_UID:
3332 effectiveUid = Integer.parseInt(attrValue);
3333 break;
3334 case ATTR_TASKTYPE:
3335 taskType = Integer.parseInt(attrValue);
3336 break;
3337 case ATTR_LASTDESCRIPTION:
3338 lastDescription = attrValue;
3339 break;
3340 case ATTR_LASTTIMEMOVED:
3341 lastTimeOnTop = Long.parseLong(attrValue);
3342 break;
3343 case ATTR_NEVERRELINQUISH:
3344 neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
3345 break;
3346 case ATTR_TASK_AFFILIATION:
3347 taskAffiliation = Integer.parseInt(attrValue);
3348 break;
3349 case ATTR_PREV_AFFILIATION:
3350 prevTaskId = Integer.parseInt(attrValue);
3351 break;
3352 case ATTR_NEXT_AFFILIATION:
3353 nextTaskId = Integer.parseInt(attrValue);
3354 break;
3355 case ATTR_TASK_AFFILIATION_COLOR:
3356 taskAffiliationColor = Integer.parseInt(attrValue);
3357 break;
3358 case ATTR_CALLING_UID:
3359 callingUid = Integer.parseInt(attrValue);
3360 break;
3361 case ATTR_CALLING_PACKAGE:
3362 callingPackage = attrValue;
3363 break;
3364 case ATTR_RESIZE_MODE:
3365 resizeMode = Integer.parseInt(attrValue);
3366 break;
3367 case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
3368 supportsPictureInPicture = Boolean.parseBoolean(attrValue);
3369 break;
3370 case ATTR_NON_FULLSCREEN_BOUNDS:
3371 lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
3372 break;
3373 case ATTR_MIN_WIDTH:
3374 minWidth = Integer.parseInt(attrValue);
3375 break;
3376 case ATTR_MIN_HEIGHT:
3377 minHeight = Integer.parseInt(attrValue);
3378 break;
3379 case ATTR_PERSIST_TASK_VERSION:
3380 persistTaskVersion = Integer.parseInt(attrValue);
3381 break;
3382 default:
3383 if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
3384 taskDescription.restoreFromXml(attrName, attrValue);
3385 } else {
3386 Slog.w(TAG, "Task: Unknown attribute=" + attrName);
3387 }
3388 }
3389 }
3390
3391 int event;
3392 while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
3393 && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
3394 if (event == XmlPullParser.START_TAG) {
3395 final String name = in.getName();
3396 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
3397 "Task: START_TAG name=" + name);
3398 if (TAG_AFFINITYINTENT.equals(name)) {
3399 affinityIntent = Intent.restoreFromXml(in);
3400 } else if (TAG_INTENT.equals(name)) {
3401 intent = Intent.restoreFromXml(in);
3402 } else if (TAG_ACTIVITY.equals(name)) {
3403 ActivityRecord activity =
3404 ActivityRecord.restoreFromXml(in, stackSupervisor);
3405 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: activity="
3406 + activity);
3407 if (activity != null) {
3408 activities.add(activity);
3409 }
3410 } else {
3411 handleUnknownTag(name, in);
3412 }
3413 }
3414 }
3415 if (!hasRootAffinity) {
3416 rootAffinity = affinity;
3417 } else if ("@".equals(rootAffinity)) {
3418 rootAffinity = null;
3419 }
3420 if (effectiveUid <= 0) {
3421 Intent checkIntent = intent != null ? intent : affinityIntent;
3422 effectiveUid = 0;
3423 if (checkIntent != null) {
3424 IPackageManager pm = AppGlobals.getPackageManager();
3425 try {
3426 ApplicationInfo ai = pm.getApplicationInfo(
3427 checkIntent.getComponent().getPackageName(),
3428 PackageManager.MATCH_UNINSTALLED_PACKAGES
3429 | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
3430 if (ai != null) {
3431 effectiveUid = ai.uid;
3432 }
3433 } catch (RemoteException e) {
3434 }
3435 }
3436 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
3437 + ": effectiveUid=" + effectiveUid);
3438 }
3439
3440 if (persistTaskVersion < 1) {
3441 // We need to convert the resize mode of home activities saved before version one if
3442 // they are marked as RESIZE_MODE_RESIZEABLE to
3443 // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
3444 // before version 1 and the system didn't resize home activities before then.
3445 if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
3446 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
3447 }
3448 } else {
3449 // This activity has previously marked itself explicitly as both resizeable and
3450 // supporting picture-in-picture. Since there is no longer a requirement for
3451 // picture-in-picture activities to be resizeable, we can mark this simply as
3452 // resizeable and supporting picture-in-picture separately.
3453 if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
3454 resizeMode = RESIZE_MODE_RESIZEABLE;
3455 supportsPictureInPicture = true;
3456 }
3457 }
3458
3459 final Task task = create(stackSupervisor.mService,
3460 taskId, intent, affinityIntent,
3461 affinity, rootAffinity, realActivity, origActivity, rootHasReset,
3462 autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
3463 lastTimeOnTop, neverRelinquishIdentity, taskDescription,
3464 taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
3465 callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
3466 userSetupComplete, minWidth, minHeight, null /*stack*/);
3467 task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
3468 task.setBounds(lastNonFullscreenBounds);
3469
3470 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
3471 task.addChild(activities.get(activityNdx));
3472 }
3473
3474 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
3475 return task;
3476 }
3477
3478 void handleUnknownTag(String name, XmlPullParser in)
3479 throws IOException, XmlPullParserException {
3480 Slog.e(TAG, "restoreTask: Unexpected name=" + name);
3481 XmlUtils.skipCurrentTag(in);
3482 }
Robert Carrf59b8dd2017-10-02 18:58:36 -07003483 }
Craig Mautnerb1fd65c02013-02-05 13:34:57 -08003484}