blob: 0e07e526faac0a8b2bbb5c05cedc0a1b49b9f749 [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
Louis Changcdec0802019-11-11 11:45:07 +080059import static com.android.server.am.TaskRecordProto.ACTIVITIES;
60import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
Louis Changcdec0802019-11-11 11:45:07 +080061import static com.android.server.am.TaskRecordProto.FULLSCREEN;
Louis Changcdec0802019-11-11 11:45:07 +080062import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
63import static com.android.server.am.TaskRecordProto.MIN_HEIGHT;
64import static com.android.server.am.TaskRecordProto.MIN_WIDTH;
65import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
66import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
67import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
68import static com.android.server.am.TaskRecordProto.STACK_ID;
69import static com.android.server.am.TaskRecordProto.TASK;
Louis Changcdec0802019-11-11 11:45:07 +080070import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
71import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
72import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
73import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
74import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
75import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
76import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
77import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
78import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
79import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
80import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
81import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
82import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
83import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
Yunfan Chen0e7aff92018-12-05 16:35:32 -080084import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
Louis Changcdec0802019-11-11 11:45:07 +080085import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070086import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS;
Evan Roskyed6767f2018-10-26 17:21:06 -070087import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070088import static com.android.server.wm.TaskProto.FILLS_PARENT;
Louis Chang7501e332018-08-20 13:08:39 +080089import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
90import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070091import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
lumark9bca6b42019-10-17 18:35:22 +080092import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
93import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
chaviw8c9d1f52018-07-25 14:56:07 -070094import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
chaviw8c9d1f52018-07-25 14:56:07 -070095import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Wale Ogunwale99db1862015-10-23 20:08:22 -070096
Louis Changcdec0802019-11-11 11:45:07 +080097import static java.lang.Integer.MAX_VALUE;
98
99import android.annotation.IntDef;
100import android.annotation.NonNull;
101import android.annotation.Nullable;
102import android.app.Activity;
Yunfan Chen0e7aff92018-12-05 16:35:32 -0800103import android.app.ActivityManager;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100104import android.app.ActivityManager.TaskDescription;
Louis Changcdec0802019-11-11 11:45:07 +0800105import android.app.ActivityManager.TaskSnapshot;
106import android.app.ActivityOptions;
107import android.app.ActivityTaskManager;
108import android.app.AppGlobals;
109import android.app.TaskInfo;
110import android.app.WindowConfiguration;
111import android.content.ComponentName;
112import android.content.Intent;
Wale Ogunwaleb1faf602016-01-27 09:12:31 -0800113import android.content.pm.ActivityInfo;
Louis Changcdec0802019-11-11 11:45:07 +0800114import android.content.pm.ApplicationInfo;
115import android.content.pm.IPackageManager;
116import android.content.pm.PackageManager;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700117import android.content.res.Configuration;
118import android.graphics.Rect;
Louis Changcdec0802019-11-11 11:45:07 +0800119import android.os.Debug;
Garfield Tan90b04282018-12-11 14:04:42 -0800120import android.os.IBinder;
Louis Changcdec0802019-11-11 11:45:07 +0800121import android.os.RemoteException;
122import android.os.SystemClock;
123import android.os.Trace;
124import android.os.UserHandle;
125import android.provider.Settings;
126import android.service.voice.IVoiceInteractionSession;
127import android.util.DisplayMetrics;
Craig Mautner42bf39e2014-02-21 16:46:22 -0800128import android.util.Slog;
Steven Timotiusaf03df62017-07-18 16:56:43 -0700129import android.util.proto.ProtoOutputStream;
Garfield Tandec96db2018-10-30 11:28:49 -0700130import android.view.Display;
Louis Changcdec0802019-11-11 11:45:07 +0800131import android.view.DisplayInfo;
lumark19a5d2e2019-10-11 16:19:30 +0800132import android.view.RemoteAnimationTarget;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700133import android.view.Surface;
Winson Chungd41f71d2018-03-16 15:26:07 -0700134import android.view.SurfaceControl;
chaviw8c9d1f52018-07-25 14:56:07 -0700135
Wale Ogunwalec5cc3012017-01-13 13:26:16 -0800136import com.android.internal.annotations.VisibleForTesting;
Louis Changcdec0802019-11-11 11:45:07 +0800137import com.android.internal.app.IVoiceInteractor;
lumarkbc0032a2019-11-01 21:38:13 +0800138import com.android.internal.util.ToBooleanFunction;
Louis Changcdec0802019-11-11 11:45:07 +0800139import com.android.internal.util.XmlUtils;
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800140import com.android.internal.util.function.pooled.PooledConsumer;
141import com.android.internal.util.function.pooled.PooledFunction;
142import com.android.internal.util.function.pooled.PooledLambda;
143import com.android.internal.util.function.pooled.PooledPredicate;
Louis Changcdec0802019-11-11 11:45:07 +0800144import 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 Ogunwale85fb19a2019-12-05 10:41:05 +0900158import java.util.function.Function;
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800159import java.util.function.Predicate;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700160
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800161class Task extends WindowContainer<WindowContainer> {
Louis Changcdec0802019-11-11 11:45:07 +0800162 private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM;
163 private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
164 private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
165 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
166 private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
167
168 private static final String ATTR_TASKID = "task_id";
169 private static final String TAG_INTENT = "intent";
170 private static final String TAG_AFFINITYINTENT = "affinity_intent";
171 private static final String ATTR_REALACTIVITY = "real_activity";
172 private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
173 private static final String ATTR_ORIGACTIVITY = "orig_activity";
174 private static final String TAG_ACTIVITY = "activity";
175 private static final String ATTR_AFFINITY = "affinity";
176 private static final String ATTR_ROOT_AFFINITY = "root_affinity";
177 private static final String ATTR_ROOTHASRESET = "root_has_reset";
178 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
179 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
180 private static final String ATTR_USERID = "user_id";
181 private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
182 private static final String ATTR_EFFECTIVE_UID = "effective_uid";
183 @Deprecated
184 private static final String ATTR_TASKTYPE = "task_type";
185 private static final String ATTR_LASTDESCRIPTION = "last_description";
186 private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
187 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
188 private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
189 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
190 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
191 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
192 private static final String ATTR_CALLING_UID = "calling_uid";
193 private static final String ATTR_CALLING_PACKAGE = "calling_package";
194 private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
195 private static final String ATTR_RESIZE_MODE = "resize_mode";
196 private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
197 private static final String ATTR_MIN_WIDTH = "min_width";
198 private static final String ATTR_MIN_HEIGHT = "min_height";
199 private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
200
201 // Current version of the task record we persist. Used to check if we need to run any upgrade
202 // code.
203 private static final int PERSIST_TASK_VERSION = 1;
204
205 private static final int INVALID_MIN_SIZE = -1;
206
207 /**
208 * The modes to control how the stack is moved to the front when calling {@link Task#reparent}.
209 */
210 @Retention(RetentionPolicy.SOURCE)
211 @IntDef({
212 REPARENT_MOVE_STACK_TO_FRONT,
213 REPARENT_KEEP_STACK_AT_FRONT,
214 REPARENT_LEAVE_STACK_IN_PLACE
215 })
216 @interface ReparentMoveStackMode {}
217 // Moves the stack to the front if it was not at the front
218 static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
219 // Only moves the stack to the front if it was focused or front most already
220 static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
221 // Do not move the stack as a part of reparenting
222 static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
223
224 /**
225 * The factory used to create {@link Task}. This allows OEM subclass {@link Task}.
226 */
227 private static TaskFactory sTaskFactory;
228
229 String affinity; // The affinity name for this task, or null; may change identity.
230 String rootAffinity; // Initial base affinity, or null; does not change from initial root.
231 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
232 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
233 Intent intent; // The original intent that started the task. Note that this value can
234 // be null.
235 Intent affinityIntent; // Intent of affinity-moved activity that started this task.
236 int effectiveUid; // The current effective uid of the identity of this task.
237 ComponentName origActivity; // The non-alias activity component of the intent.
238 ComponentName realActivity; // The actual activity component that started the task.
239 boolean realActivitySuspended; // True if the actual activity component that started the
240 // task is suspended.
241 boolean inRecents; // Actually in the recents list?
242 long lastActiveTime; // Last time this task was active in the current device session,
243 // including sleep. This time is initialized to the elapsed time when
244 // restored from disk.
245 boolean isAvailable; // Is the activity available to be launched?
246 boolean rootWasReset; // True if the intent at the root of the task had
247 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
248 boolean autoRemoveRecents; // If true, we should automatically remove the task from
249 // recents when activity finishes
250 boolean askedCompatMode;// Have asked the user about compat mode for this task.
251 boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
252
253 String stringName; // caching of toString() result.
254 boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
255 // was changed.
256
Louis Changcdec0802019-11-11 11:45:07 +0800257 /** Can't be put in lockTask mode. */
258 final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
259 /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
260 final static int LOCK_TASK_AUTH_PINNABLE = 1;
261 /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
262 final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
263 /** Can enter lockTask without user approval. Can start over existing lockTask task. */
264 final static int LOCK_TASK_AUTH_WHITELISTED = 3;
265 /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
266 * lockTask task. */
267 final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
268 int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
269
270 int mLockTaskUid = -1; // The uid of the application that called startLockTask().
271
272 /** Current stack. Setter must always be used to update the value. */
273 private ActivityStack mStack;
274
275 /** The process that had previously hosted the root activity of this task.
276 * Used to know that we should try harder to keep this process around, in case the
277 * user wants to return to it. */
278 private WindowProcessController mRootProcess;
279
280 /** Takes on same value as first root activity */
281 boolean isPersistable = false;
282 int maxRecents;
283
284 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
285 * determining the order when restoring. Sign indicates whether last task movement was to front
286 * (positive) or back (negative). Absolute value indicates time. */
287 long mLastTimeMoved;
288
289 /** If original intent did not allow relinquishing task identity, save that information */
290 private boolean mNeverRelinquishIdentity = true;
291
292 // Used in the unique case where we are clearing the task in order to reuse it. In that case we
293 // do not want to delete the stack when the task goes empty.
294 private boolean mReuseTask = false;
295
296 CharSequence lastDescription; // Last description captured for this item.
297
298 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
299 int mAffiliatedTaskColor; // color of the parent task affiliation.
300 Task mPrevAffiliate; // previous task in affiliated chain.
301 int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
302 Task mNextAffiliate; // next task in affiliated chain.
303 int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
304
305 // For relaunching the task from recents as though it was launched by the original launcher.
306 int mCallingUid;
307 String mCallingPackage;
308
309 private final Rect mTmpStableBounds = new Rect();
310 private final Rect mTmpNonDecorBounds = new Rect();
311 private final Rect mTmpBounds = new Rect();
312 private final Rect mTmpInsets = new Rect();
Evan Rosky70213702019-11-05 10:26:24 -0800313 private final Rect mTmpFullBounds = new Rect();
Louis Changcdec0802019-11-11 11:45:07 +0800314
315 // Last non-fullscreen bounds the task was launched in or resized to.
316 // The information is persisted and used to determine the appropriate stack to launch the
317 // task into on restore.
318 Rect mLastNonFullscreenBounds = null;
319 // Minimal width and height of this task when it's resizeable. -1 means it should use the
320 // default minimal width/height.
321 int mMinWidth;
322 int mMinHeight;
323
324 // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
325 // This number will be assigned when we evaluate OOM scores for all visible tasks.
326 int mLayerRank = -1;
327
328 /** Helper object used for updating override configuration. */
329 private Configuration mTmpConfig = new Configuration();
330
331 /** Used by fillTaskInfo */
332 final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
Wale Ogunwale2cc92f52015-09-09 13:12:10 -0700333
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200334 final ActivityTaskManagerService mAtmService;
335
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700336 /* Unique identifier for this task. */
Craig Mautner83162a92015-01-26 14:43:30 -0800337 final int mTaskId;
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700338 /* User for which this task was created. */
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200339 // TODO: Make final
340 int mUserId;
Craig Mautnerb1fd65c02013-02-05 13:34:57 -0800341
Jorim Jaggi0429f352015-12-22 16:29:16 +0100342 final Rect mPreparedFrozenBounds = new Rect();
Jorim Jaggi26c8c422016-05-09 19:57:25 -0700343 final Configuration mPreparedFrozenMergedConfig = new Configuration();
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700344
Evan Roskyed6767f2018-10-26 17:21:06 -0700345 // If non-empty, bounds used to display the task during animations/interactions.
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200346 // TODO(b/119687367): This member is temporary.
Evan Roskyed6767f2018-10-26 17:21:06 -0700347 private final Rect mOverrideDisplayedBounds = new Rect();
Jorim Jaggidc249c42015-12-15 14:57:31 -0800348
Garfield Tandec96db2018-10-30 11:28:49 -0700349 /** ID of the display which rotation {@link #mRotation} has. */
350 private int mLastRotationDisplayId = Display.INVALID_DISPLAY;
351 /**
352 * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was
353 * moved to a new display.
354 */
Wale Ogunwale3eadad72016-10-13 09:16:59 -0700355 private int mRotation;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700356
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700357 // For comparison with DisplayContent bounds.
358 private Rect mTmpRect = new Rect();
359 // For handling display rotations.
360 private Rect mTmpRect2 = new Rect();
361
Wale Ogunwaleb1faf602016-01-27 09:12:31 -0800362 // Resize mode of the task. See {@link ActivityInfo#resizeMode}
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200363 // Based on the {@link ActivityInfo#resizeMode} of the root activity.
364 int mResizeMode;
Chong Zhangb15758a2015-11-17 12:12:03 -0800365
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200366 // Whether or not this task and its activities support PiP. Based on the
367 // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity.
368 boolean mSupportsPictureInPicture;
Winson Chungd3395382016-12-13 11:49:09 -0800369
Chong Zhang3005e752015-09-18 18:46:28 -0700370 // Whether the task is currently being drag-resized
371 private boolean mDragResizing;
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +0100372 private int mDragResizeMode;
Chong Zhang3005e752015-09-18 18:46:28 -0700373
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700374 // This represents the last resolved activity values for this task
375 // NOTE: This value needs to be persisted with each task
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100376 private TaskDescription mTaskDescription;
377
Robert Carr18f622f2017-05-08 11:20:43 -0700378 // If set to true, the task will report that it is not in the floating
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700379 // state regardless of it's stack affiliation. As the floating state drives
Robert Carr18f622f2017-05-08 11:20:43 -0700380 // production of content insets this can be used to preserve them across
381 // stack moves and we in fact do so when moving from full screen to pinned.
382 private boolean mPreserveNonFloatingState = false;
383
Robert Carrf59b8dd2017-10-02 18:58:36 -0700384 private Dimmer mDimmer = new Dimmer(this);
385 private final Rect mTmpDimBoundsRect = new Rect();
386
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100387 /** @see #setCanAffectSystemUiFlags */
388 private boolean mCanAffectSystemUiFlags = true;
389
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800390 private static Exception sTmpException;
391
392 private final FindRootHelper mFindRootHelper = new FindRootHelper();
393 private class FindRootHelper {
394 private ActivityRecord mRoot;
395
396 private void clear() {
397 mRoot = null;
398 }
399
400 ActivityRecord findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
401 final PooledFunction f = PooledLambda.obtainFunction(FindRootHelper::processActivity,
402 this, PooledLambda.__(ActivityRecord.class), ignoreRelinquishIdentity,
403 setToBottomIfNone);
404 clear();
405 forAllActivities(f, false /*traverseTopToBottom*/);
406 f.recycle();
407 return mRoot;
408 }
409
410 private boolean processActivity(ActivityRecord r,
411 boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
412 if (mRoot == null && setToBottomIfNone) {
413 // This is the first activity we are process. Set it as the candidate root in case
414 // we don't find a better one.
415 mRoot = r;
416 }
417
418 if (r.finishing) return false;
419
420 // Set this as the candidate root since it isn't finishing.
421 mRoot = r;
422
423 // Only end search if we are ignore relinquishing identity or we are not relinquishing.
424 return ignoreRelinquishIdentity || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
425 }
426 }
427
Louis Changcdec0802019-11-11 11:45:07 +0800428 /**
429 * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
430 * ActivityInfo, Intent, TaskDescription)} instead.
431 */
432 Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
433 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
434 TaskDescription _taskDescription, ActivityStack stack) {
435 this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/,
436 null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
437 false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
438 UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
439 null /*_lastDescription*/, System.currentTimeMillis(),
440 true /*neverRelinquishIdentity*/,
441 _taskDescription != null ? _taskDescription : new TaskDescription(),
442 _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
443 info.applicationInfo.uid, info.packageName, info.resizeMode,
444 info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
445 false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
446 _voiceSession, _voiceInteractor, stack);
447 }
448
449 /** Don't use constructor directly. This is only used by XML parser. */
450 Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
451 Intent _affinityIntent, String _affinity, String _rootAffinity,
452 ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
453 boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
454 int _effectiveUid, String _lastDescription,
455 long lastTimeMoved, boolean neverRelinquishIdentity,
456 TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
457 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
458 int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
459 boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
460 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
461 ActivityStack stack) {
462 super(atmService.mWindowManager);
463
Jeff Changd136e772019-11-05 20:33:52 +0800464 EventLogTags.writeWmTaskCreated(_taskId, stack != null ? stack.mStackId : INVALID_STACK_ID);
Louis Changcdec0802019-11-11 11:45:07 +0800465 mAtmService = atmService;
466 mTaskId = _taskId;
467 mUserId = _userId;
Wale Ogunwale72919d22016-12-08 18:58:50 -0800468 mResizeMode = resizeMode;
Winson Chungd3395382016-12-13 11:49:09 -0800469 mSupportsPictureInPicture = supportsPictureInPicture;
Louis Changcdec0802019-11-11 11:45:07 +0800470 mTaskDescription = _lastTaskDescription;
Riddle Hsu6b76cd32019-10-08 00:37:19 +0800471 // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
472 setOrientation(SCREEN_ORIENTATION_UNSET);
Louis Changcdec0802019-11-11 11:45:07 +0800473 mRemoteToken = new RemoteToken(this);
474 affinityIntent = _affinityIntent;
475 affinity = _affinity;
476 rootAffinity = _rootAffinity;
477 voiceSession = _voiceSession;
478 voiceInteractor = _voiceInteractor;
479 realActivity = _realActivity;
480 realActivitySuspended = _realActivitySuspended;
481 origActivity = _origActivity;
482 rootWasReset = _rootWasReset;
483 isAvailable = true;
484 autoRemoveRecents = _autoRemoveRecents;
485 askedCompatMode = _askedCompatMode;
486 mUserSetupComplete = userSetupComplete;
487 effectiveUid = _effectiveUid;
488 touchActiveTime();
489 lastDescription = _lastDescription;
490 mLastTimeMoved = lastTimeMoved;
491 mNeverRelinquishIdentity = neverRelinquishIdentity;
492 mAffiliatedTaskId = taskAffiliation;
493 mAffiliatedTaskColor = taskAffiliationColor;
494 mPrevAffiliateTaskId = prevTaskId;
495 mNextAffiliateTaskId = nextTaskId;
496 mCallingUid = callingUid;
497 mCallingPackage = callingPackage;
498 mResizeMode = resizeMode;
499 if (info != null) {
500 setIntent(_intent, info);
501 setMinDimensions(info);
502 } else {
503 intent = _intent;
504 mMinWidth = minWidth;
505 mMinHeight = minHeight;
506 }
507 mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
508 }
509
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800510 private void cleanUpResourcesForDestroy() {
Louis Changcdec0802019-11-11 11:45:07 +0800511 if (hasChild()) {
512 return;
513 }
514
515 // This task is going away, so save the last state if necessary.
516 saveLaunchingStateIfNeeded();
517
518 // TODO: VI what about activity?
519 final boolean isVoiceSession = voiceSession != null;
520 if (isVoiceSession) {
521 try {
522 voiceSession.taskFinished(intent, mTaskId);
523 } catch (RemoteException e) {
524 }
525 }
526 if (autoRemoveFromRecents() || isVoiceSession) {
527 // Task creator asked to remove this when done, or this task was a voice
528 // interaction, so it should not remain on the recent tasks list.
529 mAtmService.mStackSupervisor.mRecentTasks.remove(this);
530 }
531
532 removeIfPossible();
533 }
534
535 @VisibleForTesting
536 @Override
537 void removeIfPossible() {
538 mAtmService.getLockTaskController().clearLockedTask(this);
539 if (shouldDeferRemoval()) {
540 if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
541 return;
542 }
543 removeImmediately();
544 mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
545 }
546
547 void setResizeMode(int resizeMode) {
548 if (mResizeMode == resizeMode) {
549 return;
550 }
551 mResizeMode = resizeMode;
552 mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
553 mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
554 updateTaskDescription();
555 }
556
557 boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
558 mAtmService.deferWindowLayout();
559
560 try {
561 final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
562
563 if (getParent() == null) {
564 // Task doesn't exist in window manager yet (e.g. was restored from recents).
565 // All we can do for now is update the bounds so it can be used when the task is
566 // added to window manager.
567 setBounds(bounds);
568 if (!inFreeformWindowingMode()) {
569 // re-restore the task so it can have the proper stack association.
570 mAtmService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
571 }
572 return true;
573 }
574
575 if (!canResizeToBounds(bounds)) {
576 throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
577 + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
578 }
579
580 // Do not move the task to another stack here.
581 // This method assumes that the task is already placed in the right stack.
582 // we do not mess with that decision and we only do the resize!
583
584 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId);
585
586 boolean updatedConfig = false;
587 mTmpConfig.setTo(getResolvedOverrideConfiguration());
588 if (setBounds(bounds) != BOUNDS_CHANGE_NONE) {
589 updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration());
590 }
591 // This variable holds information whether the configuration didn't change in a
592 // significant way and the activity was kept the way it was. If it's false, it means
593 // the activity had to be relaunched due to configuration change.
594 boolean kept = true;
595 if (updatedConfig) {
596 final ActivityRecord r = topRunningActivityLocked();
597 if (r != null && !deferResume) {
598 kept = r.ensureActivityConfiguration(0 /* globalChanges */,
599 preserveWindow);
600 // Preserve other windows for resizing because if resizing happens when there
601 // is a dialog activity in the front, the activity that still shows some
602 // content to the user will become black and cause flickers. Note in most cases
603 // this won't cause tons of irrelevant windows being preserved because only
604 // activities in this task may experience a bounds change. Configs for other
605 // activities stay the same.
606 mAtmService.mRootActivityContainer.ensureActivitiesVisible(r, 0,
607 preserveWindow);
608 if (!kept) {
609 mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
610 }
611 }
612 }
613 resize(kept, forced);
614
615 saveLaunchingStateIfNeeded();
616
617 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
618 return kept;
619 } finally {
620 mAtmService.continueWindowLayout();
621 }
622 }
623
624 /** Convenience method to reparent a task to the top or bottom position of the stack. */
625 boolean reparent(ActivityStack preferredStack, boolean toTop,
626 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
627 String reason) {
628 return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
629 true /* schedulePictureInPictureModeChange */, reason);
630 }
631
632 /**
633 * Convenience method to reparent a task to the top or bottom position of the stack, with
634 * an option to skip scheduling the picture-in-picture mode change.
635 */
636 boolean reparent(ActivityStack preferredStack, boolean toTop,
637 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
638 boolean schedulePictureInPictureModeChange, String reason) {
639 return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
640 deferResume, schedulePictureInPictureModeChange, reason);
641 }
642
643 /** Convenience method to reparent a task to a specific position of the stack. */
644 boolean reparent(ActivityStack preferredStack, int position,
645 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
646 String reason) {
647 return reparent(preferredStack, position, moveStackMode, animate, deferResume,
648 true /* schedulePictureInPictureModeChange */, reason);
649 }
650
651 /**
652 * Reparents the task into a preferred stack, creating it if necessary.
653 *
654 * @param preferredStack the target stack to move this task
655 * @param position the position to place this task in the new stack
656 * @param animate whether or not we should wait for the new window created as a part of the
657 * reparenting to be drawn and animated in
658 * @param moveStackMode whether or not to move the stack to the front always, only if it was
659 * previously focused & in front, or never
660 * @param deferResume whether or not to update the visibility of other tasks and stacks that may
661 * have changed as a result of this reparenting
662 * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
663 * change. Callers may set this to false if they are explicitly scheduling PiP mode
664 * changes themselves, like during the PiP animation
665 * @param reason the caller of this reparenting
666 * @return whether the task was reparented
667 */
668 // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
669 // re-parenting the task. Can only be done when we are no longer using static stack Ids.
670 boolean reparent(ActivityStack preferredStack, int position,
671 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
672 boolean schedulePictureInPictureModeChange, String reason) {
673 final ActivityStackSupervisor supervisor = mAtmService.mStackSupervisor;
674 final RootActivityContainer root = mAtmService.mRootActivityContainer;
675 final WindowManagerService windowManager = mAtmService.mWindowManager;
676 final ActivityStack sourceStack = getStack();
677 final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
678 position == MAX_VALUE);
679 if (toStack == sourceStack) {
680 return false;
681 }
682 if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
683 return false;
684 }
685
686 final boolean toTopOfStack = position == MAX_VALUE;
687 if (toTopOfStack && toStack.getResumedActivity() != null
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900688 && toStack.topRunningActivity() != null) {
Louis Changcdec0802019-11-11 11:45:07 +0800689 // Pause the resumed activity on the target stack while re-parenting task on top of it.
690 toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
691 null /* resuming */);
692 }
693
694 final int toStackWindowingMode = toStack.getWindowingMode();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800695 final ActivityRecord topActivity = getTopNonFinishingActivity();
Louis Changcdec0802019-11-11 11:45:07 +0800696
697 final boolean mightReplaceWindow = topActivity != null
698 && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
699 if (mightReplaceWindow) {
700 // We are about to relaunch the activity because its configuration changed due to
701 // being maximized, i.e. size change. The activity will first remove the old window
702 // and then add a new one. This call will tell window manager about this, so it can
703 // preserve the old window until the new one is drawn. This prevents having a gap
704 // between the removal and addition, in which no window is visible. We also want the
705 // entrance of the new window to be properly animated.
706 // Note here we always set the replacing window first, as the flags might be needed
707 // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
708 windowManager.setWillReplaceWindow(topActivity.appToken, animate);
709 }
710
711 mAtmService.deferWindowLayout();
712 boolean kept = true;
713 try {
714 final ActivityRecord r = topRunningActivityLocked();
Louis Changcdec0802019-11-11 11:45:07 +0800715 final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
716 && (topRunningActivityLocked() == r);
717 final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
718 final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
719
720 // In some cases the focused stack isn't the front stack. E.g. pinned stack.
721 // Whenever we are moving the top activity from the front stack we want to make sure to
722 // move the stack to the front.
723 final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900724 && (sourceStack.topRunningActivity() == r);
Louis Changcdec0802019-11-11 11:45:07 +0800725
726 final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
727 || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
728
729 reparent(toStack, position, moveStackToFront, reason);
730
731 if (schedulePictureInPictureModeChange) {
732 // Notify of picture-in-picture mode changes
733 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
734 }
735
736 // If the task had focus before (or we're requested to move focus), move focus to the
737 // new stack by moving the stack to the front.
738 if (r != null) {
739 toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
740 wasPaused, reason);
741 }
742 if (!animate) {
743 mAtmService.mStackSupervisor.mNoAnimActivities.add(topActivity);
744 }
745
746 // We might trigger a configuration change. Save the current task bounds for freezing.
747 // TODO: Should this call be moved inside the resize method in WM?
748 toStack.prepareFreezingTaskBounds();
749
750 // Make sure the task has the appropriate bounds/size for the stack it is in.
751 final boolean toStackSplitScreenPrimary =
752 toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
753 final Rect configBounds = getRequestedOverrideBounds();
754 if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
755 || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
756 && !Objects.equals(configBounds, toStack.getRequestedOverrideBounds())) {
757 kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
758 !mightReplaceWindow, deferResume);
759 } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
760 Rect bounds = getLaunchBounds();
761 if (bounds == null) {
762 mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
763 bounds = configBounds;
764 }
765 kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
766 } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
767 if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
768 // Move recents to front so it is not behind home stack when going into docked
769 // mode
770 mAtmService.mStackSupervisor.moveRecentsStackToFront(reason);
771 }
772 kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
773 !mightReplaceWindow, deferResume);
774 }
775 } finally {
776 mAtmService.continueWindowLayout();
777 }
778
779 if (mightReplaceWindow) {
780 // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
781 // window), we need to clear the replace window settings. Otherwise, we schedule a
782 // timeout to remove the old window if the replacing window is not coming in time.
783 windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
784 }
785
786 if (!deferResume) {
787 // The task might have already been running and its visibility needs to be synchronized
788 // with the visibility of the stack / windows.
789 root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
790 root.resumeFocusedStacksTopActivities();
791 }
792
793 // TODO: Handle incorrect request to move before the actual move, not after.
794 supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
795 DEFAULT_DISPLAY, toStack);
796
797 return (preferredStack == toStack);
798 }
799
800 /**
801 * @return {@code true} if the windows of tasks being moved to the target stack from the
802 * source stack should be replaced, meaning that window manager will keep the old window
803 * around until the new is ready.
804 */
805 private static boolean replaceWindowsOnTaskMove(
806 int sourceWindowingMode, int targetWindowingMode) {
807 return sourceWindowingMode == WINDOWING_MODE_FREEFORM
808 || targetWindowingMode == WINDOWING_MODE_FREEFORM;
809 }
810
811 /**
812 * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
813 */
814 TaskSnapshot getSnapshot(boolean reducedResolution, boolean restoreFromDisk) {
815
816 // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
817 // synchronized between AM and WM.
818 return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, reducedResolution,
819 restoreFromDisk);
820 }
821
822 void touchActiveTime() {
823 lastActiveTime = SystemClock.elapsedRealtime();
824 }
825
826 long getInactiveDuration() {
827 return SystemClock.elapsedRealtime() - lastActiveTime;
828 }
829
830 /** Sets the original intent, and the calling uid and package. */
831 void setIntent(ActivityRecord r) {
832 mCallingUid = r.launchedFromUid;
833 mCallingPackage = r.launchedFromPackage;
834 setIntent(r.intent, r.info);
835 setLockTaskAuth(r);
836 }
837
838 /** Sets the original intent, _without_ updating the calling uid or package. */
839 private void setIntent(Intent _intent, ActivityInfo info) {
840 if (intent == null) {
841 mNeverRelinquishIdentity =
842 (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
843 } else if (mNeverRelinquishIdentity) {
844 return;
845 }
846
847 affinity = info.taskAffinity;
848 if (intent == null) {
849 // If this task already has an intent associated with it, don't set the root
850 // affinity -- we don't want it changing after initially set, but the initially
851 // set value may be null.
852 rootAffinity = affinity;
853 }
854 effectiveUid = info.applicationInfo.uid;
855 stringName = null;
856
857 if (info.targetActivity == null) {
858 if (_intent != null) {
859 // If this Intent has a selector, we want to clear it for the
860 // recent task since it is not relevant if the user later wants
861 // to re-launch the app.
862 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
863 _intent = new Intent(_intent);
864 _intent.setSelector(null);
865 _intent.setSourceBounds(null);
866 }
867 }
868 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
869 intent = _intent;
870 realActivity = _intent != null ? _intent.getComponent() : null;
871 origActivity = null;
872 } else {
873 ComponentName targetComponent = new ComponentName(
874 info.packageName, info.targetActivity);
875 if (_intent != null) {
876 Intent targetIntent = new Intent(_intent);
877 targetIntent.setSelector(null);
878 targetIntent.setSourceBounds(null);
879 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
880 "Setting Intent of " + this + " to target " + targetIntent);
881 intent = targetIntent;
882 realActivity = targetComponent;
883 origActivity = _intent.getComponent();
884 } else {
885 intent = null;
886 realActivity = targetComponent;
887 origActivity = new ComponentName(info.packageName, info.name);
888 }
889 }
890
891 final int intentFlags = intent == null ? 0 : intent.getFlags();
892 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
893 // Once we are set to an Intent with this flag, we count this
894 // task as having a true root activity.
895 rootWasReset = true;
896 }
897 mUserId = UserHandle.getUserId(info.applicationInfo.uid);
898 mUserSetupComplete = Settings.Secure.getIntForUser(
899 mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0;
900 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
901 // If the activity itself has requested auto-remove, then just always do it.
902 autoRemoveRecents = true;
903 } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
904 == FLAG_ACTIVITY_NEW_DOCUMENT) {
905 // If the caller has not asked for the document to be retained, then we may
906 // want to turn on auto-remove, depending on whether the target has set its
907 // own document launch mode.
908 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
909 autoRemoveRecents = false;
910 } else {
911 autoRemoveRecents = true;
912 }
913 } else {
914 autoRemoveRecents = false;
915 }
916 if (mResizeMode != info.resizeMode) {
917 mResizeMode = info.resizeMode;
918 updateTaskDescription();
919 }
920 mSupportsPictureInPicture = info.supportsPictureInPicture();
921 }
922
923 /** Sets the original minimal width and height. */
924 private void setMinDimensions(ActivityInfo info) {
925 if (info != null && info.windowLayout != null) {
926 mMinWidth = info.windowLayout.minWidth;
927 mMinHeight = info.windowLayout.minHeight;
928 } else {
929 mMinWidth = INVALID_MIN_SIZE;
930 mMinHeight = INVALID_MIN_SIZE;
931 }
932 }
933
934 /**
935 * Return true if the input activity has the same intent filter as the intent this task
936 * record is based on (normally the root activity intent).
937 */
938 boolean isSameIntentFilter(ActivityRecord r) {
939 final Intent intent = new Intent(r.intent);
940 // Make sure the component are the same if the input activity has the same real activity
941 // as the one in the task because either one of them could be the alias activity.
942 if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
943 intent.setComponent(this.intent.getComponent());
944 }
945 return intent.filterEquals(this.intent);
946 }
947
948 boolean returnsToHomeStack() {
949 final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
950 return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
951 }
952
953 void setPrevAffiliate(Task prevAffiliate) {
954 mPrevAffiliate = prevAffiliate;
955 mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId;
956 }
957
958 void setNextAffiliate(Task nextAffiliate) {
959 mNextAffiliate = nextAffiliate;
960 mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
961 }
962
963 ActivityStack getStack() {
964 return mStack;
965 }
966
967 @Override
968 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
Louis Changcdec0802019-11-11 11:45:07 +0800969 final ActivityStack oldStack = ((ActivityStack) oldParent);
970 final ActivityStack newStack = ((ActivityStack) newParent);
971
Louis Chang8bda2322019-12-05 16:38:11 +0800972 // Task is going to be removed, clean it up before detaching from hierarchy.
973 if (oldParent != null && newParent == null) {
974 cleanUpResourcesForDestroy();
975 }
976
Louis Changcdec0802019-11-11 11:45:07 +0800977 mStack = newStack;
978
979 super.onParentChanged(newParent, oldParent);
980
981 if (oldStack != null) {
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800982 final PooledConsumer c = PooledLambda.obtainConsumer(
983 ActivityStack::onActivityRemovedFromStack, oldStack,
984 PooledLambda.__(ActivityRecord.class));
985 forAllActivities(c);
986 c.recycle();
Louis Changcdec0802019-11-11 11:45:07 +0800987
988 if (oldStack.inPinnedWindowingMode()
989 && (newStack == null || !newStack.inPinnedWindowingMode())) {
990 // Notify if a task from the pinned stack is being removed
991 // (or moved depending on the mode).
992 mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
993 }
994 }
995
996 if (newStack != null) {
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800997 final PooledConsumer c = PooledLambda.obtainConsumer(
998 ActivityStack::onActivityAddedToStack, newStack,
999 PooledLambda.__(ActivityRecord.class));
1000 forAllActivities(c);
1001 c.recycle();
Louis Changcdec0802019-11-11 11:45:07 +08001002
1003 // TODO: Ensure that this is actually necessary here
1004 // Notify the voice session if required
1005 if (voiceSession != null) {
1006 try {
1007 voiceSession.taskStarted(intent, mTaskId);
1008 } catch (RemoteException e) {
1009 }
1010 }
1011 }
1012
1013 // First time we are adding the task to the system.
1014 if (oldParent == null && newParent != null) {
1015
1016 // TODO: Super random place to be doing this, but aligns with what used to be done
1017 // before we unified Task level. Look into if this can be done in a better place.
1018 updateOverrideConfigurationFromLaunchBounds();
1019 }
1020
Louis Changcdec0802019-11-11 11:45:07 +08001021 // Update task bounds if needed.
1022 adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
1023
1024 if (getWindowConfiguration().windowsAreScaleable()) {
1025 // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
1026 // while a resize is pending.
1027 forceWindowsScaleable(true /* force */);
1028 } else {
1029 forceWindowsScaleable(false /* force */);
1030 }
1031
1032 mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
1033 }
1034
1035 void updateTaskMovement(boolean toFront) {
1036 if (isPersistable) {
1037 mLastTimeMoved = System.currentTimeMillis();
1038 // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
1039 // recently will be most negative, tasks sent to the bottom before that will be less
1040 // negative. Similarly for recent tasks moved to the top which will be most positive.
1041 if (!toFront) {
1042 mLastTimeMoved *= -1;
1043 }
1044 }
1045 mAtmService.mRootActivityContainer.invalidateTaskLayers();
1046 }
1047
1048 /**
1049 * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
1050 */
1051 int getStackId() {
1052 return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
1053 }
1054
1055 // Close up recents linked list.
1056 private void closeRecentsChain() {
1057 if (mPrevAffiliate != null) {
1058 mPrevAffiliate.setNextAffiliate(mNextAffiliate);
1059 }
1060 if (mNextAffiliate != null) {
1061 mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
1062 }
1063 setPrevAffiliate(null);
1064 setNextAffiliate(null);
1065 }
1066
1067 void removedFromRecents() {
1068 closeRecentsChain();
1069 if (inRecents) {
1070 inRecents = false;
1071 mAtmService.notifyTaskPersisterLocked(this, false);
1072 }
1073
1074 clearRootProcess();
1075
1076 mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
1077 mTaskId, mUserId);
1078 }
1079
1080 void setTaskToAffiliateWith(Task taskToAffiliateWith) {
1081 closeRecentsChain();
1082 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
1083 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
1084 // Find the end
1085 while (taskToAffiliateWith.mNextAffiliate != null) {
1086 final Task nextRecents = taskToAffiliateWith.mNextAffiliate;
1087 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
1088 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
1089 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
1090 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
1091 nextRecents.setPrevAffiliate(null);
1092 }
1093 taskToAffiliateWith.setNextAffiliate(null);
1094 break;
1095 }
1096 taskToAffiliateWith = nextRecents;
1097 }
1098 taskToAffiliateWith.setNextAffiliate(this);
1099 setPrevAffiliate(taskToAffiliateWith);
1100 setNextAffiliate(null);
1101 }
1102
1103 /** Returns the intent for the root activity for this task */
1104 Intent getBaseIntent() {
1105 return intent != null ? intent : affinityIntent;
1106 }
1107
1108 /** Returns the first non-finishing activity from the bottom. */
1109 ActivityRecord getRootActivity() {
Wale Ogunwaledfbeed72019-11-20 08:57:39 -08001110 // TODO: Figure out why we historical ignore relinquish identity for this case...
1111 return getRootActivity(true /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/);
1112 }
1113
1114 ActivityRecord getRootActivity(boolean setToBottomIfNone) {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001115 return getRootActivity(false /*ignoreRelinquishIdentity*/, setToBottomIfNone);
Wale Ogunwaledfbeed72019-11-20 08:57:39 -08001116 }
1117
1118 ActivityRecord getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001119 return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone);
Louis Changcdec0802019-11-11 11:45:07 +08001120 }
1121
Wale Ogunwale21e06482019-11-18 05:14:15 -08001122 ActivityRecord getTopNonFinishingActivity() {
1123 return getTopNonFinishingActivity(true /* includeOverlays */);
Louis Changcdec0802019-11-11 11:45:07 +08001124 }
1125
Wale Ogunwale21e06482019-11-18 05:14:15 -08001126 ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001127 return getTopActivity(false /*includeFinishing*/, includeOverlays);
Louis Changcdec0802019-11-11 11:45:07 +08001128 }
1129
1130 ActivityRecord topRunningActivityLocked() {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001131 if (getParent() == null) {
1132 return null;
Louis Changcdec0802019-11-11 11:45:07 +08001133 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001134 return getActivity(ActivityRecord::canBeTopRunning);
Louis Changcdec0802019-11-11 11:45:07 +08001135 }
1136
1137 /**
1138 * Return true if any activities in this task belongs to input uid.
1139 */
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001140 boolean isUidPresent(int uid) {
1141 final PooledPredicate p = PooledLambda.obtainPredicate(
1142 ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
1143 final boolean isUidPresent = getActivity(p) != null;
1144 p.recycle();
1145 return isUidPresent;
Louis Changcdec0802019-11-11 11:45:07 +08001146 }
1147
1148 ActivityRecord topRunningActivityWithStartingWindowLocked() {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001149 if (getParent() == null) {
1150 return null;
Louis Changcdec0802019-11-11 11:45:07 +08001151 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001152 return getActivity((r) -> r.mStartingWindowState == STARTING_WINDOW_SHOWN
1153 && r.canBeTopRunning());
Louis Changcdec0802019-11-11 11:45:07 +08001154 }
1155
1156 /**
1157 * Return the number of running activities, and the number of non-finishing/initializing
1158 * activities in the provided {@param reportOut} respectively.
1159 */
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001160 private void getNumRunningActivities(TaskActivitiesReport reportOut) {
Louis Changcdec0802019-11-11 11:45:07 +08001161 reportOut.reset();
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001162 forAllActivities(reportOut);
Louis Changcdec0802019-11-11 11:45:07 +08001163 }
1164
1165 /**
1166 * Reorder the history stack so that the passed activity is brought to the front.
1167 */
1168 final void moveActivityToFrontLocked(ActivityRecord newTop) {
1169 if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
1170 + newTop + " to stack at top callers=" + Debug.getCallers(4));
1171
1172 positionChildAtTop(newTop);
1173 updateEffectiveIntent();
1174 }
1175
1176 @Override
1177 public int getActivityType() {
1178 final int applicationType = super.getActivityType();
1179 if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
1180 return applicationType;
1181 }
1182 return getChildAt(0).getActivityType();
1183 }
1184
1185 @Override
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001186 void addChild(WindowContainer child, int index) {
Louis Changcdec0802019-11-11 11:45:07 +08001187 // If this task had any child before we added this one.
1188 boolean hadChild = hasChild();
1189
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001190 final ActivityRecord r = (ActivityRecord) child;
Louis Changcdec0802019-11-11 11:45:07 +08001191 index = getAdjustedAddPosition(r, index);
1192 super.addChild(r, index);
1193
1194 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
1195 r.inHistory = true;
1196
Louis Changcdec0802019-11-11 11:45:07 +08001197 // Only set this based on the first activity
1198 if (!hadChild) {
1199 if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
1200 // Normally non-standard activity type for the activity record will be set when the
1201 // object is created, however we delay setting the standard application type until
1202 // this point so that the task can set the type for additional activities added in
1203 // the else condition below.
1204 r.setActivityType(ACTIVITY_TYPE_STANDARD);
1205 }
1206 setActivityType(r.getActivityType());
1207 isPersistable = r.isPersistable();
1208 mCallingUid = r.launchedFromUid;
1209 mCallingPackage = r.launchedFromPackage;
1210 // Clamp to [1, max].
1211 maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
1212 ActivityTaskManager.getMaxAppRecentsLimitStatic());
1213 } else {
1214 // Otherwise make all added activities match this one.
1215 r.setActivityType(getActivityType());
1216 }
1217
1218 updateEffectiveIntent();
Louis Changcdec0802019-11-11 11:45:07 +08001219
1220 // Make sure the list of display UID whitelists is updated
1221 // now that this record is in a new task.
1222 mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
1223 }
1224
1225 void addChild(ActivityRecord r) {
1226 addChild(r, Integer.MAX_VALUE /* add on top */);
1227 }
1228
1229 @Override
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001230 void removeChild(WindowContainer r) {
Louis Changcdec0802019-11-11 11:45:07 +08001231 if (!mChildren.contains(r)) {
1232 Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
1233 return;
1234 }
1235
1236 super.removeChild(r);
Louis Changcdec0802019-11-11 11:45:07 +08001237
1238 if (inPinnedWindowingMode()) {
1239 // We normally notify listeners of task stack changes on pause, however pinned stack
1240 // activities are normally in the paused state so no notification will be sent there
1241 // before the activity is removed. We send it here so instead.
1242 mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
1243 }
1244
1245 final String reason = "removeChild";
1246 if (hasChild()) {
1247 updateEffectiveIntent();
1248
1249 // The following block can be executed multiple times if there is more than one overlay.
1250 // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
1251 // of the task by id and exiting early if not found.
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001252 if (onlyHasTaskOverlayActivities(true /*includeFinishing*/)) {
Louis Changcdec0802019-11-11 11:45:07 +08001253 // When destroying a task, tell the supervisor to remove it so that any activity it
1254 // has can be cleaned up correctly. This is currently the only place where we remove
1255 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
1256 // state into removeChild(), we just clear the task here before the other residual
1257 // work.
1258 // TODO: If the callers to removeChild() changes such that we have multiple places
1259 // where we are destroying the task, move this back into removeChild()
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09001260 mAtmService.mStackSupervisor.removeTask(this, false /* killProcess */,
Louis Changcdec0802019-11-11 11:45:07 +08001261 !REMOVE_FROM_RECENTS, reason);
1262 }
1263 } else if (!mReuseTask) {
1264 // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
1265 mStack.removeChild(this, reason);
Jeff Changd136e772019-11-05 20:33:52 +08001266 EventLogTags.writeWmTaskRemoved(mTaskId,
Louis Changcdec0802019-11-11 11:45:07 +08001267 "removeChild: last r=" + r + " in t=" + this);
1268 removeIfPossible();
1269 }
1270 }
1271
1272 /**
1273 * @return whether or not there are ONLY task overlay activities in the stack.
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001274 * If {@param includeFinishing} is set, then don't ignore finishing activities in the
1275 * check. If there are no task overlay activities, this call returns false.
Louis Changcdec0802019-11-11 11:45:07 +08001276 */
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001277 boolean onlyHasTaskOverlayActivities(boolean includeFinishing) {
1278 if (getChildCount() == 0) {
1279 return false;
Louis Changcdec0802019-11-11 11:45:07 +08001280 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001281 if (includeFinishing) {
1282 return getActivity((r) -> r.mTaskOverlay) != null;
1283 }
1284 return getActivity((r) -> !r.finishing && r.mTaskOverlay) != null;
Louis Changcdec0802019-11-11 11:45:07 +08001285 }
1286
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001287 private boolean autoRemoveFromRecents() {
Louis Changcdec0802019-11-11 11:45:07 +08001288 // We will automatically remove the task either if it has explicitly asked for
1289 // this, or it is empty and has never contained an activity that got shown to
1290 // the user.
1291 return autoRemoveRecents || (!hasChild() && !hasBeenVisible);
1292 }
1293
1294 /**
1295 * Completely remove all activities associated with an existing
1296 * task starting at a specified index.
1297 */
Wale Ogunwale21e06482019-11-18 05:14:15 -08001298 private void performClearTaskAtIndexLocked(String reason) {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001299 // Broken down into to cases to avoid object create due to capturing mStack.
1300 if (mStack == null) {
1301 forAllActivities((r) -> {
1302 if (r.finishing) return;
Louis Changcdec0802019-11-11 11:45:07 +08001303 // Task was restored from persistent storage.
1304 r.takeFromHistory();
1305 removeChild(r);
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001306 });
1307 } else {
1308 forAllActivities((r) -> {
1309 if (r.finishing) return;
1310 // TODO: figure-out how to avoid object creation due to capture of reason variable.
1311 r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
1312 false /* oomAdj */);
1313 });
Louis Changcdec0802019-11-11 11:45:07 +08001314 }
1315 }
1316
1317 /**
1318 * Completely remove all activities associated with an existing task.
1319 */
1320 void performClearTaskLocked() {
1321 mReuseTask = true;
Wale Ogunwale21e06482019-11-18 05:14:15 -08001322 performClearTaskAtIndexLocked("clear-task-all");
Louis Changcdec0802019-11-11 11:45:07 +08001323 mReuseTask = false;
1324 }
1325
1326 ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
1327 mReuseTask = true;
1328 final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
1329 mReuseTask = false;
1330 return result;
1331 }
1332
1333 /**
1334 * Perform clear operation as requested by
1335 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
1336 * stack to the given task, then look for
1337 * an instance of that activity in the stack and, if found, finish all
1338 * activities on top of it and return the instance.
1339 *
1340 * @param newR Description of the new activity being started.
1341 * @return Returns the old activity that should be continued to be used,
1342 * or {@code null} if none was found.
1343 */
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001344 private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
1345 final ActivityRecord r = findActivityInHistory(newR.mActivityComponent);
1346 if (r == null) return null;
Louis Changcdec0802019-11-11 11:45:07 +08001347
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001348 final PooledFunction f = PooledLambda.obtainFunction(Task::finishActivityAbove,
1349 PooledLambda.__(ActivityRecord.class), r);
1350 forAllActivities(f);
1351 f.recycle();
Louis Changcdec0802019-11-11 11:45:07 +08001352
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001353 // Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we
1354 // will finish the current instance of the activity so a new fresh one can be started.
1355 if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE
1356 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
1357 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
1358 if (!r.finishing) {
1359 r.finishIfPossible("clear-task-top", false /* oomAdj */);
1360 return null;
Louis Changcdec0802019-11-11 11:45:07 +08001361 }
1362 }
1363
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001364 return r;
1365 }
1366
1367 private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) {
1368 // Stop operation once we reach the boundary activity.
1369 if (r == boundaryActivity) return true;
1370
1371 if (!r.finishing) {
1372 final ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
1373 if (opts != null) {
1374 // TODO: Why is this updating the boundary activity vs. the current activity???
1375 boundaryActivity.updateOptionsLocked(opts);
1376 }
1377 r.finishIfPossible("clear-task-stack", false /* oomAdj */);
1378 }
1379
1380 return false;
Louis Changcdec0802019-11-11 11:45:07 +08001381 }
1382
1383 void removeTaskActivitiesLocked(String reason) {
1384 // Just remove the entire task.
Wale Ogunwale21e06482019-11-18 05:14:15 -08001385 performClearTaskAtIndexLocked(reason);
Louis Changcdec0802019-11-11 11:45:07 +08001386 }
1387
1388 String lockTaskAuthToString() {
1389 switch (mLockTaskAuth) {
1390 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
1391 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
1392 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
1393 case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
1394 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
1395 default: return "unknown=" + mLockTaskAuth;
1396 }
1397 }
1398
1399 void setLockTaskAuth() {
1400 setLockTaskAuth(getRootActivity());
1401 }
1402
1403 private void setLockTaskAuth(@Nullable ActivityRecord r) {
1404 if (r == null) {
1405 mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
1406 return;
1407 }
1408
1409 final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
1410 final LockTaskController lockTaskController = mAtmService.getLockTaskController();
1411 switch (r.lockTaskLaunchMode) {
1412 case LOCK_TASK_LAUNCH_MODE_DEFAULT:
1413 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
1414 ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
1415 break;
1416
1417 case LOCK_TASK_LAUNCH_MODE_NEVER:
1418 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
1419 break;
1420
1421 case LOCK_TASK_LAUNCH_MODE_ALWAYS:
1422 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
1423 break;
1424
1425 case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
1426 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
1427 ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
1428 break;
1429 }
1430 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
1431 + " mLockTaskAuth=" + lockTaskAuthToString());
1432 }
1433
1434 @Override
1435 public boolean supportsSplitScreenWindowingMode() {
1436 // A task can not be docked even if it is considered resizeable because it only supports
1437 // picture-in-picture mode but has a non-resizeable resizeMode
1438 return super.supportsSplitScreenWindowingMode()
1439 // TODO(task-group): Probably makes sense to move this and associated code into
1440 // WindowContainer so it affects every node.
1441 && mAtmService.mSupportsSplitScreenMultiWindow
1442 && (mAtmService.mForceResizableActivities
1443 || (isResizeable(false /* checkSupportsPip */)
1444 && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
1445 }
1446
1447 /**
1448 * Check whether this task can be launched on the specified display.
1449 *
1450 * @param displayId Target display id.
1451 * @return {@code true} if either it is the default display or this activity can be put on a
1452 * secondary display.
1453 */
1454 boolean canBeLaunchedOnDisplay(int displayId) {
1455 return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
1456 -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
1457 }
1458
1459 /**
1460 * Check that a given bounds matches the application requested orientation.
1461 *
1462 * @param bounds The bounds to be tested.
1463 * @return True if the requested bounds are okay for a resizing request.
1464 */
1465 private boolean canResizeToBounds(Rect bounds) {
1466 if (bounds == null || !inFreeformWindowingMode()) {
1467 // Note: If not on the freeform workspace, we ignore the bounds.
1468 return true;
1469 }
1470 final boolean landscape = bounds.width() > bounds.height();
1471 final Rect configBounds = getRequestedOverrideBounds();
1472 if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
1473 return configBounds.isEmpty()
1474 || landscape == (configBounds.width() > configBounds.height());
1475 }
1476 return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
1477 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
1478 }
1479
1480 /**
1481 * @return {@code true} if the task is being cleared for the purposes of being reused.
1482 */
1483 boolean isClearingToReuseTask() {
1484 return mReuseTask;
1485 }
1486
1487 /**
1488 * Find the activity in the history stack within the given task. Returns
1489 * the index within the history at which it's found, or < 0 if not found.
1490 */
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001491 ActivityRecord findActivityInHistory(ComponentName component) {
1492 final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory,
1493 PooledLambda.__(ActivityRecord.class), component);
1494 final ActivityRecord r = getActivity(p);
1495 p.recycle();
1496 return r;
1497 }
1498
1499 private static boolean matchesActivityInHistory(
1500 ActivityRecord r, ComponentName activityComponent) {
1501 return !r.finishing && r.mActivityComponent.equals(activityComponent);
Louis Changcdec0802019-11-11 11:45:07 +08001502 }
1503
1504 /** Updates the last task description values. */
1505 void updateTaskDescription() {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001506 final ActivityRecord root = getRootActivity(true);
1507 if (root == null) return;
1508
1509 final TaskDescription taskDescription = new TaskDescription();
1510 final PooledFunction f = PooledLambda.obtainFunction(
1511 Task::setTaskDescriptionFromActivityAboveRoot,
1512 PooledLambda.__(ActivityRecord.class), root, taskDescription);
1513 forAllActivities(f);
1514 f.recycle();
1515 taskDescription.setResizeMode(mResizeMode);
1516 taskDescription.setMinWidth(mMinWidth);
1517 taskDescription.setMinHeight(mMinHeight);
1518 setTaskDescription(taskDescription);
1519 // Update the task affiliation color if we are the parent of the group
1520 if (mTaskId == mAffiliatedTaskId) {
1521 mAffiliatedTaskColor = taskDescription.getPrimaryColor();
Louis Changcdec0802019-11-11 11:45:07 +08001522 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001523 mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
1524 getTaskInfo());
Louis Changcdec0802019-11-11 11:45:07 +08001525 }
1526
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001527 private static boolean setTaskDescriptionFromActivityAboveRoot(
1528 ActivityRecord r, ActivityRecord root, TaskDescription td) {
1529 if (!r.mTaskOverlay && r.taskDescription != null) {
1530 final TaskDescription atd = r.taskDescription;
1531 if (td.getLabel() == null) {
1532 td.setLabel(atd.getLabel());
Louis Changcdec0802019-11-11 11:45:07 +08001533 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001534 if (td.getIconResource() == 0) {
1535 td.setIcon(atd.getIconResource());
Louis Changcdec0802019-11-11 11:45:07 +08001536 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001537 if (td.getIconFilename() == null) {
1538 td.setIconFilename(atd.getIconFilename());
1539 }
1540 if (td.getPrimaryColor() == 0) {
1541 td.setPrimaryColor(atd.getPrimaryColor());
1542 }
1543 if (td.getBackgroundColor() == 0) {
1544 td.setBackgroundColor(atd.getBackgroundColor());
1545 }
1546 if (td.getStatusBarColor() == 0) {
1547 td.setStatusBarColor(atd.getStatusBarColor());
1548 td.setEnsureStatusBarContrastWhenTransparent(
1549 atd.getEnsureStatusBarContrastWhenTransparent());
1550 }
1551 if (td.getNavigationBarColor() == 0) {
1552 td.setNavigationBarColor(atd.getNavigationBarColor());
1553 td.setEnsureNavigationBarContrastWhenTransparent(
1554 atd.getEnsureNavigationBarContrastWhenTransparent());
1555 }
1556
Louis Changcdec0802019-11-11 11:45:07 +08001557 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001558
1559 // End search once we get to root.
1560 return r == root;
Louis Changcdec0802019-11-11 11:45:07 +08001561 }
1562
1563 // TODO (AM refactor): Invoke automatically when there is a change in children
1564 @VisibleForTesting
1565 void updateEffectiveIntent() {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001566 final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/);
1567 setIntent(root);
Louis Changcdec0802019-11-11 11:45:07 +08001568 // Update the task description when the activities change
1569 updateTaskDescription();
1570 }
1571
1572 void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
Evan Rosky70213702019-11-05 10:26:24 -08001573 final Rect parentBounds = getParent() != null ? getParent().getBounds() : null;
1574 if (bounds == null
1575 || (bounds.isEmpty() && (parentBounds == null || parentBounds.isEmpty()))) {
Louis Changcdec0802019-11-11 11:45:07 +08001576 return;
1577 }
1578 int minWidth = mMinWidth;
1579 int minHeight = mMinHeight;
1580 // If the task has no requested minimal size, we'd like to enforce a minimal size
1581 // so that the user can not render the task too small to manipulate. We don't need
1582 // to do this for the pinned stack as the bounds are controlled by the system.
1583 if (!inPinnedWindowingMode() && mStack != null) {
1584 final int defaultMinSizeDp =
1585 mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
1586 final ActivityDisplay display =
1587 mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
1588 final float density =
1589 (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
1590 final int defaultMinSize = (int) (defaultMinSizeDp * density);
1591
1592 if (minWidth == INVALID_MIN_SIZE) {
1593 minWidth = defaultMinSize;
1594 }
1595 if (minHeight == INVALID_MIN_SIZE) {
1596 minHeight = defaultMinSize;
1597 }
1598 }
Evan Rosky70213702019-11-05 10:26:24 -08001599 if (bounds.isEmpty()) {
1600 // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
1601 // do, we can just skip.
1602 if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
1603 return;
1604 }
1605 bounds.set(parentBounds);
1606 }
Louis Changcdec0802019-11-11 11:45:07 +08001607 final boolean adjustWidth = minWidth > bounds.width();
1608 final boolean adjustHeight = minHeight > bounds.height();
1609 if (!(adjustWidth || adjustHeight)) {
1610 return;
1611 }
1612
1613 if (adjustWidth) {
1614 if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
1615 bounds.left = bounds.right - minWidth;
1616 } else {
1617 // Either left bounds match, or neither match, or the previous bounds were
1618 // fullscreen and we default to keeping left.
1619 bounds.right = bounds.left + minWidth;
1620 }
1621 }
1622 if (adjustHeight) {
1623 if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
1624 bounds.top = bounds.bottom - minHeight;
1625 } else {
1626 // Either top bounds match, or neither match, or the previous bounds were
1627 // fullscreen and we default to keeping top.
1628 bounds.bottom = bounds.top + minHeight;
1629 }
1630 }
1631 }
1632
1633 void setLastNonFullscreenBounds(Rect bounds) {
1634 if (mLastNonFullscreenBounds == null) {
1635 mLastNonFullscreenBounds = new Rect(bounds);
1636 } else {
1637 mLastNonFullscreenBounds.set(bounds);
1638 }
1639 }
1640
1641 /**
1642 * This should be called when an child activity changes state. This should only
1643 * be called from
1644 * {@link ActivityRecord#setState(ActivityState, String)} .
1645 * @param record The {@link ActivityRecord} whose state has changed.
1646 * @param state The new state.
1647 * @param reason The reason for the change.
1648 */
1649 void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
1650 final ActivityStack parent = getStack();
1651
1652 if (parent != null) {
1653 parent.onActivityStateChanged(record, state, reason);
1654 }
1655 }
1656
1657 @Override
1658 public void onConfigurationChanged(Configuration newParentConfig) {
1659 // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
1660 // restore the last recorded non-fullscreen bounds.
1661 final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
1662 final boolean nextPersistTaskBounds =
1663 getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
1664 || newParentConfig.windowConfiguration.persistTaskBounds();
1665 if (!prevPersistTaskBounds && nextPersistTaskBounds
1666 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
1667 // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
1668 getRequestedOverrideConfiguration().windowConfiguration
1669 .setBounds(mLastNonFullscreenBounds);
1670 }
1671
1672 final boolean wasInMultiWindowMode = inMultiWindowMode();
1673 super.onConfigurationChanged(newParentConfig);
1674 if (wasInMultiWindowMode != inMultiWindowMode()) {
1675 mAtmService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
1676 }
1677
1678 // If the configuration supports persistent bounds (eg. Freeform), keep track of the
1679 // current (non-fullscreen) bounds for persistence.
1680 if (getWindowConfiguration().persistTaskBounds()) {
1681 final Rect currentBounds = getRequestedOverrideBounds();
1682 if (!currentBounds.isEmpty()) {
1683 setLastNonFullscreenBounds(currentBounds);
1684 }
1685 }
1686 // TODO: Should also take care of Pip mode changes here.
1687
1688 saveLaunchingStateIfNeeded();
1689 }
1690
1691 /**
1692 * Saves launching state if necessary so that we can launch the activity to its latest state.
1693 * It only saves state if this task has been shown to user and it's in fullscreen or freeform
1694 * mode on freeform displays.
1695 */
1696 void saveLaunchingStateIfNeeded() {
1697 if (!hasBeenVisible) {
1698 // Not ever visible to user.
1699 return;
1700 }
1701
1702 final int windowingMode = getWindowingMode();
1703 if (windowingMode != WINDOWING_MODE_FULLSCREEN
1704 && windowingMode != WINDOWING_MODE_FREEFORM) {
1705 return;
1706 }
1707
1708 // Don't persist state if display isn't in freeform mode. Then the task will be launched
1709 // back to its last state in a freeform display when it's launched in a freeform display
1710 // next time.
1711 if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) {
1712 return;
1713 }
1714
1715 // Saves the new state so that we can launch the activity at the same location.
1716 mAtmService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
1717 }
1718
1719 /**
1720 * Adjust bounds to stay within stack bounds.
1721 *
1722 * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
1723 * that keep them unchanged, but be contained within the stack bounds.
1724 *
1725 * @param bounds Bounds to be adjusted.
1726 * @param stackBounds Bounds within which the other bounds should remain.
1727 * @param overlapPxX The amount of px required to be visible in the X dimension.
1728 * @param overlapPxY The amount of px required to be visible in the Y dimension.
1729 */
1730 private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
1731 int overlapPxY) {
1732 if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
1733 return;
1734 }
1735
1736 // For each side of the parent (eg. left), check if the opposing side of the window (eg.
1737 // right) is at least overlap pixels away. If less, offset the window by that difference.
1738 int horizontalDiff = 0;
1739 // If window is smaller than overlap, use it's smallest dimension instead
1740 int overlapLR = Math.min(overlapPxX, bounds.width());
1741 if (bounds.right < (stackBounds.left + overlapLR)) {
1742 horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
1743 } else if (bounds.left > (stackBounds.right - overlapLR)) {
1744 horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
1745 }
1746 int verticalDiff = 0;
1747 int overlapTB = Math.min(overlapPxY, bounds.width());
1748 if (bounds.bottom < (stackBounds.top + overlapTB)) {
1749 verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
1750 } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
1751 verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
1752 }
1753 bounds.offset(horizontalDiff, verticalDiff);
1754 }
1755
1756 /**
1757 * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
1758 * intersectBounds on a side, then the respective side will not be intersected.
1759 *
1760 * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
1761 * inset on that side is no-longer applicable. This scenario happens when a task's minimal
1762 * bounds are larger than the provided parent/display bounds.
1763 *
1764 * @param inOutBounds the bounds to intersect.
1765 * @param intersectBounds the bounds to intersect with.
1766 * @param intersectInsets insets to apply to intersectBounds before intersecting.
1767 */
1768 static void intersectWithInsetsIfFits(
1769 Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
1770 if (inOutBounds.right <= intersectBounds.right) {
1771 inOutBounds.right =
1772 Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
1773 }
1774 if (inOutBounds.bottom <= intersectBounds.bottom) {
1775 inOutBounds.bottom =
1776 Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
1777 }
1778 if (inOutBounds.left >= intersectBounds.left) {
1779 inOutBounds.left =
1780 Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
1781 }
1782 if (inOutBounds.top >= intersectBounds.top) {
1783 inOutBounds.top =
1784 Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
1785 }
1786 }
1787
1788 /**
1789 * Gets bounds with non-decor and stable insets applied respectively.
1790 *
1791 * If bounds overhangs the display, those edges will not get insets. See
1792 * {@link #intersectWithInsetsIfFits}
1793 *
1794 * @param outNonDecorBounds where to place bounds with non-decor insets applied.
1795 * @param outStableBounds where to place bounds with stable insets applied.
1796 * @param bounds the bounds to inset.
1797 */
1798 private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
1799 DisplayInfo displayInfo) {
1800 outNonDecorBounds.set(bounds);
1801 outStableBounds.set(bounds);
1802 if (getStack() == null || getStack().getDisplay() == null) {
1803 return;
1804 }
1805 DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
1806 if (policy == null) {
1807 return;
1808 }
1809 mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
1810
1811 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
1812 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
1813 intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
1814
1815 policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
1816 intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
1817 }
1818
1819 /**
1820 * Asks docked-divider controller for the smallestwidthdp given bounds.
1821 * @param bounds bounds to calculate smallestwidthdp for.
1822 */
1823 private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
1824 DisplayContent dc = mStack.getDisplay().mDisplayContent;
1825 if (dc != null) {
1826 return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
1827 }
1828 return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
1829 }
1830
1831 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1832 @NonNull Configuration parentConfig) {
1833 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
1834 }
1835
1836 /**
1837 * Calculates configuration values used by the client to get resources. This should be run
1838 * using app-facing bounds (bounds unmodified by animations or transient interactions).
1839 *
1840 * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
1841 * configuring an "inherit-bounds" window which means that all configuration settings would
1842 * just be inherited from the parent configuration.
1843 **/
1844 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1845 @NonNull Configuration parentConfig,
1846 @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
1847 int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
1848 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1849 windowingMode = parentConfig.windowConfiguration.getWindowingMode();
1850 }
1851
1852 float density = inOutConfig.densityDpi;
1853 if (density == Configuration.DENSITY_DPI_UNDEFINED) {
1854 density = parentConfig.densityDpi;
1855 }
1856 density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
1857
Evan Rosky70213702019-11-05 10:26:24 -08001858 final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
1859 if (resolvedBounds == null) {
1860 mTmpFullBounds.setEmpty();
1861 } else {
1862 mTmpFullBounds.set(resolvedBounds);
1863 }
1864 if (mTmpFullBounds.isEmpty()) {
1865 mTmpFullBounds.set(parentConfig.windowConfiguration.getBounds());
1866 }
1867
Louis Changcdec0802019-11-11 11:45:07 +08001868 Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
1869 if (outAppBounds == null || outAppBounds.isEmpty()) {
Evan Rosky70213702019-11-05 10:26:24 -08001870 inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds);
Louis Changcdec0802019-11-11 11:45:07 +08001871 outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
1872 }
1873 // Non-null compatibility insets means the activity prefers to keep its original size, so
1874 // the out bounds doesn't need to be restricted by the parent.
1875 final boolean insideParentBounds = compatInsets == null;
1876 if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
1877 final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
1878 if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
1879 outAppBounds.intersect(parentAppBounds);
1880 }
1881 }
1882
1883 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
1884 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
1885 if (insideParentBounds && mStack != null) {
1886 final DisplayInfo di = new DisplayInfo();
1887 mStack.getDisplay().mDisplay.getDisplayInfo(di);
1888
1889 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
1890 // area, i.e. the screen area without the system bars.
1891 // The non decor inset are areas that could never be removed in Honeycomb. See
1892 // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
Evan Rosky70213702019-11-05 10:26:24 -08001893 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);
Louis Changcdec0802019-11-11 11:45:07 +08001894 } else {
1895 // Apply the given non-decor and stable insets to calculate the corresponding bounds
1896 // for screen size of configuration.
1897 int rotation = inOutConfig.windowConfiguration.getRotation();
1898 if (rotation == ROTATION_UNDEFINED) {
1899 rotation = parentConfig.windowConfiguration.getRotation();
1900 }
1901 if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
Evan Rosky70213702019-11-05 10:26:24 -08001902 mTmpNonDecorBounds.set(mTmpFullBounds);
1903 mTmpStableBounds.set(mTmpFullBounds);
Louis Changcdec0802019-11-11 11:45:07 +08001904 compatInsets.getDisplayBoundsByRotation(mTmpBounds, rotation);
1905 intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
1906 compatInsets.mNonDecorInsets[rotation]);
1907 intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
1908 compatInsets.mStableInsets[rotation]);
1909 outAppBounds.set(mTmpNonDecorBounds);
1910 } else {
1911 // Set to app bounds because it excludes decor insets.
1912 mTmpNonDecorBounds.set(outAppBounds);
1913 mTmpStableBounds.set(outAppBounds);
1914 }
1915 }
1916
1917 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
1918 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
1919 inOutConfig.screenWidthDp = insideParentBounds
1920 ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
1921 : overrideScreenWidthDp;
1922 }
1923 if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
1924 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
1925 inOutConfig.screenHeightDp = insideParentBounds
1926 ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
1927 : overrideScreenHeightDp;
1928 }
1929
1930 if (inOutConfig.smallestScreenWidthDp
1931 == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
1932 if (WindowConfiguration.isFloating(windowingMode)) {
1933 // For floating tasks, calculate the smallest width from the bounds of the task
1934 inOutConfig.smallestScreenWidthDp = (int) (
Evan Rosky70213702019-11-05 10:26:24 -08001935 Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
Louis Changcdec0802019-11-11 11:45:07 +08001936 } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
1937 // Iterating across all screen orientations, and return the minimum of the task
1938 // width taking into account that the bounds might change because the snap
1939 // algorithm snaps to a different value
1940 inOutConfig.smallestScreenWidthDp =
Evan Rosky70213702019-11-05 10:26:24 -08001941 getSmallestScreenWidthDpForDockedBounds(mTmpFullBounds);
Louis Changcdec0802019-11-11 11:45:07 +08001942 }
1943 // otherwise, it will just inherit
1944 }
1945 }
1946
1947 if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
1948 inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
1949 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
1950 }
1951 if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
1952 // For calculating screen layout, we need to use the non-decor inset screen area for the
1953 // calculation for compatibility reasons, i.e. screen area without system bars that
1954 // could never go away in Honeycomb.
1955 final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
1956 final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
Louis Changcdec0802019-11-11 11:45:07 +08001957 // Reducing the screen layout starting from its parent config.
Riddle Hsuca928562019-11-22 01:04:14 +08001958 inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout,
1959 compatScreenWidthDp, compatScreenHeightDp);
Louis Changcdec0802019-11-11 11:45:07 +08001960 }
1961 }
1962
Riddle Hsuca928562019-11-22 01:04:14 +08001963 /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */
1964 static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp,
1965 int screenHeightDp) {
1966 sourceScreenLayout = sourceScreenLayout
1967 & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
1968 final int longSize = Math.max(screenWidthDp, screenHeightDp);
1969 final int shortSize = Math.min(screenWidthDp, screenHeightDp);
1970 return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
1971 }
1972
Louis Changcdec0802019-11-11 11:45:07 +08001973 @Override
1974 void resolveOverrideConfiguration(Configuration newParentConfig) {
1975 mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
1976 super.resolveOverrideConfiguration(newParentConfig);
1977 int windowingMode =
1978 getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
1979 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1980 windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
1981 }
1982 Rect outOverrideBounds =
1983 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
1984
1985 if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
1986 computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
1987 newParentConfig.windowConfiguration.getBounds(),
1988 newParentConfig.orientation);
1989 }
1990
Louis Changcdec0802019-11-11 11:45:07 +08001991 adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
1992 if (windowingMode == WINDOWING_MODE_FREEFORM) {
1993 // by policy, make sure the window remains within parent somewhere
1994 final float density =
1995 ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
1996 final Rect parentBounds =
1997 new Rect(newParentConfig.windowConfiguration.getBounds());
1998 final ActivityDisplay display = mStack.getDisplay();
1999 if (display != null && display.mDisplayContent != null) {
2000 // If a freeform window moves below system bar, there is no way to move it again
2001 // by touch. Because its caption is covered by system bar. So we exclude them
2002 // from stack bounds. and then caption will be shown inside stable area.
2003 final Rect stableBounds = new Rect();
2004 display.mDisplayContent.getStableRect(stableBounds);
2005 parentBounds.intersect(stableBounds);
2006 }
2007
2008 fitWithinBounds(outOverrideBounds, parentBounds,
2009 (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
2010 (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
2011
2012 // Prevent to overlap caption with stable insets.
2013 final int offsetTop = parentBounds.top - outOverrideBounds.top;
2014 if (offsetTop > 0) {
2015 outOverrideBounds.offset(0, offsetTop);
2016 }
2017 }
2018 computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
2019 }
2020
2021 /**
2022 * Compute bounds (letterbox or pillarbox) for
2023 * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
2024 * orientation change and the requested orientation is different from the parent.
2025 */
2026 void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
2027 @NonNull Rect parentBounds, int parentOrientation) {
2028 // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
2029 outBounds.setEmpty();
2030 if (handlesOrientationChangeFromDescendant()) {
2031 return;
2032 }
2033 if (refActivity == null) {
2034 // Use the top activity as the reference of orientation. Don't include overlays because
2035 // it is usually not the actual content or just temporarily shown.
2036 // E.g. ForcedResizableInfoActivity.
Wale Ogunwale21e06482019-11-18 05:14:15 -08002037 refActivity = getTopNonFinishingActivity(false /* includeOverlays */);
Louis Changcdec0802019-11-11 11:45:07 +08002038 }
2039
2040 // If the task or the reference activity requires a different orientation (either by
2041 // override or activityInfo), make it fit the available bounds by scaling down its bounds.
2042 final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
2043 final int forcedOrientation =
2044 (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
2045 ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
2046 if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
2047 return;
2048 }
2049
2050 final int parentWidth = parentBounds.width();
2051 final int parentHeight = parentBounds.height();
2052 final float aspect = ((float) parentHeight) / parentWidth;
2053 if (forcedOrientation == ORIENTATION_LANDSCAPE) {
2054 final int height = (int) (parentWidth / aspect);
2055 final int top = parentBounds.centerY() - height / 2;
2056 outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
2057 } else {
2058 final int width = (int) (parentHeight * aspect);
2059 final int left = parentBounds.centerX() - width / 2;
2060 outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
2061 }
2062 }
2063
2064 Rect updateOverrideConfigurationFromLaunchBounds() {
2065 final Rect bounds = getLaunchBounds();
2066 setBounds(bounds);
2067 if (bounds != null && !bounds.isEmpty()) {
2068 // TODO: Review if we actually want to do this - we are setting the launch bounds
2069 // directly here.
2070 bounds.set(getRequestedOverrideBounds());
2071 }
2072 return bounds;
2073 }
2074
2075 /** Updates the task's bounds and override configuration to match what is expected for the
2076 * input stack. */
2077 void updateOverrideConfigurationForStack(ActivityStack inStack) {
2078 if (mStack != null && mStack == inStack) {
2079 return;
2080 }
2081
2082 if (inStack.inFreeformWindowingMode()) {
2083 if (!isResizeable()) {
2084 throw new IllegalArgumentException("Can not position non-resizeable task="
2085 + this + " in stack=" + inStack);
2086 }
2087 if (!matchParentBounds()) {
2088 return;
2089 }
2090 if (mLastNonFullscreenBounds != null) {
2091 setBounds(mLastNonFullscreenBounds);
2092 } else {
2093 mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
2094 }
2095 } else {
2096 setBounds(inStack.getRequestedOverrideBounds());
2097 }
2098 }
2099
2100 /** Returns the bounds that should be used to launch this task. */
2101 Rect getLaunchBounds() {
2102 if (mStack == null) {
2103 return null;
2104 }
2105
2106 final int windowingMode = getWindowingMode();
2107 if (!isActivityTypeStandardOrUndefined()
2108 || windowingMode == WINDOWING_MODE_FULLSCREEN
2109 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
2110 return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
2111 } else if (!getWindowConfiguration().persistTaskBounds()) {
2112 return mStack.getRequestedOverrideBounds();
2113 }
2114 return mLastNonFullscreenBounds;
2115 }
2116
Louis Changcdec0802019-11-11 11:45:07 +08002117 void setRootProcess(WindowProcessController proc) {
2118 clearRootProcess();
2119 if (intent != null
2120 && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
2121 mRootProcess = proc;
2122 mRootProcess.addRecentTask(this);
2123 }
2124 }
2125
2126 void clearRootProcess() {
2127 if (mRootProcess != null) {
2128 mRootProcess.removeRecentTask(this);
2129 mRootProcess = null;
2130 }
2131 }
2132
Tiger Huanged6794e2019-05-07 20:07:59 +08002133 @Override
Craig Mautnerc00204b2013-03-05 15:02:14 -08002134 DisplayContent getDisplayContent() {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002135 return getTaskStack() != null ? getTaskStack().getDisplayContent() : null;
2136 }
2137
Louis Changdc077272019-11-12 16:52:56 +08002138 ActivityStack getTaskStack() {
2139 return (ActivityStack) getParent();
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002140 }
2141
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002142 // TODO(task-hierarchy): Needs to take a generic WindowManager when task contains other tasks.
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002143 int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
2144 int maxPosition = mChildren.size();
2145 if (!r.mTaskOverlay) {
2146 // We want to place all non-overlay activities below overlays.
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002147 final ActivityRecord bottomMostOverlay = getActivity((ar) -> ar.mTaskOverlay, false);
2148 if (bottomMostOverlay != null) {
2149 maxPosition = Math.max(mChildren.indexOf(bottomMostOverlay) - 1, 0);
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002150 }
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002151 }
2152
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002153 return Math.min(maxPosition, suggestedPosition);
Craig Mautnerc00204b2013-03-05 15:02:14 -08002154 }
2155
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002156 @Override
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002157 void positionChildAt(int position, WindowContainer child, boolean includingParents) {
2158 position = getAdjustedAddPosition((ActivityRecord) child, position);
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002159 super.positionChildAt(position, child, includingParents);
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002160 }
2161
Wale Ogunwalee42d0e12016-05-02 16:40:59 -07002162 private boolean hasWindowsAlive() {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002163 return getActivity(ActivityRecord::hasWindowsAlive) != null;
Chong Zhang7e8eeb72016-01-06 19:14:47 -08002164 }
2165
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002166 @VisibleForTesting
2167 boolean shouldDeferRemoval() {
Wale Ogunwalec17418e2019-10-13 23:00:40 +02002168 if (mChildren.isEmpty()) {
2169 // No reason to defer removal of a Task that doesn't have any child.
2170 return false;
2171 }
Wale Ogunwale8577a052019-10-26 23:22:34 -07002172 return hasWindowsAlive() && getTaskStack().isAnimating(TRANSITION | CHILDREN);
Wale Ogunwalec5cc3012017-01-13 13:26:16 -08002173 }
2174
Wale Ogunwalef6192862016-09-10 13:42:30 -07002175 @Override
Andrii Kulian45a61fe2017-01-05 16:53:19 -08002176 void removeImmediately() {
Wale Ogunwaleb9b16a72016-01-27 12:24:44 -08002177 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
Jeff Changd136e772019-11-05 20:33:52 +08002178 EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
Andrii Kulian45a61fe2017-01-05 16:53:19 -08002179 super.removeImmediately();
Craig Mautnere3119b72015-01-20 15:02:36 -08002180 }
2181
Louis Changcdec0802019-11-11 11:45:07 +08002182 // TODO: Consolidate this with Task.reparent()
Louis Changdc077272019-11-12 16:52:56 +08002183 void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -08002184 if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
Wale Ogunwale8577a052019-10-26 23:22:34 -07002185 + " from stack=" + getTaskStack());
Jeff Changd136e772019-11-05 20:33:52 +08002186 EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask");
Andrii Kulian7cd7c2d2017-01-18 12:14:37 -08002187
Louis Changdc077272019-11-12 16:52:56 +08002188 final ActivityStack prevStack = getTaskStack();
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002189 final boolean wasTopFocusedStack =
2190 mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack);
2191 final ActivityDisplay prevStackDisplay = prevStack.getDisplay();
2192
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -07002193 position = stack.findPositionForTask(this, position, showForAllUsers());
2194
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002195 reparent(stack, position);
2196
2197 if (!moveParents) {
2198 // Only move home stack forward if we are not going to move the new parent forward.
2199 prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason);
Robert Carr18f622f2017-05-08 11:20:43 -07002200 }
2201
Louis Changcdec0802019-11-11 11:45:07 +08002202 stack.positionChildAt(position, this, moveParents);
Andrii Kulian7cd7c2d2017-01-18 12:14:37 -08002203
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002204 // If we are moving from the fullscreen stack to the pinned stack then we want to preserve
2205 // our insets so that there will not be a jump in the area covered by system decorations.
2206 // We rely on the pinned animation to later unset this value.
2207 mPreserveNonFloatingState = stack.inPinnedWindowingMode();
Wale Ogunwale53a29a92015-02-23 15:42:52 -08002208 }
2209
Bryce Leef3c6a472017-11-14 14:53:06 -08002210 public int setBounds(Rect bounds, boolean forceResize) {
2211 final int boundsChanged = setBounds(bounds);
2212
2213 if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) {
2214 onResize();
2215 return BOUNDS_CHANGE_SIZE | boundsChanged;
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -07002216 }
Wale Ogunwale68278562017-09-23 17:13:55 -07002217
Bryce Leef3c6a472017-11-14 14:53:06 -08002218 return boundsChanged;
2219 }
2220
2221 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
2222 @Override
2223 public int setBounds(Rect bounds) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002224 int rotation = Surface.ROTATION_0;
Wale Ogunwale8577a052019-10-26 23:22:34 -07002225 final DisplayContent displayContent = getTaskStack() != null
2226 ? getTaskStack().getDisplayContent() : null;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002227 if (displayContent != null) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002228 rotation = displayContent.getDisplayInfo().rotation;
Bryce Leef3c6a472017-11-14 14:53:06 -08002229 } else if (bounds == null) {
Evan Roskye747c3e2018-10-30 20:06:41 -07002230 return super.setBounds(bounds);
Wale Ogunwale2cc92f52015-09-09 13:12:10 -07002231 }
2232
Bryce Leef3c6a472017-11-14 14:53:06 -08002233 final int boundsChange = super.setBounds(bounds);
Chong Zhangf66db432016-01-13 10:39:51 -08002234
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002235 mRotation = rotation;
Robert Carrf59b8dd2017-10-02 18:58:36 -07002236
Evan Rosky89f5c1d2019-01-29 10:04:05 -08002237 updateSurfacePosition();
Wale Ogunwale2cc92f52015-09-09 13:12:10 -07002238 return boundsChange;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002239 }
2240
Garfield Tan90b04282018-12-11 14:04:42 -08002241 @Override
2242 public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
2243 ConfigurationContainer requestingContainer) {
2244 if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
2245 return true;
2246 }
2247
2248 // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
2249 // it if possible.
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002250 if (getParent() != null) {
2251 onConfigurationChanged(getParent().getConfiguration());
Garfield Tan90b04282018-12-11 14:04:42 -08002252 return true;
2253 }
2254 return false;
2255 }
2256
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002257 void resize(boolean relayout, boolean forced) {
2258 if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) {
2259 getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
2260 }
2261 }
2262
Louis Chang7501e332018-08-20 13:08:39 +08002263 @Override
2264 void onDisplayChanged(DisplayContent dc) {
Garfield Tan2f145f22018-11-01 15:27:03 -07002265 adjustBoundsForDisplayChangeIfNeeded(dc);
Louis Chang7501e332018-08-20 13:08:39 +08002266 super.onDisplayChanged(dc);
davidln1ceedb52019-05-30 14:25:01 -07002267 final int displayId = (dc != null) ? dc.getDisplayId() : Display.INVALID_DISPLAY;
2268 mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
2269 mTaskId, displayId);
Louis Chang7501e332018-08-20 13:08:39 +08002270 }
2271
Jorim Jaggidc249c42015-12-15 14:57:31 -08002272 /**
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002273 * Displayed bounds are used to set where the task is drawn at any given time. This is
2274 * separate from its actual bounds so that the app doesn't see any meaningful configuration
2275 * changes during transitionary periods.
Jorim Jaggidc249c42015-12-15 14:57:31 -08002276 */
Evan Roskyed6767f2018-10-26 17:21:06 -07002277 void setOverrideDisplayedBounds(Rect overrideDisplayedBounds) {
2278 if (overrideDisplayedBounds != null) {
2279 mOverrideDisplayedBounds.set(overrideDisplayedBounds);
Jorim Jaggidc249c42015-12-15 14:57:31 -08002280 } else {
Evan Roskyed6767f2018-10-26 17:21:06 -07002281 mOverrideDisplayedBounds.setEmpty();
Jorim Jaggidc249c42015-12-15 14:57:31 -08002282 }
Evan Rosky89f5c1d2019-01-29 10:04:05 -08002283 updateSurfacePosition();
Jorim Jaggidc249c42015-12-15 14:57:31 -08002284 }
2285
2286 /**
Evan Roskyed6767f2018-10-26 17:21:06 -07002287 * Gets the bounds that override where the task is displayed. See
Wale Ogunwale04d9cb52018-04-30 13:55:07 -07002288 * {@link android.app.IActivityTaskManager#resizeDockedStack} why this is needed.
Jorim Jaggidc249c42015-12-15 14:57:31 -08002289 */
Evan Roskyed6767f2018-10-26 17:21:06 -07002290 Rect getOverrideDisplayedBounds() {
2291 return mOverrideDisplayedBounds;
Jorim Jaggidc249c42015-12-15 14:57:31 -08002292 }
2293
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002294 boolean isResizeable(boolean checkSupportsPip) {
2295 return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
2296 || (checkSupportsPip && mSupportsPictureInPicture));
Chong Zhangb15758a2015-11-17 12:12:03 -08002297 }
2298
2299 boolean isResizeable() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002300 return isResizeable(true /* checkSupportsPip */);
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08002301 }
2302
skuhne@google.com322347b2016-12-02 12:54:03 -08002303 /**
2304 * Tests if the orientation should be preserved upon user interactive resizig operations.
2305
2306 * @return true if orientation should not get changed upon resizing operation.
2307 */
2308 boolean preserveOrientationOnResize() {
2309 return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY
2310 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY
2311 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
2312 }
2313
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08002314 boolean cropWindowsToStackBounds() {
Wale Ogunwaledf241e92016-10-13 15:14:21 -07002315 return isResizeable();
Wale Ogunwaleb1faf602016-01-27 09:12:31 -08002316 }
2317
Jorim Jaggi0429f352015-12-22 16:29:16 +01002318 /**
2319 * Prepares the task bounds to be frozen with the current size. See
Garfield Tane8d84ab2019-10-11 09:49:40 -07002320 * {@link ActivityRecord#freezeBounds}.
Jorim Jaggi0429f352015-12-22 16:29:16 +01002321 */
2322 void prepareFreezingBounds() {
Bryce Leef3c6a472017-11-14 14:53:06 -08002323 mPreparedFrozenBounds.set(getBounds());
Andrii Kulian441e4492016-09-29 15:25:00 -07002324 mPreparedFrozenMergedConfig.setTo(getConfiguration());
Jorim Jaggi0429f352015-12-22 16:29:16 +01002325 }
2326
Chong Zhang5117e272016-05-03 12:47:34 -07002327 /**
2328 * Align the task to the adjusted bounds.
2329 *
2330 * @param adjustedBounds Adjusted bounds to which the task should be aligned.
2331 * @param tempInsetBounds Insets bounds for the task.
2332 * @param alignBottom True if the task's bottom should be aligned to the adjusted
2333 * bounds's bottom; false if the task's top should be aligned
2334 * the adjusted bounds's top.
2335 */
Andrii Kulian441e4492016-09-29 15:25:00 -07002336 void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
Evan Roskydfe3da72018-10-26 17:21:06 -07002337 if (!isResizeable() || EMPTY.equals(getRequestedOverrideConfiguration())) {
Chong Zhang5117e272016-05-03 12:47:34 -07002338 return;
2339 }
2340
2341 getBounds(mTmpRect2);
2342 if (alignBottom) {
2343 int offsetY = adjustedBounds.bottom - mTmpRect2.bottom;
2344 mTmpRect2.offset(0, offsetY);
2345 } else {
2346 mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
2347 }
Evan Roskyed6767f2018-10-26 17:21:06 -07002348 if (tempInsetBounds == null || tempInsetBounds.isEmpty()) {
2349 setOverrideDisplayedBounds(null);
2350 setBounds(mTmpRect2);
2351 } else {
2352 setOverrideDisplayedBounds(mTmpRect2);
2353 setBounds(tempInsetBounds);
2354 }
Chong Zhang5117e272016-05-03 12:47:34 -07002355 }
2356
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002357 /**
2358 * Gets the current overridden displayed bounds. These will be empty if the task is not
2359 * currently overriding where it is displayed.
2360 */
Evan Roskyed6767f2018-10-26 17:21:06 -07002361 @Override
2362 public Rect getDisplayedBounds() {
2363 if (mOverrideDisplayedBounds.isEmpty()) {
2364 return super.getDisplayedBounds();
2365 } else {
2366 return mOverrideDisplayedBounds;
2367 }
2368 }
2369
Issei Suzukiad287d02019-10-31 16:19:44 +01002370 @Override
2371 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
2372 Rect outSurfaceInsets) {
2373 final WindowState windowState = getTopVisibleAppMainWindow();
2374 if (windowState != null) {
2375 windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2376 } else {
2377 super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2378 }
2379 }
2380
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002381 /**
2382 * Calculate the maximum visible area of this task. If the task has only one app,
2383 * the result will be visible frame of that app. If the task has more than one apps,
2384 * we search from top down if the next app got different visible area.
2385 *
2386 * This effort is to handle the case where some task (eg. GMail composer) might pop up
2387 * a dialog that's different in size from the activity below, in which case we should
2388 * be dimming the entire task area behind the dialog.
2389 *
2390 * @param out Rect containing the max visible bounds.
2391 * @return true if the task has some visible app windows; false otherwise.
2392 */
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002393 private static void getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop) {
2394 // skip hidden (or about to hide) apps
2395 if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) {
2396 return;
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002397 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002398 final WindowState win = token.findMainWindow();
2399 if (win == null) {
2400 return;
2401 }
2402 if (!foundTop[0]) {
2403 foundTop[0] = true;
2404 out.setEmpty();
2405 }
2406
2407 win.getMaxVisibleBounds(out);
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002408 }
2409
2410 /** Bounds of the task to be used for dimming, as well as touch related tests. */
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002411 public void getDimBounds(Rect out) {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002412 final DisplayContent displayContent = getTaskStack().getDisplayContent();
Robert Carra86a6bf2016-04-08 17:34:16 -07002413 // It doesn't matter if we in particular are part of the resize, since we couldn't have
2414 // a DimLayer anyway if we weren't visible.
Wale Ogunwalef6192862016-09-10 13:42:30 -07002415 final boolean dockedResizing = displayContent != null
2416 && displayContent.mDividerControllerLocked.isResizing();
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002417 if (inFreeformWindowingMode()) {
2418 boolean[] foundTop = { false };
2419 final PooledConsumer c = PooledLambda.obtainConsumer(Task::getMaxVisibleBounds,
2420 PooledLambda.__(ActivityRecord.class), out, foundTop);
2421 c.recycle();
2422 if (foundTop[0]) {
2423 return;
2424 }
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002425 }
2426
Evan Rosky4fb1e912019-03-06 13:54:43 -08002427 if (!matchParentBounds()) {
2428 // When minimizing the docked stack when going home, we don't adjust the task bounds
2429 // so we need to intersect the task bounds with the stack bounds here.
2430 //
2431 // If we are Docked Resizing with snap points, the task bounds could be smaller than the
2432 // stack bounds and so we don't even want to use them. Even if the app should not be
2433 // resized the Dim should keep up with the divider.
2434 if (dockedResizing) {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002435 getTaskStack().getBounds(out);
Evan Rosky4fb1e912019-03-06 13:54:43 -08002436 } else {
Wale Ogunwale8577a052019-10-26 23:22:34 -07002437 getTaskStack().getBounds(mTmpRect);
Evan Rosky4fb1e912019-03-06 13:54:43 -08002438 mTmpRect.intersect(getBounds());
2439 out.set(mTmpRect);
2440 }
2441 } else {
2442 out.set(getBounds());
Wale Ogunwalef6192862016-09-10 13:42:30 -07002443 }
Evan Rosky4fb1e912019-03-06 13:54:43 -08002444 return;
Chong Zhang4c9ba52a2015-11-10 18:36:33 -08002445 }
2446
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002447 void setDragResizing(boolean dragResizing, int dragResizeMode) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -08002448 if (mDragResizing != dragResizing) {
chaviw8c9d1f52018-07-25 14:56:07 -07002449 // No need to check if the mode is allowed if it's leaving dragResize
Wale Ogunwale8577a052019-10-26 23:22:34 -07002450 if (dragResizing && !DragResizeMode.isModeAllowedForStack(getTaskStack(), dragResizeMode)) {
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002451 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
Wale Ogunwale8577a052019-10-26 23:22:34 -07002452 + getTaskStack().mStackId + " dragResizeMode=" + dragResizeMode);
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002453 }
Jorim Jaggic662d8e2016-02-05 16:54:54 -08002454 mDragResizing = dragResizing;
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002455 mDragResizeMode = dragResizeMode;
Jorim Jaggic662d8e2016-02-05 16:54:54 -08002456 resetDragResizingChangeReported();
2457 }
2458 }
2459
Chong Zhang3005e752015-09-18 18:46:28 -07002460 boolean isDragResizing() {
Wale Ogunwaled1c37912016-08-16 03:19:39 -07002461 return mDragResizing;
Chong Zhang3005e752015-09-18 18:46:28 -07002462 }
2463
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +01002464 int getDragResizeMode() {
2465 return mDragResizeMode;
2466 }
2467
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002468 /**
2469 * Puts this task into docked drag resizing mode. See {@link DragResizeMode}.
2470 *
2471 * @param resizing Whether to put the task into drag resize mode.
2472 */
2473 public void setTaskDockedResizing(boolean resizing) {
2474 setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
2475 }
2476
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002477 void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002478 if (displayContent == null) {
2479 return;
2480 }
Bryce Leef3c6a472017-11-14 14:53:06 -08002481 if (matchParentBounds()) {
Wale Ogunwale68278562017-09-23 17:13:55 -07002482 // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a
2483 // problem once we move mBounds into WindowConfiguration.
Bryce Leef3c6a472017-11-14 14:53:06 -08002484 setBounds(null);
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002485 return;
2486 }
Garfield Tandec96db2018-10-30 11:28:49 -07002487 final int displayId = displayContent.getDisplayId();
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002488 final int newRotation = displayContent.getDisplayInfo().rotation;
Garfield Tandec96db2018-10-30 11:28:49 -07002489 if (displayId != mLastRotationDisplayId) {
2490 // This task is on a display that it wasn't on. There is no point to keep the relative
2491 // position if display rotations for old and new displays are different. Just keep these
2492 // values.
2493 mLastRotationDisplayId = displayId;
2494 mRotation = newRotation;
2495 return;
2496 }
2497
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002498 if (mRotation == newRotation) {
Garfield Tandec96db2018-10-30 11:28:49 -07002499 // Rotation didn't change. We don't need to adjust the bounds to keep the relative
2500 // position.
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002501 return;
2502 }
2503
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002504 // Device rotation changed.
Chong Zhang2e2c81a2016-07-15 11:28:17 -07002505 // - We don't want the task to move around on the screen when this happens, so update the
2506 // task bounds so it stays in the same place.
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002507 // - Rotate the bounds and notify activity manager if the task can be resized independently
Chong Zhang2e2c81a2016-07-15 11:28:17 -07002508 // from its stack. The stack will take care of task rotation for the other case.
Bryce Leef3c6a472017-11-14 14:53:06 -08002509 mTmpRect2.set(getBounds());
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002510
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002511 if (!getWindowConfiguration().canResizeTask()) {
Bryce Leef3c6a472017-11-14 14:53:06 -08002512 setBounds(mTmpRect2);
Wale Ogunwalee1fe4d12016-01-14 08:52:30 -08002513 return;
2514 }
2515
Wale Ogunwale94744212015-09-21 19:01:47 -07002516 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
Bryce Leef3c6a472017-11-14 14:53:06 -08002517 if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002518 mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
Wale Ogunwale1ed0d892015-09-28 13:27:44 -07002519 }
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002520 }
2521
Wale Ogunwalef6192862016-09-10 13:42:30 -07002522 /** Cancels any running app transitions associated with the task. */
Winsonc28098f2015-10-30 14:50:19 -07002523 void cancelTaskWindowTransition() {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002524 for (int i = mChildren.size() - 1; i >= 0; --i) {
Jorim Jaggif5f9e122017-10-24 18:21:09 +02002525 mChildren.get(i).cancelAnimation();
Winsonc28098f2015-10-30 14:50:19 -07002526 }
2527 }
2528
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -07002529 boolean showForAllUsers() {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002530 if (mChildren.isEmpty()) return false;
2531 final ActivityRecord r = getTopNonFinishingActivity();
2532 return r != null && r.mShowForAllUsers;
Jorim Jaggiff71d202016-04-14 13:12:36 -07002533 }
2534
Robert Carr7e4c90e2017-02-15 19:52:38 -08002535 /**
2536 * When we are in a floating stack (Freeform, Pinned, ...) we calculate
2537 * insets differently. However if we are animating to the fullscreen stack
2538 * we need to begin calculating insets as if we were fullscreen, otherwise
2539 * we will have a jump at the end.
2540 */
Robert Carre6275582016-02-29 15:45:45 -08002541 boolean isFloating() {
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002542 return getWindowConfiguration().tasksAreFloating()
Wale Ogunwale8577a052019-10-26 23:22:34 -07002543 && !getTaskStack().isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
Robert Carre6275582016-02-29 15:45:45 -08002544 }
2545
Winson Chungd41f71d2018-03-16 15:26:07 -07002546 @Override
2547 public SurfaceControl getAnimationLeashParent() {
Riddle Hsud8302832019-09-23 21:14:07 +08002548 if (WindowManagerService.sHierarchicalAnimations) {
Issei Suzuki71142152019-08-15 14:39:40 +02002549 return super.getAnimationLeashParent();
2550 }
Winson Chung732446a2018-09-19 13:15:17 -07002551 // Currently, only the recents animation will create animation leashes for tasks. In this
2552 // case, reparent the task to the home animation layer while it is being animated to allow
2553 // the home activity to reorder the app windows relative to its own.
2554 return getAppAnimationLayer(ANIMATION_LAYER_HOME);
Winson Chungd41f71d2018-03-16 15:26:07 -07002555 }
2556
lumark19a5d2e2019-10-11 16:19:30 +08002557 boolean shouldAnimate() {
2558 // Don't animate while the task runs recents animation but only if we are in the mode
2559 // where we cancel with deferred screenshot, which means that the controller has
2560 // transformed the task.
2561 final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
2562 if (controller != null && controller.isAnimatingTask(this)
2563 && controller.shouldDeferCancelUntilNextTransition()) {
2564 return false;
2565 }
2566 return true;
2567 }
2568
Evan Rosky9020c072018-12-06 14:11:12 -08002569 @Override
2570 SurfaceControl.Builder makeSurface() {
2571 return super.makeSurface().setMetadata(METADATA_TASK_ID, mTaskId);
2572 }
2573
Winson Chungd41f71d2018-03-16 15:26:07 -07002574 boolean isTaskAnimating() {
Wale Ogunwale8b19de92018-11-29 19:58:26 -08002575 final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController();
Winson Chungd41f71d2018-03-16 15:26:07 -07002576 if (recentsAnim != null) {
2577 if (recentsAnim.isAnimatingTask(this)) {
2578 return true;
2579 }
2580 }
2581 return false;
2582 }
2583
lumark19a5d2e2019-10-11 16:19:30 +08002584 /**
2585 * @return {@code true} if changing app transition is running.
2586 */
2587 @Override
2588 boolean isChangingAppTransition() {
2589 final ActivityRecord activity = getTopVisibleActivity();
2590 return activity != null && getDisplayContent().mChangingApps.contains(activity);
2591 }
2592
2593 @Override
2594 RemoteAnimationTarget createRemoteAnimationTarget(
2595 RemoteAnimationController.RemoteAnimationRecord record) {
2596 final ActivityRecord activity = getTopVisibleActivity();
2597 return activity != null ? activity.createRemoteAnimationTarget(record) : null;
2598 }
2599
Chong Zhangd8ceb852015-11-11 14:53:41 -08002600 WindowState getTopVisibleAppMainWindow() {
Garfield Tane8d84ab2019-10-11 09:49:40 -07002601 final ActivityRecord activity = getTopVisibleActivity();
2602 return activity != null ? activity.findMainWindow() : null;
Chong Zhang9184ec62015-09-24 12:32:21 -07002603 }
2604
Garfield Tane8d84ab2019-10-11 09:49:40 -07002605 ActivityRecord getTopFullscreenActivity() {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002606 return getActivity((r) -> {
2607 final WindowState win = r.findMainWindow();
2608 return (win != null && win.mAttrs.isFullscreen());
2609 });
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +02002610 }
2611
Garfield Tane8d84ab2019-10-11 09:49:40 -07002612 ActivityRecord getTopVisibleActivity() {
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002613 return getActivity((r) -> {
2614 // skip hidden (or about to hide) apps
2615 return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested;
2616 });
Chong Zhangbef461f2015-10-27 11:38:24 -07002617 }
2618
Wale Ogunwale3198da42019-10-10 14:45:03 +02002619 void positionChildAtTop(ActivityRecord child) {
2620 positionChildAt(child, POSITION_TOP);
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002621 }
2622
Wale Ogunwale3198da42019-10-10 14:45:03 +02002623 void positionChildAt(ActivityRecord child, int position) {
2624 if (child == null) {
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002625 Slog.w(TAG_WM,
2626 "Attempted to position of non-existing app");
2627 return;
2628 }
2629
Wale Ogunwale3198da42019-10-10 14:45:03 +02002630 positionChildAt(position, child, false /* includeParents */);
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002631 }
2632
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002633 void forceWindowsScaleable(boolean force) {
Wale Ogunwale8b19de92018-11-29 19:58:26 -08002634 mWmService.openSurfaceTransaction();
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002635 try {
Wale Ogunwalef6192862016-09-10 13:42:30 -07002636 for (int i = mChildren.size() - 1; i >= 0; i--) {
2637 mChildren.get(i).forceWindowsScaleableInTransaction(force);
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002638 }
2639 } finally {
Wale Ogunwale8b19de92018-11-29 19:58:26 -08002640 mWmService.closeSurfaceTransaction("forceWindowsScaleable");
Wale Ogunwale9f25bee2016-08-02 07:23:47 -07002641 }
2642 }
2643
Jorim Jaggi829b9cd2017-01-23 16:20:53 +01002644 void setTaskDescription(TaskDescription taskDescription) {
2645 mTaskDescription = taskDescription;
2646 }
2647
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002648 void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002649 mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
2650 mTaskId, snapshot);
Yunfan Chen0e7aff92018-12-05 16:35:32 -08002651 }
2652
Jorim Jaggi829b9cd2017-01-23 16:20:53 +01002653 TaskDescription getTaskDescription() {
2654 return mTaskDescription;
2655 }
2656
Wale Ogunwalef6192862016-09-10 13:42:30 -07002657 @Override
Wale Ogunwale51362492016-09-08 17:49:17 -07002658 boolean fillsParent() {
Bryce Leef3c6a472017-11-14 14:53:06 -08002659 return matchParentBounds() || !getWindowConfiguration().canResizeTask();
Wale Ogunwale51362492016-09-08 17:49:17 -07002660 }
2661
Jorim Jaggi329a5832017-01-05 18:57:12 +01002662 @Override
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09002663 void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
2664 // TODO(task-hierarchy): Change to traverse children when tasks can contain other tasks.
Jorim Jaggi51304d72017-05-17 17:25:32 +02002665 callback.accept(this);
2666 }
2667
lumarkbc0032a2019-11-01 21:38:13 +08002668 @Override
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09002669 boolean forAllTasks(Function<Task, Boolean> callback) {
lumarkbc0032a2019-11-01 21:38:13 +08002670 return callback.apply(this);
2671 }
2672
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002673 @Override
2674 Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
2675 // I'm a task!
2676 // TODO(task-hierarchy): Change to traverse children when tasks can contain other tasks.
2677 return callback.test(this) ? this : null;
2678 }
2679
Jorim Jaggi50bf59c2018-03-09 17:29:48 +01002680 /**
2681 * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI
2682 * flags. See {@link WindowState#canAffectSystemUiFlags()}.
2683 */
2684 void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) {
2685 mCanAffectSystemUiFlags = canAffectSystemUiFlags;
2686 }
2687
2688 /**
2689 * @see #setCanAffectSystemUiFlags
2690 */
2691 boolean canAffectSystemUiFlags() {
2692 return mCanAffectSystemUiFlags;
2693 }
2694
chaviw87ca63a2018-03-26 14:06:17 -07002695 void dontAnimateDimExit() {
2696 mDimmer.dontAnimateExit();
2697 }
2698
Wale Ogunwale9adfe572016-09-08 20:43:58 -07002699 String getName() {
Louis Changcdec0802019-11-11 11:45:07 +08002700 return "Task=" + mTaskId;
Wale Ogunwale9adfe572016-09-08 20:43:58 -07002701 }
2702
Robert Carr18f622f2017-05-08 11:20:43 -07002703 void clearPreserveNonFloatingState() {
2704 mPreserveNonFloatingState = false;
2705 }
2706
chaviw2fb06bc2018-01-19 17:09:15 -08002707 @Override
Robert Carrf59b8dd2017-10-02 18:58:36 -07002708 Dimmer getDimmer() {
2709 return mDimmer;
2710 }
2711
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09002712 boolean isTaskForUser(int userId) {
2713 return mUserId == userId;
2714 }
2715
Filip Gruszczynski0689ae92015-10-01 12:30:31 -07002716 @Override
Robert Carrf59b8dd2017-10-02 18:58:36 -07002717 void prepareSurfaces() {
2718 mDimmer.resetDimStates();
2719 super.prepareSurfaces();
2720 getDimBounds(mTmpDimBoundsRect);
chaviwe07246a2017-12-12 16:18:29 -08002721
2722 // Bounds need to be relative, as the dim layer is a child.
2723 mTmpDimBoundsRect.offsetTo(0, 0);
Robert Carrf59b8dd2017-10-02 18:58:36 -07002724 if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
2725 scheduleAnimation();
2726 }
Filip Gruszczynski0689ae92015-10-01 12:30:31 -07002727 }
2728
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002729 // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged.
Jeffrey Huangcb782852019-12-05 11:28:11 -08002730 void dumpDebugInnerTaskOnly(ProtoOutputStream proto, long fieldId,
Nataniel Borges023ecb52019-01-16 14:15:43 -08002731 @WindowTraceLogLevel int logLevel) {
2732 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
2733 return;
2734 }
2735
Steven Timotiusaf03df62017-07-18 16:56:43 -07002736 final long token = proto.start(fieldId);
Jeffrey Huangcb782852019-12-05 11:28:11 -08002737 super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
Louis Changcdec0802019-11-11 11:45:07 +08002738 proto.write(TaskProto.ID, mTaskId);
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002739 forAllActivities((r) -> {
Jeffrey Huangcb782852019-12-05 11:28:11 -08002740 r.dumpDebug(proto, APP_WINDOW_TOKENS, logLevel);
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002741 });
Bryce Leef3c6a472017-11-14 14:53:06 -08002742 proto.write(FILLS_PARENT, matchParentBounds());
Jeffrey Huangcb782852019-12-05 11:28:11 -08002743 getBounds().dumpDebug(proto, TaskProto.BOUNDS);
2744 mOverrideDisplayedBounds.dumpDebug(proto, DISPLAYED_BOUNDS);
Wale Ogunwale2322bed2019-10-10 17:24:19 +02002745 if (mSurfaceControl != null) {
2746 proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
2747 proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
2748 }
Steven Timotiusaf03df62017-07-18 16:56:43 -07002749 proto.end(token);
2750 }
2751
Jorim Jaggif5f9e122017-10-24 18:21:09 +02002752 @Override
2753 public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
2754 super.dump(pw, prefix, dumpAll);
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002755 final String doublePrefix = prefix + " ";
2756
2757 pw.println(prefix + "taskId=" + mTaskId);
Bryce Leef3c6a472017-11-14 14:53:06 -08002758 pw.println(doublePrefix + "mBounds=" + getBounds().toShortString());
Wale Ogunwalef6192862016-09-10 13:42:30 -07002759 pw.println(doublePrefix + "appTokens=" + mChildren);
Evan Roskyed6767f2018-10-26 17:21:06 -07002760 pw.println(doublePrefix + "mDisplayedBounds=" + mOverrideDisplayedBounds.toShortString());
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002761
2762 final String triplePrefix = doublePrefix + " ";
Jorim Jaggi153dc9d2018-02-23 13:28:15 +01002763 final String quadruplePrefix = triplePrefix + " ";
Wale Ogunwaleb429e682016-01-06 12:36:34 -08002764
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002765 int[] index = { 0 };
2766 forAllActivities((r) -> {
2767 pw.println(triplePrefix + "Activity #" + index[0]++ + " " + r);
2768 r.dump(pw, quadruplePrefix, dumpAll);
2769 });
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07002770 }
Robert Carrf59b8dd2017-10-02 18:58:36 -07002771
Louis Changcdec0802019-11-11 11:45:07 +08002772 /**
2773 * Fills in a {@link TaskInfo} with information from this task.
2774 * @param info the {@link TaskInfo} to fill in
2775 */
2776 void fillTaskInfo(TaskInfo info) {
2777 getNumRunningActivities(mReuseActivitiesReport);
2778 info.userId = mUserId;
2779 info.stackId = getStackId();
2780 info.taskId = mTaskId;
2781 info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
Wale Ogunwale21e06482019-11-18 05:14:15 -08002782 info.isRunning = getTopNonFinishingActivity() != null;
Louis Changcdec0802019-11-11 11:45:07 +08002783 info.baseIntent = new Intent(getBaseIntent());
2784 info.baseActivity = mReuseActivitiesReport.base != null
2785 ? mReuseActivitiesReport.base.intent.getComponent()
2786 : null;
2787 info.topActivity = mReuseActivitiesReport.top != null
2788 ? mReuseActivitiesReport.top.mActivityComponent
2789 : null;
2790 info.origActivity = origActivity;
2791 info.realActivity = realActivity;
2792 info.numActivities = mReuseActivitiesReport.numActivities;
2793 info.lastActiveTime = lastActiveTime;
2794 info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
2795 info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
2796 info.resizeMode = mResizeMode;
2797 info.configuration.setTo(getConfiguration());
2798 }
2799
2800 /**
2801 * Returns a {@link TaskInfo} with information from this task.
2802 */
2803 ActivityManager.RunningTaskInfo getTaskInfo() {
2804 ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
2805 fillTaskInfo(info);
2806 return info;
2807 }
2808
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09002809 boolean isTaskId(int taskId) {
2810 return mTaskId == taskId;
2811 }
2812
Louis Changcdec0802019-11-11 11:45:07 +08002813 void dump(PrintWriter pw, String prefix) {
2814 pw.print(prefix); pw.print("userId="); pw.print(mUserId);
2815 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
2816 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
2817 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
2818 pw.print(" mCallingPackage="); pw.println(mCallingPackage);
2819 if (affinity != null || rootAffinity != null) {
2820 pw.print(prefix); pw.print("affinity="); pw.print(affinity);
2821 if (affinity == null || !affinity.equals(rootAffinity)) {
2822 pw.print(" root="); pw.println(rootAffinity);
2823 } else {
2824 pw.println();
2825 }
2826 }
2827 if (voiceSession != null || voiceInteractor != null) {
2828 pw.print(prefix); pw.print("VOICE: session=0x");
2829 pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
2830 pw.print(" interactor=0x");
2831 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
2832 }
2833 if (intent != null) {
2834 StringBuilder sb = new StringBuilder(128);
2835 sb.append(prefix); sb.append("intent={");
2836 intent.toShortString(sb, false, true, false, false);
2837 sb.append('}');
2838 pw.println(sb.toString());
2839 }
2840 if (affinityIntent != null) {
2841 StringBuilder sb = new StringBuilder(128);
2842 sb.append(prefix); sb.append("affinityIntent={");
2843 affinityIntent.toShortString(sb, false, true, false, false);
2844 sb.append('}');
2845 pw.println(sb.toString());
2846 }
2847 if (origActivity != null) {
2848 pw.print(prefix); pw.print("origActivity=");
2849 pw.println(origActivity.flattenToShortString());
2850 }
2851 if (realActivity != null) {
2852 pw.print(prefix); pw.print("mActivityComponent=");
2853 pw.println(realActivity.flattenToShortString());
2854 }
Wale Ogunwale7a8889a2019-11-16 08:23:42 -08002855 if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) {
Louis Changcdec0802019-11-11 11:45:07 +08002856 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
2857 pw.print(" isPersistable="); pw.print(isPersistable);
Louis Changcdec0802019-11-11 11:45:07 +08002858 pw.print(" activityType="); pw.println(getActivityType());
2859 }
2860 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
2861 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
2862 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
2863 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
2864 pw.print(" mReuseTask="); pw.print(mReuseTask);
2865 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
2866 }
2867 if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
2868 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
2869 || mNextAffiliate != null) {
2870 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
2871 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
2872 pw.print(" (");
2873 if (mPrevAffiliate == null) {
2874 pw.print("null");
2875 } else {
2876 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
2877 }
2878 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
2879 pw.print(" (");
2880 if (mNextAffiliate == null) {
2881 pw.print("null");
2882 } else {
2883 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
2884 }
2885 pw.println(")");
2886 }
2887 pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
2888 if (!askedCompatMode || !inRecents || !isAvailable) {
2889 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
2890 pw.print(" inRecents="); pw.print(inRecents);
2891 pw.print(" isAvailable="); pw.println(isAvailable);
2892 }
2893 if (lastDescription != null) {
2894 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
2895 }
2896 if (mRootProcess != null) {
2897 pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
2898 }
2899 pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
2900 pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
2901 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
2902 pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
2903 pw.print(" isResizeable=" + isResizeable());
2904 pw.print(" lastActiveTime=" + lastActiveTime);
2905 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
2906 }
2907
2908 @Override
2909 public String toString() {
2910 StringBuilder sb = new StringBuilder(128);
2911 if (stringName != null) {
2912 sb.append(stringName);
2913 sb.append(" U=");
2914 sb.append(mUserId);
2915 sb.append(" StackId=");
2916 sb.append(getStackId());
2917 sb.append(" sz=");
2918 sb.append(getChildCount());
2919 sb.append('}');
2920 return sb.toString();
2921 }
2922 sb.append("Task{");
2923 sb.append(Integer.toHexString(System.identityHashCode(this)));
2924 sb.append(" #");
2925 sb.append(mTaskId);
2926 if (affinity != null) {
2927 sb.append(" A=");
2928 sb.append(affinity);
2929 } else if (intent != null) {
2930 sb.append(" I=");
2931 sb.append(intent.getComponent().flattenToShortString());
2932 } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
2933 sb.append(" aI=");
2934 sb.append(affinityIntent.getComponent().flattenToShortString());
2935 } else {
2936 sb.append(" ??");
2937 }
2938 stringName = sb.toString();
2939 return toString();
2940 }
2941
2942 @Override
Jeffrey Huangcb782852019-12-05 11:28:11 -08002943 public void dumpDebug(ProtoOutputStream proto, long fieldId,
Louis Changcdec0802019-11-11 11:45:07 +08002944 @WindowTraceLogLevel int logLevel) {
2945 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
2946 return;
2947 }
2948
2949 final long token = proto.start(fieldId);
Jeffrey Huangcb782852019-12-05 11:28:11 -08002950 dumpDebugInnerTaskOnly(proto, TASK, logLevel);
Louis Changcdec0802019-11-11 11:45:07 +08002951 proto.write(com.android.server.am.TaskRecordProto.ID, mTaskId);
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002952
2953 forAllActivities((r) -> {
Jeffrey Huangcb782852019-12-05 11:28:11 -08002954 r.dumpDebug(proto, ACTIVITIES);
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002955 });
Louis Changcdec0802019-11-11 11:45:07 +08002956 proto.write(STACK_ID, getStackId());
2957 if (mLastNonFullscreenBounds != null) {
Jeffrey Huangcb782852019-12-05 11:28:11 -08002958 mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS);
Louis Changcdec0802019-11-11 11:45:07 +08002959 }
2960 if (realActivity != null) {
2961 proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
2962 }
2963 if (origActivity != null) {
2964 proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
2965 }
2966 proto.write(ACTIVITY_TYPE, getActivityType());
2967 proto.write(RESIZE_MODE, mResizeMode);
2968 // TODO: Remove, no longer needed with windowingMode.
2969 proto.write(FULLSCREEN, matchParentBounds());
2970
2971 if (!matchParentBounds()) {
2972 final Rect bounds = getRequestedOverrideBounds();
Jeffrey Huangcb782852019-12-05 11:28:11 -08002973 bounds.dumpDebug(proto, com.android.server.am.TaskRecordProto.BOUNDS);
Louis Changcdec0802019-11-11 11:45:07 +08002974 }
2975 proto.write(MIN_WIDTH, mMinWidth);
2976 proto.write(MIN_HEIGHT, mMinHeight);
2977 proto.end(token);
2978 }
2979
2980 /** @see #getNumRunningActivities(TaskActivitiesReport) */
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002981 static class TaskActivitiesReport implements Consumer<ActivityRecord> {
Louis Changcdec0802019-11-11 11:45:07 +08002982 int numRunning;
2983 int numActivities;
2984 ActivityRecord top;
2985 ActivityRecord base;
2986
2987 void reset() {
2988 numRunning = numActivities = 0;
2989 top = base = null;
2990 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -08002991
2992 @Override
2993 public void accept(ActivityRecord r) {
2994 if (r.finishing) {
2995 return;
2996 }
2997
2998 base = r;
2999
3000 // Increment the total number of non-finishing activities
3001 numActivities++;
3002
3003 if (top == null || (top.isState(ActivityState.INITIALIZING))) {
3004 top = r;
3005 // Reset the number of running activities until we hit the first non-initializing
3006 // activity
3007 numRunning = 0;
3008 }
3009 if (r.attachedToProcess()) {
3010 // Increment the number of actually running activities
3011 numRunning++;
3012 }
3013 }
Louis Changcdec0802019-11-11 11:45:07 +08003014 }
3015
3016 /**
3017 * Saves this {@link Task} to XML using given serializer.
3018 */
Wale Ogunwalea38654f2019-11-17 20:37:15 -08003019 void saveToXml(XmlSerializer out) throws Exception {
Louis Changcdec0802019-11-11 11:45:07 +08003020 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
3021
3022 out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
3023 if (realActivity != null) {
3024 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
3025 }
3026 out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
3027 if (origActivity != null) {
3028 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
3029 }
3030 // Write affinity, and root affinity if it is different from affinity.
3031 // We use the special string "@" for a null root affinity, so we can identify
3032 // later whether we were given a root affinity or should just make it the
3033 // same as the affinity.
3034 if (affinity != null) {
3035 out.attribute(null, ATTR_AFFINITY, affinity);
3036 if (!affinity.equals(rootAffinity)) {
3037 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
3038 }
3039 } else if (rootAffinity != null) {
3040 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
3041 }
3042 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
3043 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
3044 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
3045 out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
3046 out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
3047 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
3048 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
3049 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
3050 if (lastDescription != null) {
3051 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
3052 }
3053 if (getTaskDescription() != null) {
3054 getTaskDescription().saveToXml(out);
3055 }
3056 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
3057 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
3058 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
3059 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
3060 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
3061 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
3062 out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
3063 out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
3064 String.valueOf(mSupportsPictureInPicture));
3065 if (mLastNonFullscreenBounds != null) {
3066 out.attribute(
3067 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
3068 }
3069 out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
3070 out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
3071 out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
3072
3073 if (affinityIntent != null) {
3074 out.startTag(null, TAG_AFFINITYINTENT);
3075 affinityIntent.saveToXml(out);
3076 out.endTag(null, TAG_AFFINITYINTENT);
3077 }
3078
3079 if (intent != null) {
3080 out.startTag(null, TAG_INTENT);
3081 intent.saveToXml(out);
3082 out.endTag(null, TAG_INTENT);
3083 }
3084
Wale Ogunwalea38654f2019-11-17 20:37:15 -08003085 sTmpException = null;
3086 final PooledFunction f = PooledLambda.obtainFunction(Task::saveActivityToXml,
3087 PooledLambda.__(ActivityRecord.class), getBottomMostActivity(), out);
3088 forAllActivities(f);
3089 f.recycle();
3090 if (sTmpException != null) {
3091 throw sTmpException;
3092 }
3093 }
3094
3095 private static boolean saveActivityToXml(
3096 ActivityRecord r, ActivityRecord first, XmlSerializer out) {
3097 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
3098 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
3099 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
3100 && r != first) {
3101 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
3102 return true;
3103 }
3104 try {
Louis Changcdec0802019-11-11 11:45:07 +08003105 out.startTag(null, TAG_ACTIVITY);
3106 r.saveToXml(out);
3107 out.endTag(null, TAG_ACTIVITY);
Wale Ogunwalea38654f2019-11-17 20:37:15 -08003108 return false;
3109 } catch (Exception e) {
3110 sTmpException = e;
3111 return true;
Louis Changcdec0802019-11-11 11:45:07 +08003112 }
3113 }
3114
3115 @VisibleForTesting
3116 static TaskFactory getTaskFactory() {
3117 if (sTaskFactory == null) {
3118 setTaskFactory(new TaskFactory());
3119 }
3120 return sTaskFactory;
3121 }
3122
3123 static void setTaskFactory(TaskFactory factory) {
3124 sTaskFactory = factory;
3125 }
3126
3127 static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3128 Intent intent, IVoiceInteractionSession voiceSession,
3129 IVoiceInteractor voiceInteractor, ActivityStack stack) {
3130 return getTaskFactory().create(
3131 service, taskId, info, intent, voiceSession, voiceInteractor, stack);
3132 }
3133
3134 static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3135 Intent intent, TaskDescription taskDescription, ActivityStack stack) {
3136 return getTaskFactory().create(service, taskId, info, intent, taskDescription, stack);
3137 }
3138
3139 static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
3140 throws IOException, XmlPullParserException {
3141 return getTaskFactory().restoreFromXml(in, stackSupervisor);
3142 }
3143
3144 /**
3145 * A factory class used to create {@link Task} or its subclass if any. This can be
3146 * specified when system boots by setting it with
3147 * {@link #setTaskFactory(TaskFactory)}.
3148 */
3149 static class TaskFactory {
3150
3151 Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3152 Intent intent, IVoiceInteractionSession voiceSession,
3153 IVoiceInteractor voiceInteractor, ActivityStack stack) {
3154 return new Task(service, taskId, info, intent, voiceSession, voiceInteractor,
3155 null /*taskDescription*/, stack);
3156 }
3157
3158 Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
3159 Intent intent, TaskDescription taskDescription, ActivityStack stack) {
3160 return new Task(service, taskId, info, intent, null /*voiceSession*/,
3161 null /*voiceInteractor*/, taskDescription, stack);
3162 }
3163
3164 /**
3165 * Should only be used when we're restoring {@link Task} from storage.
3166 */
3167 Task create(ActivityTaskManagerService service, int taskId, Intent intent,
3168 Intent affinityIntent, String affinity, String rootAffinity,
3169 ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
3170 boolean autoRemoveRecents, boolean askedCompatMode, int userId,
3171 int effectiveUid, String lastDescription,
3172 long lastTimeMoved, boolean neverRelinquishIdentity,
3173 TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
3174 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
3175 int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
3176 boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
3177 return new Task(service, taskId, intent, affinityIntent, affinity,
3178 rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
3179 askedCompatMode, userId, effectiveUid, lastDescription,
3180 lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
3181 prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
3182 resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
3183 minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
3184 null /*_voiceInteractor*/, stack);
3185 }
3186
3187 Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
3188 throws IOException, XmlPullParserException {
3189 Intent intent = null;
3190 Intent affinityIntent = null;
3191 ArrayList<ActivityRecord> activities = new ArrayList<>();
3192 ComponentName realActivity = null;
3193 boolean realActivitySuspended = false;
3194 ComponentName origActivity = null;
3195 String affinity = null;
3196 String rootAffinity = null;
3197 boolean hasRootAffinity = false;
3198 boolean rootHasReset = false;
3199 boolean autoRemoveRecents = false;
3200 boolean askedCompatMode = false;
3201 int taskType = 0;
3202 int userId = 0;
3203 boolean userSetupComplete = true;
3204 int effectiveUid = -1;
3205 String lastDescription = null;
3206 long lastTimeOnTop = 0;
3207 boolean neverRelinquishIdentity = true;
3208 int taskId = INVALID_TASK_ID;
3209 final int outerDepth = in.getDepth();
3210 TaskDescription taskDescription = new TaskDescription();
3211 int taskAffiliation = INVALID_TASK_ID;
3212 int taskAffiliationColor = 0;
3213 int prevTaskId = INVALID_TASK_ID;
3214 int nextTaskId = INVALID_TASK_ID;
3215 int callingUid = -1;
3216 String callingPackage = "";
3217 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
3218 boolean supportsPictureInPicture = false;
3219 Rect lastNonFullscreenBounds = null;
3220 int minWidth = INVALID_MIN_SIZE;
3221 int minHeight = INVALID_MIN_SIZE;
3222 int persistTaskVersion = 0;
3223
3224 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
3225 final String attrName = in.getAttributeName(attrNdx);
3226 final String attrValue = in.getAttributeValue(attrNdx);
3227 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: attribute name="
3228 + attrName + " value=" + attrValue);
3229 switch (attrName) {
3230 case ATTR_TASKID:
3231 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
3232 break;
3233 case ATTR_REALACTIVITY:
3234 realActivity = ComponentName.unflattenFromString(attrValue);
3235 break;
3236 case ATTR_REALACTIVITY_SUSPENDED:
3237 realActivitySuspended = Boolean.valueOf(attrValue);
3238 break;
3239 case ATTR_ORIGACTIVITY:
3240 origActivity = ComponentName.unflattenFromString(attrValue);
3241 break;
3242 case ATTR_AFFINITY:
3243 affinity = attrValue;
3244 break;
3245 case ATTR_ROOT_AFFINITY:
3246 rootAffinity = attrValue;
3247 hasRootAffinity = true;
3248 break;
3249 case ATTR_ROOTHASRESET:
3250 rootHasReset = Boolean.parseBoolean(attrValue);
3251 break;
3252 case ATTR_AUTOREMOVERECENTS:
3253 autoRemoveRecents = Boolean.parseBoolean(attrValue);
3254 break;
3255 case ATTR_ASKEDCOMPATMODE:
3256 askedCompatMode = Boolean.parseBoolean(attrValue);
3257 break;
3258 case ATTR_USERID:
3259 userId = Integer.parseInt(attrValue);
3260 break;
3261 case ATTR_USER_SETUP_COMPLETE:
3262 userSetupComplete = Boolean.parseBoolean(attrValue);
3263 break;
3264 case ATTR_EFFECTIVE_UID:
3265 effectiveUid = Integer.parseInt(attrValue);
3266 break;
3267 case ATTR_TASKTYPE:
3268 taskType = Integer.parseInt(attrValue);
3269 break;
3270 case ATTR_LASTDESCRIPTION:
3271 lastDescription = attrValue;
3272 break;
3273 case ATTR_LASTTIMEMOVED:
3274 lastTimeOnTop = Long.parseLong(attrValue);
3275 break;
3276 case ATTR_NEVERRELINQUISH:
3277 neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
3278 break;
3279 case ATTR_TASK_AFFILIATION:
3280 taskAffiliation = Integer.parseInt(attrValue);
3281 break;
3282 case ATTR_PREV_AFFILIATION:
3283 prevTaskId = Integer.parseInt(attrValue);
3284 break;
3285 case ATTR_NEXT_AFFILIATION:
3286 nextTaskId = Integer.parseInt(attrValue);
3287 break;
3288 case ATTR_TASK_AFFILIATION_COLOR:
3289 taskAffiliationColor = Integer.parseInt(attrValue);
3290 break;
3291 case ATTR_CALLING_UID:
3292 callingUid = Integer.parseInt(attrValue);
3293 break;
3294 case ATTR_CALLING_PACKAGE:
3295 callingPackage = attrValue;
3296 break;
3297 case ATTR_RESIZE_MODE:
3298 resizeMode = Integer.parseInt(attrValue);
3299 break;
3300 case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
3301 supportsPictureInPicture = Boolean.parseBoolean(attrValue);
3302 break;
3303 case ATTR_NON_FULLSCREEN_BOUNDS:
3304 lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
3305 break;
3306 case ATTR_MIN_WIDTH:
3307 minWidth = Integer.parseInt(attrValue);
3308 break;
3309 case ATTR_MIN_HEIGHT:
3310 minHeight = Integer.parseInt(attrValue);
3311 break;
3312 case ATTR_PERSIST_TASK_VERSION:
3313 persistTaskVersion = Integer.parseInt(attrValue);
3314 break;
3315 default:
3316 if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
3317 taskDescription.restoreFromXml(attrName, attrValue);
3318 } else {
3319 Slog.w(TAG, "Task: Unknown attribute=" + attrName);
3320 }
3321 }
3322 }
3323
3324 int event;
3325 while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
3326 && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
3327 if (event == XmlPullParser.START_TAG) {
3328 final String name = in.getName();
3329 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
3330 "Task: START_TAG name=" + name);
3331 if (TAG_AFFINITYINTENT.equals(name)) {
3332 affinityIntent = Intent.restoreFromXml(in);
3333 } else if (TAG_INTENT.equals(name)) {
3334 intent = Intent.restoreFromXml(in);
3335 } else if (TAG_ACTIVITY.equals(name)) {
3336 ActivityRecord activity =
3337 ActivityRecord.restoreFromXml(in, stackSupervisor);
3338 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: activity="
3339 + activity);
3340 if (activity != null) {
3341 activities.add(activity);
3342 }
3343 } else {
3344 handleUnknownTag(name, in);
3345 }
3346 }
3347 }
3348 if (!hasRootAffinity) {
3349 rootAffinity = affinity;
3350 } else if ("@".equals(rootAffinity)) {
3351 rootAffinity = null;
3352 }
3353 if (effectiveUid <= 0) {
3354 Intent checkIntent = intent != null ? intent : affinityIntent;
3355 effectiveUid = 0;
3356 if (checkIntent != null) {
3357 IPackageManager pm = AppGlobals.getPackageManager();
3358 try {
3359 ApplicationInfo ai = pm.getApplicationInfo(
3360 checkIntent.getComponent().getPackageName(),
3361 PackageManager.MATCH_UNINSTALLED_PACKAGES
3362 | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
3363 if (ai != null) {
3364 effectiveUid = ai.uid;
3365 }
3366 } catch (RemoteException e) {
3367 }
3368 }
3369 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
3370 + ": effectiveUid=" + effectiveUid);
3371 }
3372
3373 if (persistTaskVersion < 1) {
3374 // We need to convert the resize mode of home activities saved before version one if
3375 // they are marked as RESIZE_MODE_RESIZEABLE to
3376 // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
3377 // before version 1 and the system didn't resize home activities before then.
3378 if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
3379 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
3380 }
3381 } else {
3382 // This activity has previously marked itself explicitly as both resizeable and
3383 // supporting picture-in-picture. Since there is no longer a requirement for
3384 // picture-in-picture activities to be resizeable, we can mark this simply as
3385 // resizeable and supporting picture-in-picture separately.
3386 if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
3387 resizeMode = RESIZE_MODE_RESIZEABLE;
3388 supportsPictureInPicture = true;
3389 }
3390 }
3391
3392 final Task task = create(stackSupervisor.mService,
3393 taskId, intent, affinityIntent,
3394 affinity, rootAffinity, realActivity, origActivity, rootHasReset,
3395 autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
3396 lastTimeOnTop, neverRelinquishIdentity, taskDescription,
3397 taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
3398 callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
3399 userSetupComplete, minWidth, minHeight, null /*stack*/);
3400 task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
3401 task.setBounds(lastNonFullscreenBounds);
3402
3403 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
3404 task.addChild(activities.get(activityNdx));
3405 }
3406
3407 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
3408 return task;
3409 }
3410
3411 void handleUnknownTag(String name, XmlPullParser in)
3412 throws IOException, XmlPullParserException {
3413 Slog.e(TAG, "restoreTask: Unexpected name=" + name);
3414 XmlUtils.skipCurrentTag(in);
3415 }
Robert Carrf59b8dd2017-10-02 18:58:36 -07003416 }
Craig Mautnerb1fd65c02013-02-05 13:34:57 -08003417}