1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
20 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
21 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
22 import static android.app.ActivityOptions.ANIM_CUSTOM;
23 import static android.app.ActivityOptions.ANIM_NONE;
24 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
25 import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION;
26 import static android.app.ActivityOptions.ANIM_SCALE_UP;
27 import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
28 import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
29 import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP;
30 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
31 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
32 import static android.app.ActivityOptions.ANIM_UNDEFINED;
33 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
34 import static android.app.AppOpsManager.MODE_ALLOWED;
35 import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
36 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
37 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
38 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
39 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
40 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
41 import static android.app.CameraCompatTaskInfo.cameraCompatControlStateToString;
42 import static android.app.WaitResult.INVALID_DELAY;
43 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
44 import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
45 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
46 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
47 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
48 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
49 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
50 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
51 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
52 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
53 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
54 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
55 import static android.app.WindowConfiguration.activityTypeToString;
56 import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
57 import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
58 import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
59 import static android.content.Context.CONTEXT_RESTRICTED;
60 import static android.content.Intent.ACTION_MAIN;
61 import static android.content.Intent.CATEGORY_HOME;
62 import static android.content.Intent.CATEGORY_LAUNCHER;
63 import static android.content.Intent.CATEGORY_SECONDARY_HOME;
64 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
65 import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY;
66 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
67 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
68 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
69 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
70 import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
71 import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
72 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
73 import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
74 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
75 import static android.content.pm.ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
76 import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
77 import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY;
78 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
79 import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
80 import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON;
81 import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
82 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
83 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
84 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
85 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
86 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
87 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
88 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
89 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
90 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
91 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN;
92 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
93 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
94 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY;
95 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN;
96 import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
97 import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
98 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
99 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
100 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
101 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
102 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
103 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
104 import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_METADATA;
105 import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_OVERRIDE;
106 import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_METADATA;
107 import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
108 import static android.content.res.Configuration.ASSETS_SEQ_UNDEFINED;
109 import static android.content.res.Configuration.EMPTY;
110 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
111 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
112 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
113 import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
114 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
115 import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
116 import static android.os.Build.VERSION_CODES.HONEYCOMB;
117 import static android.os.Build.VERSION_CODES.O;
118 import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
119 import static android.os.Process.SYSTEM_UID;
120 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
121 import static android.view.Display.INVALID_DISPLAY;
122 import static android.view.Surface.ROTATION_270;
123 import static android.view.Surface.ROTATION_90;
124 import static android.view.WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15;
125 import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15;
126 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
127 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
128 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
129 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
130 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
131 import static android.view.WindowManager.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED;
132 import static android.view.WindowManager.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING;
133 import static android.view.WindowManager.TRANSIT_CLOSE;
134 import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
135 import static android.view.WindowManager.TRANSIT_OLD_UNSET;
136 import static android.view.WindowManager.TRANSIT_RELAUNCH;
137 import static android.view.WindowManager.hasWindowExtensionsEnabled;
138 import static android.window.TransitionInfo.FLAGS_IS_OCCLUDED_NO_ANIMATION;
139 import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
140 import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
141 
142 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
143 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
144 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
145 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
146 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
147 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTAINERS;
148 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
149 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
150 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
151 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
152 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
153 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
154 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN;
155 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
156 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
157 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
158 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
159 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
160 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
161 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
162 import static com.android.server.wm.ActivityRecord.State.DESTROYED;
163 import static com.android.server.wm.ActivityRecord.State.DESTROYING;
164 import static com.android.server.wm.ActivityRecord.State.FINISHING;
165 import static com.android.server.wm.ActivityRecord.State.INITIALIZING;
166 import static com.android.server.wm.ActivityRecord.State.PAUSED;
167 import static com.android.server.wm.ActivityRecord.State.PAUSING;
168 import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
169 import static com.android.server.wm.ActivityRecord.State.RESUMED;
170 import static com.android.server.wm.ActivityRecord.State.STARTED;
171 import static com.android.server.wm.ActivityRecord.State.STOPPED;
172 import static com.android.server.wm.ActivityRecord.State.STOPPING;
173 import static com.android.server.wm.ActivityRecordProto.ALL_DRAWN;
174 import static com.android.server.wm.ActivityRecordProto.APP_STOPPED;
175 import static com.android.server.wm.ActivityRecordProto.CLIENT_VISIBLE;
176 import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT;
177 import static com.android.server.wm.ActivityRecordProto.ENABLE_RECENTS_SCREENSHOT;
178 import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT;
179 import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK;
180 import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE;
181 import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
182 import static com.android.server.wm.ActivityRecordProto.IS_USER_FULLSCREEN_OVERRIDE_ENABLED;
183 import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
184 import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
185 import static com.android.server.wm.ActivityRecordProto.LAST_DROP_INPUT_MODE;
186 import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING;
187 import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO;
188 import static com.android.server.wm.ActivityRecordProto.NAME;
189 import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS;
190 import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS;
191 import static com.android.server.wm.ActivityRecordProto.OVERRIDE_ORIENTATION;
192 import static com.android.server.wm.ActivityRecordProto.PIP_AUTO_ENTER_ENABLED;
193 import static com.android.server.wm.ActivityRecordProto.PROC_ID;
194 import static com.android.server.wm.ActivityRecordProto.PROVIDES_MAX_BOUNDS;
195 import static com.android.server.wm.ActivityRecordProto.REPORTED_DRAWN;
196 import static com.android.server.wm.ActivityRecordProto.REPORTED_VISIBLE;
197 import static com.android.server.wm.ActivityRecordProto.SHOULD_ENABLE_USER_ASPECT_RATIO_SETTINGS;
198 import static com.android.server.wm.ActivityRecordProto.SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT;
199 import static com.android.server.wm.ActivityRecordProto.SHOULD_IGNORE_ORIENTATION_REQUEST_LOOP;
200 import static com.android.server.wm.ActivityRecordProto.SHOULD_OVERRIDE_FORCE_RESIZE_APP;
201 import static com.android.server.wm.ActivityRecordProto.SHOULD_OVERRIDE_MIN_ASPECT_RATIO;
202 import static com.android.server.wm.ActivityRecordProto.SHOULD_REFRESH_ACTIVITY_FOR_CAMERA_COMPAT;
203 import static com.android.server.wm.ActivityRecordProto.SHOULD_REFRESH_ACTIVITY_VIA_PAUSE_FOR_CAMERA_COMPAT;
204 import static com.android.server.wm.ActivityRecordProto.SHOULD_SEND_COMPAT_FAKE_FOCUS;
205 import static com.android.server.wm.ActivityRecordProto.STARTING_DISPLAYED;
206 import static com.android.server.wm.ActivityRecordProto.STARTING_MOVED;
207 import static com.android.server.wm.ActivityRecordProto.STARTING_WINDOW;
208 import static com.android.server.wm.ActivityRecordProto.STATE;
209 import static com.android.server.wm.ActivityRecordProto.THUMBNAIL;
210 import static com.android.server.wm.ActivityRecordProto.TRANSLUCENT;
211 import static com.android.server.wm.ActivityRecordProto.VISIBLE;
212 import static com.android.server.wm.ActivityRecordProto.VISIBLE_REQUESTED;
213 import static com.android.server.wm.ActivityRecordProto.VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW;
214 import static com.android.server.wm.ActivityRecordProto.WINDOW_TOKEN;
215 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
216 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
217 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
218 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
219 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
220 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
221 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
222 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
223 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_APP;
224 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
225 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONTAINERS;
226 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
227 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
228 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
229 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE;
230 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
231 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
232 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION;
233 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING;
234 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
235 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
236 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
237 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
238 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
239 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
240 import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutMillisLocked;
241 import static com.android.server.wm.IdentifierProto.HASH_CODE;
242 import static com.android.server.wm.IdentifierProto.TITLE;
243 import static com.android.server.wm.IdentifierProto.USER_ID;
244 import static com.android.server.wm.LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
245 import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
246 import static com.android.server.wm.StartingData.AFTER_TRANSACTION_COPY_TO_CLIENT;
247 import static com.android.server.wm.StartingData.AFTER_TRANSACTION_REMOVE_DIRECTLY;
248 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
249 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK;
250 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
251 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
252 import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
253 import static com.android.server.wm.TaskPersister.DEBUG;
254 import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
255 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
256 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
257 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
258 import static com.android.server.wm.WindowContainerChildProto.ACTIVITY;
259 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
260 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
261 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
262 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
263 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
264 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
265 import static com.android.server.wm.WindowManagerService.sEnableShellTransitions;
266 import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
267 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
268 
269 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
270 import static org.xmlpull.v1.XmlPullParser.END_TAG;
271 import static org.xmlpull.v1.XmlPullParser.START_TAG;
272 
273 import android.annotation.IntDef;
274 import android.annotation.NonNull;
275 import android.annotation.Nullable;
276 import android.annotation.Size;
277 import android.app.Activity;
278 import android.app.ActivityManager.TaskDescription;
279 import android.app.ActivityOptions;
280 import android.app.CameraCompatTaskInfo.CameraCompatControlState;
281 import android.app.ICompatCameraControlCallback;
282 import android.app.IScreenCaptureObserver;
283 import android.app.PendingIntent;
284 import android.app.PictureInPictureParams;
285 import android.app.ResultInfo;
286 import android.app.WaitResult;
287 import android.app.WindowConfiguration;
288 import android.app.admin.DevicePolicyManager;
289 import android.app.assist.ActivityId;
290 import android.app.compat.CompatChanges;
291 import android.app.servertransaction.ActivityConfigurationChangeItem;
292 import android.app.servertransaction.ActivityLifecycleItem;
293 import android.app.servertransaction.ActivityRelaunchItem;
294 import android.app.servertransaction.ActivityResultItem;
295 import android.app.servertransaction.ClientTransactionItem;
296 import android.app.servertransaction.DestroyActivityItem;
297 import android.app.servertransaction.MoveToDisplayItem;
298 import android.app.servertransaction.NewIntentItem;
299 import android.app.servertransaction.PauseActivityItem;
300 import android.app.servertransaction.ResumeActivityItem;
301 import android.app.servertransaction.StartActivityItem;
302 import android.app.servertransaction.StopActivityItem;
303 import android.app.servertransaction.TopResumedActivityChangeItem;
304 import android.app.servertransaction.TransferSplashScreenViewStateItem;
305 import android.app.usage.UsageEvents.Event;
306 import android.content.ComponentName;
307 import android.content.Context;
308 import android.content.Intent;
309 import android.content.LocusId;
310 import android.content.pm.ActivityInfo;
311 import android.content.pm.ApplicationInfo;
312 import android.content.pm.ConstrainDisplayApisConfig;
313 import android.content.pm.PackageManager;
314 import android.content.pm.PackageManagerInternal;
315 import android.content.pm.UserProperties;
316 import android.content.res.Configuration;
317 import android.content.res.Resources;
318 import android.graphics.Bitmap;
319 import android.graphics.Insets;
320 import android.graphics.PixelFormat;
321 import android.graphics.Point;
322 import android.graphics.Rect;
323 import android.graphics.drawable.Drawable;
324 import android.gui.DropInputMode;
325 import android.hardware.HardwareBuffer;
326 import android.net.Uri;
327 import android.os.Binder;
328 import android.os.Build;
329 import android.os.Bundle;
330 import android.os.Debug;
331 import android.os.IBinder;
332 import android.os.IRemoteCallback;
333 import android.os.PersistableBundle;
334 import android.os.Process;
335 import android.os.RemoteCallbackList;
336 import android.os.RemoteException;
337 import android.os.SystemClock;
338 import android.os.Trace;
339 import android.os.UserHandle;
340 import android.service.contentcapture.ActivityEvent;
341 import android.service.dreams.DreamActivity;
342 import android.service.voice.IVoiceInteractionSession;
343 import android.util.ArraySet;
344 import android.util.EventLog;
345 import android.util.Log;
346 import android.util.MergedConfiguration;
347 import android.util.Slog;
348 import android.util.TimeUtils;
349 import android.util.proto.ProtoOutputStream;
350 import android.view.AppTransitionAnimationSpec;
351 import android.view.DisplayInfo;
352 import android.view.IAppTransitionAnimationSpecsFuture;
353 import android.view.InputApplicationHandle;
354 import android.view.RemoteAnimationAdapter;
355 import android.view.RemoteAnimationDefinition;
356 import android.view.RemoteAnimationTarget;
357 import android.view.Surface.Rotation;
358 import android.view.SurfaceControl;
359 import android.view.SurfaceControl.Transaction;
360 import android.view.WindowInsets;
361 import android.view.WindowInsets.Type;
362 import android.view.WindowManager;
363 import android.view.WindowManager.LayoutParams;
364 import android.view.WindowManager.TransitionOldType;
365 import android.view.animation.Animation;
366 import android.window.ActivityWindowInfo;
367 import android.window.ITaskFragmentOrganizer;
368 import android.window.RemoteTransition;
369 import android.window.SizeConfigurationBuckets;
370 import android.window.SplashScreen;
371 import android.window.SplashScreenView;
372 import android.window.SplashScreenView.SplashScreenViewParcelable;
373 import android.window.TaskSnapshot;
374 import android.window.TransitionInfo.AnimationOptions;
375 import android.window.WindowContainerToken;
376 import android.window.WindowOnBackInvokedDispatcher;
377 
378 import com.android.internal.R;
379 import com.android.internal.annotations.GuardedBy;
380 import com.android.internal.annotations.VisibleForTesting;
381 import com.android.internal.app.ResolverActivity;
382 import com.android.internal.content.ReferrerIntent;
383 import com.android.internal.os.TimeoutRecord;
384 import com.android.internal.os.TransferPipe;
385 import com.android.internal.policy.AttributeCache;
386 import com.android.internal.protolog.common.ProtoLog;
387 import com.android.internal.util.XmlUtils;
388 import com.android.modules.utils.TypedXmlPullParser;
389 import com.android.modules.utils.TypedXmlSerializer;
390 import com.android.server.LocalServices;
391 import com.android.server.am.AppTimeTracker;
392 import com.android.server.am.PendingIntentRecord;
393 import com.android.server.contentcapture.ContentCaptureManagerInternal;
394 import com.android.server.display.color.ColorDisplayService;
395 import com.android.server.pm.UserManagerInternal;
396 import com.android.server.uri.GrantUri;
397 import com.android.server.uri.NeededUriGrants;
398 import com.android.server.uri.UriPermissionOwner;
399 import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
400 import com.android.server.wm.SurfaceAnimator.AnimationType;
401 import com.android.server.wm.WindowManagerService.H;
402 import com.android.server.wm.utils.InsetUtils;
403 import com.android.window.flags.Flags;
404 
405 import dalvik.annotation.optimization.NeverCompile;
406 
407 import com.google.android.collect.Sets;
408 
409 import org.xmlpull.v1.XmlPullParserException;
410 
411 import java.io.File;
412 import java.io.FileDescriptor;
413 import java.io.IOException;
414 import java.io.PrintWriter;
415 import java.lang.ref.WeakReference;
416 import java.util.ArrayList;
417 import java.util.Arrays;
418 import java.util.HashSet;
419 import java.util.List;
420 import java.util.Objects;
421 import java.util.function.Consumer;
422 import java.util.function.Predicate;
423 
424 /**
425  * An entry in the history task, representing an activity.
426  */
427 final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {
428     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_ATM;
429     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
430     private static final String TAG_APP = TAG + POSTFIX_APP;
431     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
432     private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
433     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
434     private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
435     private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
436     private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
437     private static final String TAG_STATES = TAG + POSTFIX_STATES;
438     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
439     private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
440     private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
441     private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
442 
443     private static final String ATTR_ID = "id";
444     private static final String TAG_INTENT = "intent";
445     private static final String ATTR_USERID = "user_id";
446     private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle";
447     private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid";
448     private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
449     private static final String ATTR_LAUNCHEDFROMFEATURE = "launched_from_feature";
450     private static final String ATTR_RESOLVEDTYPE = "resolved_type";
451     private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
452     private static final String TAG_INITIAL_CALLER_INFO = "initial_caller_info";
453     static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
454 
455     // How many activities have to be scheduled to stop to force a stop pass.
456     private static final int MAX_STOPPING_TO_FORCE = 3;
457 
458     static final int STARTING_WINDOW_TYPE_NONE = 0;
459     static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
460     static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
461 
462     static final int INVALID_PID = -1;
463 
464     // How long we wait until giving up on the last activity to pause.  This
465     // is short because it directly impacts the responsiveness of starting the
466     // next activity.
467     private static final int PAUSE_TIMEOUT = 500;
468 
469     // Ticks during which we check progress while waiting for an app to launch.
470     private static final int LAUNCH_TICK = 500;
471 
472     // How long we wait for the activity to tell us it has stopped before
473     // giving up.  This is a good amount of time because we really need this
474     // from the application in order to get its saved state. Once the stop
475     // is complete we may start destroying client resources triggering
476     // crashes if the UI thread was hung. We put this timeout one second behind
477     // the ANR timeout so these situations will generate ANR instead of
478     // Surface lost or other errors.
479     private static final int STOP_TIMEOUT = 11 * 1000;
480 
481     // How long we wait until giving up on an activity telling us it has
482     // finished destroying itself.
483     private static final int DESTROY_TIMEOUT = 10 * 1000;
484 
485     // Rounding tolerance to be used in aspect ratio computations
486     private static final float ASPECT_RATIO_ROUNDING_TOLERANCE = 0.005f;
487 
488     final ActivityTaskManagerService mAtmService;
489     final ActivityCallerState mCallerState;
490     @NonNull
491     final ActivityInfo info; // activity info provided by developer in AndroidManifest
492     // Which user is this running for?
493     final int mUserId;
494     // The package implementing intent's component
495     // TODO: rename to mPackageName
496     final String packageName;
497     // the intent component, or target of an alias.
498     final ComponentName mActivityComponent;
499     // Input application handle used by the input dispatcher.
500     private InputApplicationHandle mInputApplicationHandle;
501 
502     final int launchedFromPid; // always the pid who started the activity.
503     final int launchedFromUid; // always the uid who started the activity.
504     final String launchedFromPackage; // always the package who started the activity.
505     @Nullable
506     final String launchedFromFeatureId; // always the feature in launchedFromPackage
507     private final int mLaunchSourceType; // original launch source type
508     final Intent intent;    // the original intent that generated us
509     final String shortComponentName; // the short component name of the intent
510     final String resolvedType; // as per original caller;
511     final String processName; // process where this component wants to run
512     final String taskAffinity; // as per ActivityInfo.taskAffinity
513     final boolean stateNotNeeded; // As per ActivityInfo.flags
514     @VisibleForTesting
515     int mHandoverLaunchDisplayId = INVALID_DISPLAY; // Handover launch display id to next activity.
516     @VisibleForTesting
517     TaskDisplayArea mHandoverTaskDisplayArea; // Handover launch task display area.
518     private final boolean componentSpecified;  // did caller specify an explicit component?
519     final boolean rootVoiceInteraction;  // was this the root activity of a voice interaction?
520 
521     private final int theme;        // resource identifier of activity's theme.
522     private Task task;              // the task this is in.
523     private long createTime = System.currentTimeMillis();
524     long lastVisibleTime;         // last time this activity became visible
525     long pauseTime;               // last time we started pausing the activity
526     long launchTickTime;          // base time for launch tick messages
527     long topResumedStateLossTime; // last time we reported top resumed state loss to an activity
528     // Last configuration reported to the activity in the client process.
529     private final MergedConfiguration mLastReportedConfiguration;
530     private int mLastReportedDisplayId;
531     boolean mLastReportedMultiWindowMode;
532     boolean mLastReportedPictureInPictureMode;
533     private final ActivityWindowInfo mLastReportedActivityWindowInfo = new ActivityWindowInfo();
534     ActivityRecord resultTo; // who started this entry, so will get our reply
535     final String resultWho; // additional identifier for use by resultTo.
536     final int requestCode;  // code given by requester (resultTo)
537     ArrayList<ResultInfo> results; // pending ActivityResult objs we have received
538     HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
539     ArrayList<ReferrerIntent> newIntents; // any pending new intents for single-top mode
540     Intent mLastNewIntent;  // the last new intent we delivered to client
541     /** The most recently given options. */
542     private ActivityOptions mPendingOptions;
543     /** Non-null if {@link #mPendingOptions} specifies the remote animation. */
544     RemoteAnimationAdapter mPendingRemoteAnimation;
545     private RemoteTransition mPendingRemoteTransition;
546     ActivityOptions returningOptions; // options that are coming back via convertToTranslucent
547     AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity
548     @GuardedBy("this")
549     ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections.
550     /** @see android.content.Context#BIND_ADJUST_WITH_ACTIVITY */
551     volatile boolean mVisibleForServiceConnection;
552     UriPermissionOwner uriPermissions; // current special URI access perms.
553     WindowProcessController app;      // if non-null, hosting application
554     private State mState;    // current state we are in
555     private Bundle mIcicle;         // last saved activity state
556     private PersistableBundle mPersistentState; // last persistently saved activity state
557     private boolean mHaveState = true; // Indicates whether the last saved state of activity is
558                                        // preserved. This starts out 'true', since the initial state
559                                        // of an activity is that we have everything, and we should
560                                        // never consider it lacking in state to be removed if it
561                                        // dies. After an activity is launched it follows the value
562                                        // of #mIcicle.
563     boolean launchFailed;   // set if a launched failed, to abort on 2nd try
564     boolean delayedResume;  // not yet resumed because of stopped app switches?
565     boolean finishing;      // activity in pending finish list?
566     private boolean keysPaused;     // has key dispatching been paused for it?
567     int launchMode;         // the launch mode activity attribute.
568     int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override
569     private boolean mVisible;        // Should this token's windows be visible?
570     boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
571                                      // might hide this activity?
572     // True if the visible state of this token was forced to true due to a transferred starting
573     // window.
574     private boolean mVisibleSetFromTransferredStartingWindow;
575     // TODO: figure out how to consolidate with the same variable in ActivityRecord.
576     private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client
577                                         // process that it is hidden.
578     private boolean mLastDeferHidingClient; // If true we will defer setting mClientVisible to false
579                                            // and reporting to the client that it is hidden.
580     boolean nowVisible;     // is this activity's window visible?
581     boolean mClientVisibilityDeferred;// was the visibility change message to client deferred?
582     boolean idle;           // has the activity gone idle?
583     boolean hasBeenLaunched;// has this activity ever been launched?
584     boolean immersive;      // immersive mode (don't interrupt if possible)
585     boolean supportsEnterPipOnTaskSwitch;  // This flag is set by the system to indicate that the
586         // activity can enter picture in picture while pausing (only when switching to another task)
587     // The PiP params used when deferring the entering of picture-in-picture.
588     PictureInPictureParams pictureInPictureArgs = new PictureInPictureParams.Builder().build();
589     boolean shouldDockBigOverlays;
590     int launchCount;        // count of launches since last state
591     long lastLaunchTime;    // time of last launch of this activity
592     ComponentName requestedVrComponent; // the requested component for handling VR mode.
593 
594     /** Whether this activity is reachable from hierarchy. */
595     volatile boolean inHistory;
596     final ActivityTaskSupervisor mTaskSupervisor;
597     final RootWindowContainer mRootWindowContainer;
598     // The token of the TaskFragment that this activity was requested to be launched into.
599     IBinder mRequestedLaunchingTaskFragmentToken;
600 
601     // Tracking splash screen status from previous activity
602     boolean mSplashScreenStyleSolidColor = false;
603 
604     boolean mPauseSchedulePendingForPip = false;
605 
606     // Gets set to indicate that the activity is currently being auto-pipped.
607     boolean mAutoEnteringPip = false;
608 
609     static final int LAUNCH_SOURCE_TYPE_SYSTEM = 1;
610     static final int LAUNCH_SOURCE_TYPE_HOME = 2;
611     static final int LAUNCH_SOURCE_TYPE_SYSTEMUI = 3;
612     static final int LAUNCH_SOURCE_TYPE_APPLICATION = 4;
613 
614     enum State {
615         INITIALIZING,
616         STARTED,
617         RESUMED,
618         PAUSING,
619         PAUSED,
620         STOPPING,
621         STOPPED,
622         FINISHING,
623         DESTROYING,
624         DESTROYED,
625         RESTARTING_PROCESS
626     }
627 
628     /**
629      * The type of launch source.
630      */
631     @IntDef(prefix = {"LAUNCH_SOURCE_TYPE_"}, value = {
632             LAUNCH_SOURCE_TYPE_SYSTEM,
633             LAUNCH_SOURCE_TYPE_HOME,
634             LAUNCH_SOURCE_TYPE_SYSTEMUI,
635             LAUNCH_SOURCE_TYPE_APPLICATION
636     })
637     @interface LaunchSourceType {}
638 
639     private boolean mTaskOverlay = false; // Task is always on-top of other activities in the task.
640 
641     // Marking the reason why this activity is being relaunched. Mainly used to track that this
642     // activity is being relaunched to fulfill a resize request due to compatibility issues, e.g. in
643     // pre-NYC apps that don't have a sense of being resized.
644     int mRelaunchReason = RELAUNCH_REASON_NONE;
645 
646     private boolean mForceSendResultForMediaProjection = false;
647 
648     TaskDescription taskDescription; // the recents information for this activity
649 
650     // The locusId associated with this activity, if set.
651     private LocusId mLocusId;
652 
653     // Whether the activity was launched from a bubble.
654     private boolean mLaunchedFromBubble;
655 
656     private SizeConfigurationBuckets mSizeConfigurations;
657 
658     /**
659      * The precomputed display insets for resolving configuration. It will be non-null if
660      * {@link #shouldCreateCompatDisplayInsets} returns {@code true}.
661      */
662     private CompatDisplayInsets mCompatDisplayInsets;
663 
664     @VisibleForTesting
665     final TaskFragment.ConfigOverrideHint mResolveConfigHint;
666 
667     private final boolean mOptOutEdgeToEdge;
668 
669     private static ConstrainDisplayApisConfig sConstrainDisplayApisConfig;
670 
671     boolean pendingVoiceInteractionStart;   // Waiting for activity-invoked voice session
672     IVoiceInteractionSession voiceSession;  // Voice interaction session for this activity
673 
674     boolean mVoiceInteraction;
675 
676     int mPendingRelaunchCount;
677     long mRelaunchStartTime;
678 
679     // True if we are current in the process of removing this app token from the display
680     private boolean mRemovingFromDisplay = false;
681 
682     private RemoteAnimationDefinition mRemoteAnimationDefinition;
683 
684     AnimatingActivityRegistry mAnimatingActivityRegistry;
685 
686     // Set to the previous Task parent of the ActivityRecord when it is reparented to a new Task
687     // due to picture-in-picture. This gets cleared whenever this activity or the Task
688     // it references to gets removed. This should also be cleared when we move out of pip.
689     private Task mLastParentBeforePip;
690 
691     // The token of the previous TaskFragment parent of this embedded ActivityRecord when it is
692     // reparented to a new Task due to picture-in-picture.
693     // Note that the TaskFragment may be finished and no longer attached in WM hierarchy.
694     @Nullable
695     private IBinder mLastEmbeddedParentTfTokenBeforePip;
696 
697     // Only set if this instance is a launch-into-pip Activity, points to the
698     // host Activity the launch-into-pip Activity is originated from.
699     private ActivityRecord mLaunchIntoPipHostActivity;
700 
701     /**
702      * Sets to the previous {@link ITaskFragmentOrganizer} of the {@link TaskFragment} that the
703      * activity is embedded in before it is reparented to a new Task due to picture-in-picture.
704      */
705     @Nullable
706     ITaskFragmentOrganizer mLastTaskFragmentOrganizerBeforePip;
707 
708     boolean firstWindowDrawn;
709     /** Whether the visible window(s) of this activity is drawn. */
710     private boolean mReportedDrawn;
711     private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
712             new WindowState.UpdateReportedVisibilityResults();
713 
714     // TODO(b/317000737): Replace it with visibility states lookup.
715     int mTransitionChangeFlags;
716 
717     /** Whether we need to setup the animation to animate only within the letterbox. */
718     private boolean mNeedsLetterboxedAnimation;
719 
720     /**
721      * @see #currentLaunchCanTurnScreenOn()
722      */
723     private boolean mCurrentLaunchCanTurnScreenOn = true;
724 
725     /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */
726     boolean mLastSurfaceShowing;
727 
728     /**
729      * The activity is opaque and fills the entire space of this task.
730      * @see #occludesParent()
731      */
732     private boolean mOccludesParent;
733 
734     /**
735      * Unlike {@link #mOccludesParent} which can be changed at runtime. This is a static attribute
736      * from the style of activity. Because we don't want {@link WindowContainer#getOrientation()}
737      * to be affected by the temporal state of {@link ActivityClientController#convertToTranslucent}
738      * when running ANIM_SCENE_TRANSITION.
739      * @see WindowContainer#providesOrientation()
740      */
741     final boolean mStyleFillsParent;
742 
743     // The input dispatching timeout for this application token in milliseconds.
744     long mInputDispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
745 
746     private boolean mShowWhenLocked;
747     private boolean mInheritShownWhenLocked;
748     private boolean mTurnScreenOn;
749 
750     /**
751      * Whether the user is always-visible (e.g. a communal profile). Activities for such users
752      * are treated as visible regardless of what user is in the foreground, and can appear
753      * over the lockscreen.
754      */
755     private final boolean mIsUserAlwaysVisible;
756 
757     /** Allow activity launches which would otherwise be blocked by
758      * {@link BackgroundActivityStartController#checkActivityAllowedToStart}
759      */
760     boolean mAllowCrossUidActivitySwitchFromBelow;
761 
762     /** Have we been asked to have this token keep the screen frozen? */
763     private boolean mFreezingScreen;
764 
765     // These are used for determining when all windows associated with
766     // an activity have been drawn, so they can be made visible together
767     // at the same time.
768     // initialize so that it doesn't match mTransactionSequence which is an int.
769     private long mLastTransactionSequence = Long.MIN_VALUE;
770     private int mNumInterestingWindows;
771     private int mNumDrawnWindows;
772     boolean allDrawn;
773     private boolean mLastAllDrawn;
774 
775     /**
776      * Solely for reporting to ActivityMetricsLogger. Just tracks whether, the last time this
777      * Activity was part of a syncset, all windows were ready by the time the sync was ready (vs.
778      * only the top-occluding ones). The assumption here is if some were not ready, they were
779      * covered with starting-window/splash-screen.
780      */
781     boolean mLastAllReadyAtSync = false;
782 
783     private boolean mLastContainsShowWhenLockedWindow;
784     private boolean mLastContainsDismissKeyguardWindow;
785     private boolean mLastContainsTurnScreenOnWindow;
786 
787     /** Whether the IME is showing when transitioning away from this activity. */
788     boolean mLastImeShown;
789 
790     /**
791      * When set to true, the IME insets will be frozen until the next app becomes IME input target.
792      * @see InsetsPolicy#adjustVisibilityForIme
793      * @see ImeInsetsSourceProvider#updateClientVisibility
794      */
795     boolean mImeInsetsFrozenUntilStartInput;
796 
797     /**
798      * A flag to determine if this AR is in the process of closing or entering PIP. This is needed
799      * to help AR know that the app is in the process of closing but hasn't yet started closing on
800      * the WM side.
801      */
802     private boolean mWillCloseOrEnterPip;
803 
804     final LetterboxUiController mLetterboxUiController;
805 
806     /**
807      * The policy for transparent activities
808      */
809     final TransparentPolicy mTransparentPolicy;
810 
811     /**
812      * The scale to fit at least one side of the activity to its parent. If the activity uses
813      * 1920x1080, and the actually size on the screen is 960x540, then the scale is 0.5.
814      */
815     private float mSizeCompatScale = 1f;
816 
817     /**
818      * The bounds in global coordinates for activity in size compatibility mode.
819      * @see ActivityRecord#hasSizeCompatBounds()
820      */
821     private Rect mSizeCompatBounds;
822 
823     // Whether this activity is in size compatibility mode because its bounds don't fit in parent
824     // naturally.
825     private boolean mInSizeCompatModeForBounds = false;
826 
827     // Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio().
828     private boolean mIsAspectRatioApplied = false;
829 
830     // Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
831     // for fixed orientation. If not null, they are used as parent container in
832     // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets. If
833     // letterboxed due to fixed orientation then aspect ratio restrictions are also respected.
834     // This happens when an activity has fixed orientation which doesn't match orientation of the
835     // parent because a display is ignoring orientation request or fixed to user rotation.
836     // See WindowManagerService#getIgnoreOrientationRequest and
837     // WindowManagerService#getFixedToUserRotation for more context.
838     @Nullable
839     private Rect mLetterboxBoundsForFixedOrientationAndAspectRatio;
840 
841     // Bounds populated in resolveAspectRatioRestriction when this activity is letterboxed for
842     // aspect ratio. If not null, they are used as parent container in
843     // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets.
844     @Nullable
845     private Rect mLetterboxBoundsForAspectRatio;
846 
847     // Whether the activity is eligible to be letterboxed for fixed orientation with respect to its
848     // requested orientation, even when it's letterbox for another reason (e.g., size compat mode)
849     // and therefore #isLetterboxedForFixedOrientationAndAspectRatio returns false.
850     private boolean mIsEligibleForFixedOrientationLetterbox;
851 
852     // State of the Camera app compat control which is used to correct stretched viewfinder
853     // in apps that don't handle all possible configurations and changes between them correctly.
854     @CameraCompatControlState
855     private int mCameraCompatControlState = CAMERA_COMPAT_CONTROL_HIDDEN;
856 
857     // The callback that allows to ask the calling View to apply the treatment for stretched
858     // issues affecting camera viewfinders when the user clicks on the camera compat control.
859     @Nullable
860     private ICompatCameraControlCallback mCompatCameraControlCallback;
861 
862     private final boolean mCameraCompatControlEnabled;
863     private boolean mCameraCompatControlClickedByUser;
864 
865     // activity is not displayed?
866     // TODO: rename to mNoDisplay
867     @VisibleForTesting
868     boolean noDisplay;
869     final boolean mShowForAllUsers;
870     // TODO: Make this final
871     int mTargetSdk;
872 
873     // Last visibility state we reported to the app token.
874     boolean reportedVisible;
875 
876     boolean mEnableRecentsScreenshot = true;
877 
878     // Information about an application starting window if displayed.
879     // Note: these are de-referenced before the starting window animates away.
880     StartingData mStartingData;
881     WindowState mStartingWindow;
882     StartingSurfaceController.StartingSurface mStartingSurface;
883     boolean startingMoved;
884 
885     /** The last set {@link DropInputMode} for this activity surface. */
886     @DropInputMode
887     private int mLastDropInputMode = DropInputMode.NONE;
888     /** Whether the input to this activity will be dropped during the current playing animation. */
889     private boolean mIsInputDroppedForAnimation;
890 
891     /**
892      * Whether the application has desk mode resources. Calculated and cached when
893      * {@link #hasDeskResources()} is called.
894      */
895     @Nullable
896     private Boolean mHasDeskResources;
897 
898     boolean mHandleExitSplashScreen;
899     @TransferSplashScreenState
900     int mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
901 
902     /** Idle, can be triggered to do transfer if needed. */
903     static final int TRANSFER_SPLASH_SCREEN_IDLE = 0;
904 
905     /** Requesting a copy from shell. */
906     static final int TRANSFER_SPLASH_SCREEN_COPYING = 1;
907 
908     /** Attach the splash screen view to activity. */
909     static final int TRANSFER_SPLASH_SCREEN_ATTACH_TO_CLIENT = 2;
910 
911     /** Client has taken over splash screen view. */
912     static final int TRANSFER_SPLASH_SCREEN_FINISH = 3;
913 
914     @IntDef(prefix = {"TRANSFER_SPLASH_SCREEN_"}, value = {
915             TRANSFER_SPLASH_SCREEN_IDLE,
916             TRANSFER_SPLASH_SCREEN_COPYING,
917             TRANSFER_SPLASH_SCREEN_ATTACH_TO_CLIENT,
918             TRANSFER_SPLASH_SCREEN_FINISH,
919     })
920     @interface TransferSplashScreenState {
921     }
922 
923     // How long we wait until giving up transfer splash screen.
924     private static final int TRANSFER_SPLASH_SCREEN_TIMEOUT = 2000;
925 
926     /**
927      * The icon is shown when the launching activity sets the splashScreenStyle to
928      * SPLASH_SCREEN_STYLE_ICON. If the launching activity does not specify any style,
929      * follow the system behavior.
930      *
931      * @see android.R.attr#windowSplashScreenBehavior
932      */
933     private static final int SPLASH_SCREEN_BEHAVIOR_DEFAULT = 0;
934     /**
935      * The icon is shown unless the launching app specified SPLASH_SCREEN_STYLE_SOLID_COLOR.
936      *
937      * @see android.R.attr#windowSplashScreenBehavior
938      */
939     private static final int SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED = 1;
940 
941     @IntDef(prefix = {"SPLASH_SCREEN_BEHAVIOR_"}, value = {
942             SPLASH_SCREEN_BEHAVIOR_DEFAULT,
943             SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED
944     })
945     @interface SplashScreenBehavior { }
946 
947     // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
948     boolean mIsExiting;
949     // Force an app transition to be ran in the case the visibility of the app did not change.
950     // We use this for the case of moving a Root Task to the back with multiple activities, and the
951     // top activity enters PIP; the bottom activity's visibility stays the same, but we need to
952     // run the transition.
953     boolean mRequestForceTransition;
954 
955     boolean mEnteringAnimation;
956     boolean mOverrideTaskTransition;
957     boolean mDismissKeyguardIfInsecure;
958     boolean mShareIdentity;
959 
960     /** True if the activity has reported stopped; False if the activity becomes visible. */
961     boolean mAppStopped;
962     // A hint to override the window specified rotation animation, or -1 to use the window specified
963     // value. We use this so that we can select the right animation in the cases of starting
964     // windows, where the app hasn't had time to set a value on the window.
965     int mRotationAnimationHint = -1;
966 
967     private AppSaturationInfo mLastAppSaturationInfo;
968 
969     private RemoteCallbackList<IScreenCaptureObserver> mCaptureCallbacks;
970 
971     private final ColorDisplayService.ColorTransformController mColorTransformController =
972             (matrix, translation) -> mWmService.mH.post(() -> {
973                 synchronized (mWmService.mGlobalLock) {
974                     if (mLastAppSaturationInfo == null) {
975                         mLastAppSaturationInfo = new AppSaturationInfo();
976                     }
977 
978                     mLastAppSaturationInfo.setSaturation(matrix, translation);
979                     updateColorTransform();
980                 }
981             });
982 
983     /**
984      * Current sequencing integer of the configuration, for skipping old activity configurations.
985      */
986     private int mConfigurationSeq;
987 
988     /**
989      * Temp configs used in {@link #ensureActivityConfiguration()}
990      */
991     private final Configuration mTmpConfig = new Configuration();
992     private final Rect mTmpBounds = new Rect();
993     private final ActivityWindowInfo mTmpActivityWindowInfo = new ActivityWindowInfo();
994 
995     // Token for targeting this activity for assist purposes.
996     final Binder assistToken = new Binder();
997 
998     // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be used
999     // without security checks
1000     final Binder shareableActivityToken = new Binder();
1001 
1002     // Token for accessing the initial caller who started the activity.
1003     final IBinder initialCallerInfoAccessToken = new Binder();
1004 
1005     // Tracking cookie for the launch of this activity and it's task.
1006     IBinder mLaunchCookie;
1007 
1008     // Tracking indicated launch root in order to propagate it among trampoline activities.
1009     WindowContainerToken mLaunchRootTask;
1010 
1011     // Entering PiP is usually done in two phases, we put the task into pinned mode first and
1012     // SystemUi sets the pinned mode on activity after transition is done.
1013     boolean mWaitForEnteringPinnedMode;
1014 
1015     final ActivityRecordInputSink mActivityRecordInputSink;
1016     // System activities with INTERNAL_SYSTEM_WINDOW can disable ActivityRecordInputSink.
1017     boolean mActivityRecordInputSinkEnabled = true;
1018 
1019     // Activities with this uid are allowed to not create an input sink while being in the same
1020     // task and directly above this ActivityRecord. This field is updated whenever a new activity
1021     // is launched from this ActivityRecord. Touches are always allowed within the same uid.
1022     int mAllowedTouchUid;
1023     // Whether client has requested a scene transition when exiting.
1024     final boolean mHasSceneTransition;
1025     // Whether the app has opt-in enableOnBackInvokedCallback.
1026     final boolean mOptInOnBackInvoked;
1027 
1028     // Whether the ActivityEmbedding is enabled on the app.
1029     private final boolean mAppActivityEmbeddingSplitsEnabled;
1030 
1031     // Whether the Activity allows state sharing in untrusted embedding
1032     private final boolean mAllowUntrustedEmbeddingStateSharing;
1033 
1034     // Records whether client has overridden the WindowAnimation_(Open/Close)(Enter/Exit)Animation.
1035     private CustomAppTransition mCustomOpenTransition;
1036     private CustomAppTransition mCustomCloseTransition;
1037 
1038     /** Non-zero to pause dispatching configuration changes to the client. */
1039     int mPauseConfigurationDispatchCount = 0;
1040 
1041     private final Runnable mPauseTimeoutRunnable = new Runnable() {
1042         @Override
1043         public void run() {
1044             // We don't at this point know if the activity is fullscreen,
1045             // so we need to be conservative and assume it isn't.
1046             Slog.w(TAG, "Activity pause timeout for " + ActivityRecord.this);
1047             synchronized (mAtmService.mGlobalLock) {
1048                 if (!hasProcess()) {
1049                     return;
1050                 }
1051                 mAtmService.logAppTooSlow(app, pauseTime, "pausing " + ActivityRecord.this);
1052                 activityPaused(true);
1053             }
1054         }
1055     };
1056 
1057     private final Runnable mLaunchTickRunnable = new Runnable() {
1058         @Override
1059         public void run() {
1060             synchronized (mAtmService.mGlobalLock) {
1061                 if (continueLaunchTicking()) {
1062                     mAtmService.logAppTooSlow(
1063                             app, launchTickTime, "launching " + ActivityRecord.this);
1064                 }
1065             }
1066         }
1067     };
1068 
1069     private final Runnable mDestroyTimeoutRunnable = new Runnable() {
1070         @Override
1071         public void run() {
1072             synchronized (mAtmService.mGlobalLock) {
1073                 Slog.w(TAG, "Activity destroy timeout for " + ActivityRecord.this);
1074                 destroyed("destroyTimeout");
1075             }
1076         }
1077     };
1078 
1079     private final Runnable mStopTimeoutRunnable = new Runnable() {
1080         @Override
1081         public void run() {
1082             synchronized (mAtmService.mGlobalLock) {
1083                 Slog.w(TAG, "Activity stop timeout for " + ActivityRecord.this);
1084                 if (isInHistory()) {
1085                     activityStopped(
1086                             null /*icicle*/, null /*persistentState*/, null /*description*/);
1087                 }
1088             }
1089         }
1090     };
1091 
1092     @NeverCompile // Avoid size overhead of debugging code.
1093     @Override
dump(PrintWriter pw, String prefix, boolean dumpAll)1094     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
1095         final long now = SystemClock.uptimeMillis();
1096         pw.print(prefix); pw.print("packageName="); pw.print(packageName);
1097                 pw.print(" processName="); pw.println(processName);
1098         pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
1099                 pw.print(" launchedFromPackage="); pw.print(launchedFromPackage);
1100                 pw.print(" launchedFromFeature="); pw.print(launchedFromFeatureId);
1101                 pw.print(" userId="); pw.println(mUserId);
1102         pw.print(prefix); pw.print("app="); pw.println(app);
1103         pw.print(prefix); pw.println(intent.toInsecureString());
1104         pw.print(prefix); pw.print("rootOfTask="); pw.print(isRootOfTask());
1105                 pw.print(" task="); pw.println(task);
1106         pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
1107         pw.print(prefix); pw.print("mActivityComponent=");
1108                 pw.println(mActivityComponent.flattenToShortString());
1109         final ApplicationInfo appInfo = info.applicationInfo;
1110         pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir);
1111         if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
1112             pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
1113         }
1114         pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
1115         if (appInfo.splitSourceDirs != null) {
1116             pw.print(prefix); pw.print("splitDir=");
1117             pw.println(Arrays.toString(appInfo.splitSourceDirs));
1118         }
1119         pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
1120                 pw.print(" componentSpecified="); pw.print(componentSpecified);
1121                 pw.print(" mActivityType="); pw.println(
1122                         activityTypeToString(getActivityType()));
1123         if (rootVoiceInteraction) {
1124             pw.print(prefix); pw.print("rootVoiceInteraction="); pw.println(rootVoiceInteraction);
1125         }
1126         pw.print(prefix); pw.print("compat=");
1127         pw.print(mAtmService.compatibilityInfoForPackageLocked(info.applicationInfo));
1128                 pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
1129         pw.println(prefix + "mLastReportedConfigurations:");
1130         mLastReportedConfiguration.dump(pw, prefix + "  ");
1131 
1132         if (Flags.activityWindowInfoFlag()) {
1133             pw.print(prefix);
1134             pw.print("mLastReportedActivityWindowInfo=");
1135             pw.println(mLastReportedActivityWindowInfo);
1136         }
1137 
1138         pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration());
1139         if (!getRequestedOverrideConfiguration().equals(EMPTY)) {
1140             pw.println(prefix + "RequestedOverrideConfiguration="
1141                     + getRequestedOverrideConfiguration());
1142         }
1143         if (!getResolvedOverrideConfiguration().equals(getRequestedOverrideConfiguration())) {
1144             pw.println(prefix + "ResolvedOverrideConfiguration="
1145                     + getResolvedOverrideConfiguration());
1146         }
1147         if (!matchParentBounds()) {
1148             pw.println(prefix + "bounds=" + getBounds());
1149         }
1150         if (resultTo != null || resultWho != null) {
1151             pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
1152                     pw.print(" resultWho="); pw.print(resultWho);
1153                     pw.print(" resultCode="); pw.println(requestCode);
1154         }
1155         if (taskDescription != null) {
1156             final String iconFilename = taskDescription.getIconFilename();
1157             if (iconFilename != null || taskDescription.getLabel() != null ||
1158                     taskDescription.getPrimaryColor() != 0) {
1159                 pw.print(prefix); pw.print("taskDescription:");
1160                         pw.print(" label=\""); pw.print(taskDescription.getLabel());
1161                                 pw.print("\"");
1162                         pw.print(" icon="); pw.print(taskDescription.getInMemoryIcon() != null
1163                                 ? taskDescription.getInMemoryIcon().getByteCount() + " bytes"
1164                                 : "null");
1165                         pw.print(" iconResource=");
1166                                 pw.print(taskDescription.getIconResourcePackage());
1167                                 pw.print("/");
1168                                 pw.print(taskDescription.getIconResource());
1169                         pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename());
1170                         pw.print(" primaryColor=");
1171                         pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
1172                         pw.print(prefix); pw.print("  backgroundColor=");
1173                         pw.print(Integer.toHexString(taskDescription.getBackgroundColor()));
1174                         pw.print(" statusBarColor=");
1175                         pw.print(Integer.toHexString(taskDescription.getStatusBarColor()));
1176                         pw.print(" navigationBarColor=");
1177                         pw.println(Integer.toHexString(taskDescription.getNavigationBarColor()));
1178                         pw.print(prefix); pw.print(" backgroundColorFloating=");
1179                         pw.println(Integer.toHexString(
1180                                 taskDescription.getBackgroundColorFloating()));
1181             }
1182         }
1183         if (results != null) {
1184             pw.print(prefix); pw.print("results="); pw.println(results);
1185         }
1186         if (pendingResults != null && pendingResults.size() > 0) {
1187             pw.print(prefix); pw.println("Pending Results:");
1188             for (WeakReference<PendingIntentRecord> wpir : pendingResults) {
1189                 PendingIntentRecord pir = wpir != null ? wpir.get() : null;
1190                 pw.print(prefix); pw.print("  - ");
1191                 if (pir == null) {
1192                     pw.println("null");
1193                 } else {
1194                     pw.println(pir);
1195                     pir.dump(pw, prefix + "    ");
1196                 }
1197             }
1198         }
1199         if (newIntents != null && newIntents.size() > 0) {
1200             pw.print(prefix); pw.println("Pending New Intents:");
1201             for (int i=0; i<newIntents.size(); i++) {
1202                 Intent intent = newIntents.get(i);
1203                 pw.print(prefix); pw.print("  - ");
1204                 if (intent == null) {
1205                     pw.println("null");
1206                 } else {
1207                     pw.println(intent.toShortString(false, true, false, false));
1208                 }
1209             }
1210         }
1211         if (mPendingOptions != null) {
1212             pw.print(prefix); pw.print("pendingOptions="); pw.println(mPendingOptions);
1213         }
1214         if (mPendingRemoteAnimation != null) {
1215             pw.print(prefix);
1216             pw.print("pendingRemoteAnimationCallingPid=");
1217             pw.println(mPendingRemoteAnimation.getCallingPid());
1218         }
1219         if (mPendingRemoteTransition != null) {
1220             pw.print(prefix + " pendingRemoteTransition="
1221                     + mPendingRemoteTransition.getRemoteTransition());
1222         }
1223         if (appTimeTracker != null) {
1224             appTimeTracker.dumpWithHeader(pw, prefix, false);
1225         }
1226         if (uriPermissions != null) {
1227             uriPermissions.dump(pw, prefix);
1228         }
1229         pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed);
1230                 pw.print(" launchCount="); pw.print(launchCount);
1231                 pw.print(" lastLaunchTime=");
1232                 if (lastLaunchTime == 0) pw.print("0");
1233                 else TimeUtils.formatDuration(lastLaunchTime, now, pw);
1234                 pw.println();
1235         if (mLaunchCookie != null) {
1236             pw.print(prefix);
1237             pw.print("launchCookie=");
1238             pw.println(mLaunchCookie);
1239         }
1240         if (mLaunchRootTask != null) {
1241             pw.print(prefix);
1242             pw.print("mLaunchRootTask=");
1243             pw.println(mLaunchRootTask);
1244         }
1245         pw.print(prefix); pw.print("mHaveState="); pw.print(mHaveState);
1246                 pw.print(" mIcicle="); pw.println(mIcicle);
1247         pw.print(prefix); pw.print("state="); pw.print(mState);
1248                 pw.print(" delayedResume="); pw.print(delayedResume);
1249                 pw.print(" finishing="); pw.println(finishing);
1250         pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
1251                 pw.print(" inHistory="); pw.print(inHistory);
1252                 pw.print(" idle="); pw.println(idle);
1253         pw.print(prefix); pw.print("occludesParent="); pw.print(occludesParent());
1254                 pw.print(" noDisplay="); pw.print(noDisplay);
1255                 pw.print(" immersive="); pw.print(immersive);
1256                 pw.print(" launchMode="); pw.println(launchMode);
1257         pw.print(prefix); pw.print("mActivityType=");
1258                 pw.println(activityTypeToString(getActivityType()));
1259         pw.print(prefix); pw.print("mImeInsetsFrozenUntilStartInput=");
1260                 pw.println(mImeInsetsFrozenUntilStartInput);
1261         if (requestedVrComponent != null) {
1262             pw.print(prefix);
1263             pw.print("requestedVrComponent=");
1264             pw.println(requestedVrComponent);
1265         }
1266         super.dump(pw, prefix, dumpAll);
1267         if (mVoiceInteraction) {
1268             pw.println(prefix + "mVoiceInteraction=true");
1269         }
1270         pw.print(prefix); pw.print("mOccludesParent="); pw.println(mOccludesParent);
1271         pw.print(prefix); pw.print("overrideOrientation=");
1272         pw.println(ActivityInfo.screenOrientationToString(getOverrideOrientation()));
1273         pw.print(prefix); pw.print("requestedOrientation=");
1274         pw.println(ActivityInfo.screenOrientationToString(super.getOverrideOrientation()));
1275         pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
1276                 + " mVisible=" + mVisible + " mClientVisible=" + isClientVisible()
1277                 + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
1278                 + " reportedDrawn=" + mReportedDrawn + " reportedVisible=" + reportedVisible);
1279         if (paused) {
1280             pw.print(prefix); pw.print("paused="); pw.println(paused);
1281         }
1282         if (mAppStopped) {
1283             pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
1284         }
1285         if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0
1286                 || allDrawn || mLastAllDrawn) {
1287             pw.print(prefix); pw.print("mNumInterestingWindows=");
1288             pw.print(mNumInterestingWindows);
1289             pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows);
1290             pw.print(" allDrawn="); pw.print(allDrawn);
1291             pw.print(" lastAllDrawn="); pw.print(mLastAllDrawn);
1292             pw.println(")");
1293         }
1294         if (mStartingData != null || firstWindowDrawn || mIsExiting) {
1295             pw.print(prefix); pw.print("startingData="); pw.print(mStartingData);
1296             pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
1297             pw.print(" mIsExiting="); pw.println(mIsExiting);
1298         }
1299         if (mStartingWindow != null || mStartingData != null || mStartingSurface != null
1300                 || startingMoved || mVisibleSetFromTransferredStartingWindow) {
1301             pw.print(prefix); pw.print("startingWindow="); pw.print(mStartingWindow);
1302             pw.print(" startingSurface="); pw.print(mStartingSurface);
1303             pw.print(" startingDisplayed="); pw.print(isStartingWindowDisplayed());
1304             pw.print(" startingMoved="); pw.print(startingMoved);
1305             pw.println(" mVisibleSetFromTransferredStartingWindow="
1306                     + mVisibleSetFromTransferredStartingWindow);
1307         }
1308         if (mPendingRelaunchCount != 0) {
1309             pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
1310         }
1311         if (mSizeCompatScale != 1f || mSizeCompatBounds != null) {
1312             pw.println(prefix + "mSizeCompatScale=" + mSizeCompatScale + " mSizeCompatBounds="
1313                     + mSizeCompatBounds);
1314         }
1315         if (mRemovingFromDisplay) {
1316             pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
1317         }
1318         if (lastVisibleTime != 0 || nowVisible) {
1319             pw.print(prefix); pw.print("nowVisible="); pw.print(nowVisible);
1320                     pw.print(" lastVisibleTime=");
1321                     if (lastVisibleTime == 0) pw.print("0");
1322                     else TimeUtils.formatDuration(lastVisibleTime, now, pw);
1323                     pw.println();
1324         }
1325         if (mDeferHidingClient) {
1326             pw.println(prefix + "mDeferHidingClient=" + mDeferHidingClient);
1327         }
1328         if (mServiceConnectionsHolder != null) {
1329             pw.print(prefix); pw.print("connections="); pw.println(mServiceConnectionsHolder);
1330         }
1331         if (info != null) {
1332             pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
1333             pw.println(prefix + "mLastReportedMultiWindowMode=" + mLastReportedMultiWindowMode
1334                     + " mLastReportedPictureInPictureMode=" + mLastReportedPictureInPictureMode);
1335             if (info.supportsPictureInPicture()) {
1336                 pw.println(prefix + "supportsPictureInPicture=" + info.supportsPictureInPicture());
1337                 pw.println(prefix + "supportsEnterPipOnTaskSwitch: "
1338                         + supportsEnterPipOnTaskSwitch);
1339                 pw.println(prefix + "mPauseSchedulePendingForPip=" + mPauseSchedulePendingForPip);
1340             }
1341             if (getMaxAspectRatio() != 0) {
1342                 pw.println(prefix + "maxAspectRatio=" + getMaxAspectRatio());
1343             }
1344             final float minAspectRatio = getMinAspectRatio();
1345             if (minAspectRatio != 0) {
1346                 pw.println(prefix + "minAspectRatio=" + minAspectRatio);
1347             }
1348             if (minAspectRatio != info.getManifestMinAspectRatio()) {
1349                 // Log the fact that we've overridden the min aspect ratio from the manifest
1350                 pw.println(prefix + "manifestMinAspectRatio="
1351                         + info.getManifestMinAspectRatio());
1352             }
1353             pw.println(prefix + "supportsSizeChanges="
1354                     + ActivityInfo.sizeChangesSupportModeToString(supportsSizeChanges()));
1355             if (info.configChanges != 0) {
1356                 pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
1357             }
1358             pw.println(prefix + "neverSandboxDisplayApis=" + info.neverSandboxDisplayApis(
1359                     sConstrainDisplayApisConfig));
1360             pw.println(prefix + "alwaysSandboxDisplayApis=" + info.alwaysSandboxDisplayApis(
1361                     sConstrainDisplayApisConfig));
1362         }
1363         if (mLastParentBeforePip != null) {
1364             pw.println(prefix + "lastParentTaskIdBeforePip=" + mLastParentBeforePip.mTaskId);
1365         }
1366         if (mLaunchIntoPipHostActivity != null) {
1367             pw.println(prefix + "launchIntoPipHostActivity=" + mLaunchIntoPipHostActivity);
1368         }
1369         if (mWaitForEnteringPinnedMode) {
1370             pw.print(prefix); pw.println("mWaitForEnteringPinnedMode=true");
1371         }
1372 
1373         mLetterboxUiController.dump(pw, prefix);
1374 
1375         pw.println(prefix + "mCameraCompatControlState="
1376                 + cameraCompatControlStateToString(mCameraCompatControlState));
1377         pw.println(prefix + "mCameraCompatControlEnabled=" + mCameraCompatControlEnabled);
1378     }
1379 
dumpActivity(FileDescriptor fd, PrintWriter pw, int index, ActivityRecord r, String prefix, String label, boolean complete, boolean brief, boolean client, String dumpPackage, boolean needNL, Runnable header, Task lastTask)1380     static boolean dumpActivity(FileDescriptor fd, PrintWriter pw, int index, ActivityRecord r,
1381             String prefix, String label, boolean complete, boolean brief, boolean client,
1382             String dumpPackage, boolean needNL, Runnable header, Task lastTask) {
1383         if (dumpPackage != null && !dumpPackage.equals(r.packageName)) {
1384             return false;
1385         }
1386 
1387         final boolean full = !brief && (complete || !r.isInHistory());
1388         if (needNL) {
1389             pw.println("");
1390         }
1391         if (header != null) {
1392             header.run();
1393         }
1394 
1395         String innerPrefix = prefix + "  ";
1396         String[] args = new String[0];
1397         if (lastTask != r.getTask()) {
1398             lastTask = r.getTask();
1399             pw.print(prefix);
1400             pw.print(full ? "* " : "  ");
1401             pw.println(lastTask);
1402             if (full) {
1403                 lastTask.dump(pw, prefix + "  ");
1404             } else if (complete) {
1405                 // Complete + brief == give a summary.  Isn't that obvious?!?
1406                 if (lastTask.intent != null) {
1407                     pw.print(prefix);
1408                     pw.print("  ");
1409                     pw.println(lastTask.intent.toInsecureString());
1410                 }
1411             }
1412         }
1413         pw.print(prefix); pw.print(full ? "* " : "    "); pw.print(label);
1414         pw.print(" #"); pw.print(index); pw.print(": ");
1415         pw.println(r);
1416         if (full) {
1417             r.dump(pw, innerPrefix, true /* dumpAll */);
1418         } else if (complete) {
1419             // Complete + brief == give a summary.  Isn't that obvious?!?
1420             pw.print(innerPrefix);
1421             pw.println(r.intent.toInsecureString());
1422             if (r.app != null) {
1423                 pw.print(innerPrefix);
1424                 pw.println(r.app);
1425             }
1426         }
1427         if (client && r.attachedToProcess()) {
1428             // flush anything that is already in the PrintWriter since the thread is going
1429             // to write to the file descriptor directly
1430             pw.flush();
1431             try {
1432                 TransferPipe tp = new TransferPipe();
1433                 try {
1434                     r.app.getThread().dumpActivity(
1435                             tp.getWriteFd(), r.token, innerPrefix, args);
1436                     // Short timeout, since blocking here can deadlock with the application.
1437                     tp.go(fd, 2000);
1438                 } finally {
1439                     tp.kill();
1440                 }
1441             } catch (IOException e) {
1442                 pw.println(innerPrefix + "Failure while dumping the activity: " + e);
1443             } catch (RemoteException e) {
1444                 pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
1445             }
1446         }
1447         return true;
1448     }
1449 
1450     /** Update the saved state of an activity. */
setSavedState(@ullable Bundle savedState)1451     void setSavedState(@Nullable Bundle savedState) {
1452         mIcicle = savedState;
1453         mHaveState = mIcicle != null;
1454     }
1455 
1456     /**
1457      * Get the actual Bundle instance of the saved state.
1458      * @see #hasSavedState() for checking if the record has saved state.
1459      */
getSavedState()1460     @Nullable Bundle getSavedState() {
1461         return mIcicle;
1462     }
1463 
1464     /**
1465      * Check if the activity has saved state.
1466      * @return {@code true} if the client reported a non-empty saved state from last onStop(), or
1467      *         if this record was just created and the client is yet to be launched and resumed.
1468      */
hasSavedState()1469     boolean hasSavedState() {
1470         return mHaveState;
1471     }
1472 
1473     /** @return The actual PersistableBundle instance of the saved persistent state. */
getPersistentSavedState()1474     @Nullable PersistableBundle getPersistentSavedState() {
1475         return mPersistentState;
1476     }
1477 
updateApplicationInfo(ApplicationInfo aInfo)1478     void updateApplicationInfo(ApplicationInfo aInfo) {
1479         info.applicationInfo = aInfo;
1480     }
1481 
setSizeConfigurations(SizeConfigurationBuckets sizeConfigurations)1482     void setSizeConfigurations(SizeConfigurationBuckets sizeConfigurations) {
1483         mSizeConfigurations = sizeConfigurations;
1484     }
1485 
scheduleActivityMovedToDisplay(int displayId, @NonNull Configuration config, @NonNull ActivityWindowInfo activityWindowInfo)1486     private void scheduleActivityMovedToDisplay(int displayId, @NonNull Configuration config,
1487             @NonNull ActivityWindowInfo activityWindowInfo) {
1488         if (!attachedToProcess()) {
1489             ProtoLog.w(WM_DEBUG_SWITCH, "Can't report activity moved "
1490                     + "to display - client not running, activityRecord=%s, displayId=%d",
1491                     this, displayId);
1492             return;
1493         }
1494         try {
1495             ProtoLog.v(WM_DEBUG_SWITCH, "Reporting activity moved to "
1496                     + "display, activityRecord=%s, displayId=%d, config=%s", this, displayId,
1497                     config);
1498 
1499             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
1500                     MoveToDisplayItem.obtain(token, displayId, config, activityWindowInfo));
1501         } catch (RemoteException e) {
1502             // If process died, whatever.
1503         }
1504     }
1505 
scheduleConfigurationChanged(@onNull Configuration config, @NonNull ActivityWindowInfo activityWindowInfo)1506     private void scheduleConfigurationChanged(@NonNull Configuration config,
1507             @NonNull ActivityWindowInfo activityWindowInfo) {
1508         if (!attachedToProcess()) {
1509             ProtoLog.w(WM_DEBUG_CONFIGURATION, "Can't report activity configuration "
1510                     + "update - client not running, activityRecord=%s", this);
1511             return;
1512         }
1513         try {
1514             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending new config to %s, "
1515                     + "config: %s", this, config);
1516 
1517             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
1518                     ActivityConfigurationChangeItem.obtain(token, config, activityWindowInfo));
1519         } catch (RemoteException e) {
1520             // If process died, whatever.
1521         }
1522     }
1523 
scheduleTopResumedActivityChanged(boolean onTop)1524     boolean scheduleTopResumedActivityChanged(boolean onTop) {
1525         if (!attachedToProcess()) {
1526             ProtoLog.w(WM_DEBUG_STATES,
1527                     "Can't report activity position update - client not running, "
1528                             + "activityRecord=%s", this);
1529             return false;
1530         }
1531         if (onTop) {
1532             app.addToPendingTop();
1533         }
1534         try {
1535             ProtoLog.v(WM_DEBUG_STATES, "Sending position change to %s, onTop: %b",
1536                     this, onTop);
1537 
1538             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
1539                     TopResumedActivityChangeItem.obtain(token, onTop));
1540         } catch (RemoteException e) {
1541             // If process died, whatever.
1542             Slog.w(TAG, "Failed to send top-resumed=" + onTop + " to " + this, e);
1543             return false;
1544         }
1545         return true;
1546     }
1547 
updateMultiWindowMode()1548     void updateMultiWindowMode() {
1549         if (task == null || task.getRootTask() == null || !attachedToProcess()) {
1550             return;
1551         }
1552 
1553         // An activity is considered to be in multi-window mode if its task isn't fullscreen.
1554         final boolean inMultiWindowMode = inMultiWindowMode();
1555         if (inMultiWindowMode != mLastReportedMultiWindowMode) {
1556             if (!inMultiWindowMode && mLastReportedPictureInPictureMode) {
1557                 updatePictureInPictureMode(null, false);
1558             } else {
1559                 mLastReportedMultiWindowMode = inMultiWindowMode;
1560                 ensureActivityConfiguration();
1561             }
1562         }
1563     }
1564 
updatePictureInPictureMode(Rect targetRootTaskBounds, boolean forceUpdate)1565     void updatePictureInPictureMode(Rect targetRootTaskBounds, boolean forceUpdate) {
1566         if (task == null || task.getRootTask() == null || !attachedToProcess()) {
1567             return;
1568         }
1569 
1570         final boolean inPictureInPictureMode =
1571                 inPinnedWindowingMode() && targetRootTaskBounds != null;
1572         if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) {
1573             // Picture-in-picture mode changes also trigger a multi-window mode change as well, so
1574             // update that here in order. Set the last reported MW state to the same as the PiP
1575             // state since we haven't yet actually resized the task (these callbacks need to
1576             // precede the configuration change from the resize.)
1577             mLastReportedPictureInPictureMode = inPictureInPictureMode;
1578             mLastReportedMultiWindowMode = inPictureInPictureMode;
1579             ensureActivityConfiguration(true /* ignoreVisibility */);
1580             if (inPictureInPictureMode && findMainWindow() == null
1581                     && task.topRunningActivity() == this) {
1582                 // Prevent malicious app entering PiP without valid WindowState, which can in turn
1583                 // result a non-touchable PiP window since the InputConsumer for PiP requires it.
1584                 EventLog.writeEvent(0x534e4554, "265293293", -1, "");
1585                 removeImmediately();
1586             }
1587         }
1588     }
1589 
getTask()1590     Task getTask() {
1591         return task;
1592     }
1593 
1594     @Nullable
getTaskFragment()1595     TaskFragment getTaskFragment() {
1596         WindowContainer parent = getParent();
1597         return parent != null ? parent.asTaskFragment() : null;
1598     }
1599 
1600     /** Whether we should prepare a transition for this {@link ActivityRecord} parent change. */
shouldStartChangeTransition( @ullable TaskFragment newParent, @Nullable TaskFragment oldParent)1601     private boolean shouldStartChangeTransition(
1602             @Nullable TaskFragment newParent, @Nullable TaskFragment oldParent) {
1603         if (newParent == null || oldParent == null || !canStartChangeTransition()) {
1604             return false;
1605         }
1606 
1607         final boolean isInPip2 = ActivityTaskManagerService.isPip2ExperimentEnabled()
1608                 && inPinnedWindowingMode();
1609         if (!newParent.isOrganizedTaskFragment() && !isInPip2) {
1610             // Parent TaskFragment isn't associated with a TF organizer and we are not in PiP2,
1611             // so do not allow for initializeChangeTransition() on parent changes
1612             return false;
1613         }
1614         // Transition change for the activity moving into TaskFragment of different bounds.
1615         return !newParent.getBounds().equals(oldParent.getBounds());
1616     }
1617 
1618     @Override
canStartChangeTransition()1619     boolean canStartChangeTransition() {
1620         final Task task = getTask();
1621         // Skip change transition when the Task is drag resizing.
1622         return task != null && !task.isDragResizing() && super.canStartChangeTransition();
1623     }
1624 
1625     @Override
onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent)1626     void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) {
1627         final TaskFragment oldParent = (TaskFragment) rawOldParent;
1628         final TaskFragment newParent = (TaskFragment) rawNewParent;
1629         final Task oldTask = oldParent != null ? oldParent.getTask() : null;
1630         final Task newTask = newParent != null ? newParent.getTask() : null;
1631         this.task = newTask;
1632 
1633         if (shouldStartChangeTransition(newParent, oldParent)) {
1634             if (mTransitionController.isShellTransitionsEnabled()) {
1635                 // For Shell transition, call #initializeChangeTransition directly to take the
1636                 // screenshot at the Activity level. And Shell will be in charge of handling the
1637                 // surface reparent and crop.
1638                 initializeChangeTransition(getBounds());
1639             } else {
1640                 // For legacy app transition, we want to take a screenshot of the Activity surface,
1641                 // but animate the change transition on TaskFragment level to get the correct window
1642                 // crop.
1643                 newParent.initializeChangeTransition(getBounds(), getSurfaceControl());
1644             }
1645         }
1646 
1647         super.onParentChanged(newParent, oldParent);
1648 
1649         if (isPersistable()) {
1650             if (oldTask != null) {
1651                 mAtmService.notifyTaskPersisterLocked(oldTask, false);
1652             }
1653             if (newTask != null) {
1654                 mAtmService.notifyTaskPersisterLocked(newTask, false);
1655             }
1656         }
1657 
1658         if (oldParent == null && newParent != null) {
1659             // First time we are adding the activity to the system.
1660             mVoiceInteraction = newTask.voiceSession != null;
1661 
1662             // TODO(b/36505427): Maybe this call should be moved inside
1663             // updateOverrideConfiguration()
1664             newTask.updateOverrideConfigurationFromLaunchBounds();
1665             // When an activity is started directly into a split-screen fullscreen root task, we
1666             // need to update the initial multi-window modes so that the callbacks are scheduled
1667             // correctly when the user leaves that mode.
1668             mLastReportedMultiWindowMode = inMultiWindowMode();
1669             mLastReportedPictureInPictureMode = inPinnedWindowingMode();
1670         }
1671 
1672         // When the associated task is {@code null}, the {@link ActivityRecord} can no longer
1673         // access visual elements like the {@link DisplayContent}. We must remove any associations
1674         // such as animations.
1675         if (task == null) {
1676             // It is possible we have been marked as a closing app earlier. We must remove ourselves
1677             // from this list so we do not participate in any future animations.
1678             if (getDisplayContent() != null) {
1679                 getDisplayContent().mClosingApps.remove(this);
1680             }
1681         }
1682         final Task rootTask = getRootTask();
1683 
1684         updateAnimatingActivityRegistry();
1685 
1686         if (task == mLastParentBeforePip && task != null) {
1687             // Notify the TaskFragmentOrganizer that the activity is reparented back from pip.
1688             mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController
1689                     .onActivityReparentedToTask(this);
1690             // Activity's reparented back from pip, clear the links once established
1691             clearLastParentBeforePip();
1692         }
1693 
1694         updateColorTransform();
1695 
1696         if (oldParent != null) {
1697             oldParent.cleanUpActivityReferences(this);
1698             // Clear the state as this activity is removed from its old parent.
1699             mRequestedLaunchingTaskFragmentToken = null;
1700         }
1701 
1702         if (newParent != null) {
1703             if (isState(RESUMED)) {
1704                 newParent.setResumedActivity(this, "onParentChanged");
1705             }
1706             mTransparentPolicy.start();
1707         }
1708 
1709         if (rootTask != null && rootTask.topRunningActivity() == this) {
1710             // make ensure the TaskOrganizer still works after re-parenting
1711             if (firstWindowDrawn) {
1712                 rootTask.setHasBeenVisible(true);
1713             }
1714         }
1715 
1716         // Update the input mode if the embedded mode is changed.
1717         updateUntrustedEmbeddingInputProtection();
1718     }
1719 
1720     @Override
setSurfaceControl(SurfaceControl sc)1721     void setSurfaceControl(SurfaceControl sc) {
1722         super.setSurfaceControl(sc);
1723         if (sc != null) {
1724             mLastDropInputMode = DropInputMode.NONE;
1725             updateUntrustedEmbeddingInputProtection();
1726         }
1727     }
1728 
1729     /** Sets if all input will be dropped as a protection during the client-driven animation. */
setDropInputForAnimation(boolean isInputDroppedForAnimation)1730     void setDropInputForAnimation(boolean isInputDroppedForAnimation) {
1731         if (mIsInputDroppedForAnimation == isInputDroppedForAnimation) {
1732             return;
1733         }
1734         mIsInputDroppedForAnimation = isInputDroppedForAnimation;
1735         updateUntrustedEmbeddingInputProtection();
1736     }
1737 
1738     /**
1739      * Sets to drop input when obscured to activity if it is embedded in untrusted mode.
1740      *
1741      * Although the untrusted embedded activity should be invisible when behind other overlay,
1742      * theoretically even if this activity is the top most, app can still move surface of activity
1743      * below it to the top. As a result, we want to update the input mode to drop when obscured for
1744      * all untrusted activities.
1745      */
updateUntrustedEmbeddingInputProtection()1746     private void updateUntrustedEmbeddingInputProtection() {
1747         if (getSurfaceControl() == null) {
1748             return;
1749         }
1750         if (mIsInputDroppedForAnimation) {
1751             // Disable all input during the animation.
1752             setDropInputMode(DropInputMode.ALL);
1753         } else if (isEmbeddedInUntrustedMode()) {
1754             // Set drop input to OBSCURED when untrusted embedded.
1755             setDropInputMode(DropInputMode.OBSCURED);
1756         } else {
1757             // Reset drop input mode when this activity is not embedded in untrusted mode.
1758             setDropInputMode(DropInputMode.NONE);
1759         }
1760     }
1761 
1762     @VisibleForTesting
setDropInputMode(@ropInputMode int mode)1763     void setDropInputMode(@DropInputMode int mode) {
1764         if (mLastDropInputMode != mode) {
1765             mLastDropInputMode = mode;
1766             mWmService.mTransactionFactory.get()
1767                     .setDropInputMode(getSurfaceControl(), mode)
1768                     .apply();
1769         }
1770     }
1771 
isEmbeddedInUntrustedMode()1772     private boolean isEmbeddedInUntrustedMode() {
1773         final TaskFragment organizedTaskFragment = getOrganizedTaskFragment();
1774         if (organizedTaskFragment == null) {
1775             // Not embedded.
1776             return false;
1777         }
1778         // Check if trusted.
1779         return !organizedTaskFragment.isAllowedToEmbedActivityInTrustedMode(this);
1780     }
1781 
updateAnimatingActivityRegistry()1782     void updateAnimatingActivityRegistry() {
1783         final Task rootTask = getRootTask();
1784         final AnimatingActivityRegistry registry = rootTask != null
1785                 ? rootTask.getAnimatingActivityRegistry()
1786                 : null;
1787 
1788         // If we reparent, make sure to remove ourselves from the old animation registry.
1789         if (mAnimatingActivityRegistry != null && mAnimatingActivityRegistry != registry) {
1790             mAnimatingActivityRegistry.notifyFinished(this);
1791         }
1792 
1793         mAnimatingActivityRegistry = registry;
1794     }
1795 
canAutoEnterPip()1796     boolean canAutoEnterPip() {
1797         // beforeStopping=false since the actual pip-ing will take place after startPausing()
1798         final boolean activityCanPip = checkEnterPictureInPictureState(
1799                 "startActivityUnchecked", false /* beforeStopping */);
1800 
1801         // check if this activity is about to auto-enter pip
1802         return activityCanPip && pictureInPictureArgs != null
1803                 && pictureInPictureArgs.isAutoEnterEnabled();
1804     }
1805 
1806     /**
1807      * Sets {@link #mLastParentBeforePip} to the current parent Task, it's caller's job to ensure
1808      * {@link #getTask()} is set before this is called.
1809      *
1810      * @param launchIntoPipHostActivity {@link ActivityRecord} as the host Activity for the
1811      *        launch-int-pip Activity see also {@link #mLaunchIntoPipHostActivity}.
1812      */
setLastParentBeforePip(@ullable ActivityRecord launchIntoPipHostActivity)1813     void setLastParentBeforePip(@Nullable ActivityRecord launchIntoPipHostActivity) {
1814         mLastParentBeforePip = (launchIntoPipHostActivity == null)
1815                 ? getTask()
1816                 : launchIntoPipHostActivity.getTask();
1817         mLastParentBeforePip.mChildPipActivity = this;
1818         mLaunchIntoPipHostActivity = launchIntoPipHostActivity;
1819         final TaskFragment organizedTf = launchIntoPipHostActivity == null
1820                 ? getOrganizedTaskFragment()
1821                 : launchIntoPipHostActivity.getOrganizedTaskFragment();
1822         mLastTaskFragmentOrganizerBeforePip = organizedTf != null
1823                 ? organizedTf.getTaskFragmentOrganizer()
1824                 : null;
1825         if (organizedTf != null
1826                 // Not necessary for content pip.
1827                 && launchIntoPipHostActivity == null) {
1828             mLastEmbeddedParentTfTokenBeforePip = organizedTf.getFragmentToken();
1829         }
1830     }
1831 
clearLastParentBeforePip()1832     void clearLastParentBeforePip() {
1833         if (mLastParentBeforePip != null) {
1834             mLastParentBeforePip.mChildPipActivity = null;
1835             mLastParentBeforePip = null;
1836         }
1837         mLaunchIntoPipHostActivity = null;
1838         mLastTaskFragmentOrganizerBeforePip = null;
1839         mLastEmbeddedParentTfTokenBeforePip = null;
1840     }
1841 
getLastParentBeforePip()1842     @Nullable Task getLastParentBeforePip() {
1843         return mLastParentBeforePip;
1844     }
1845 
getLastEmbeddedParentTfTokenBeforePip()1846     @Nullable IBinder getLastEmbeddedParentTfTokenBeforePip() {
1847         return mLastEmbeddedParentTfTokenBeforePip;
1848     }
1849 
getLaunchIntoPipHostActivity()1850     @Nullable ActivityRecord getLaunchIntoPipHostActivity() {
1851         return mLaunchIntoPipHostActivity;
1852     }
1853 
updateColorTransform()1854     private void updateColorTransform() {
1855         if (mSurfaceControl != null && mLastAppSaturationInfo != null) {
1856             getPendingTransaction().setColorTransform(mSurfaceControl,
1857                     mLastAppSaturationInfo.mMatrix, mLastAppSaturationInfo.mTranslation);
1858             mWmService.scheduleAnimationLocked();
1859         }
1860     }
1861 
1862     @Override
onDisplayChanged(DisplayContent dc)1863     void onDisplayChanged(DisplayContent dc) {
1864         DisplayContent prevDc = mDisplayContent;
1865         super.onDisplayChanged(dc);
1866         if (prevDc == mDisplayContent) {
1867             return;
1868         }
1869 
1870         mDisplayContent.onRunningActivityChanged();
1871 
1872         if (prevDc == null) {
1873             return;
1874         }
1875         prevDc.onRunningActivityChanged();
1876 
1877         // TODO(b/169035022): move to a more-appropriate place.
1878         mTransitionController.collect(this);
1879         if (prevDc.mOpeningApps.remove(this)) {
1880             // Transfer opening transition to new display.
1881             mDisplayContent.mOpeningApps.add(this);
1882             mDisplayContent.transferAppTransitionFrom(prevDc);
1883             mDisplayContent.executeAppTransition();
1884         }
1885 
1886         prevDc.mClosingApps.remove(this);
1887         prevDc.getDisplayPolicy().removeRelaunchingApp(this);
1888 
1889         if (prevDc.mFocusedApp == this) {
1890             prevDc.setFocusedApp(null);
1891             if (dc.getTopMostActivity() == this) {
1892                 dc.setFocusedApp(this);
1893             }
1894         }
1895 
1896         mLetterboxUiController.onMovedToDisplay(mDisplayContent.getDisplayId());
1897     }
1898 
layoutLetterboxIfNeeded(WindowState winHint)1899     void layoutLetterboxIfNeeded(WindowState winHint) {
1900         mLetterboxUiController.layoutLetterboxIfNeeded(winHint);
1901     }
1902 
hasWallpaperBackgroundForLetterbox()1903     boolean hasWallpaperBackgroundForLetterbox() {
1904         return mLetterboxUiController.hasWallpaperBackgroundForLetterbox();
1905     }
1906 
updateLetterboxSurfaceIfNeeded(WindowState winHint, Transaction t)1907     void updateLetterboxSurfaceIfNeeded(WindowState winHint, Transaction t) {
1908         mLetterboxUiController.updateLetterboxSurfaceIfNeeded(winHint, t, getPendingTransaction());
1909     }
1910 
updateLetterboxSurfaceIfNeeded(WindowState winHint)1911     void updateLetterboxSurfaceIfNeeded(WindowState winHint) {
1912         mLetterboxUiController.updateLetterboxSurfaceIfNeeded(winHint);
1913     }
1914 
1915     /** Gets the letterbox insets. The insets will be empty if there is no letterbox. */
getLetterboxInsets()1916     Rect getLetterboxInsets() {
1917         return mLetterboxUiController.getLetterboxInsets();
1918     }
1919 
1920     /** Gets the inner bounds of letterbox. The bounds will be empty if there is no letterbox. */
getLetterboxInnerBounds(Rect outBounds)1921     void getLetterboxInnerBounds(Rect outBounds) {
1922         mLetterboxUiController.getLetterboxInnerBounds(outBounds);
1923     }
1924 
updateCameraCompatState(boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback)1925     void updateCameraCompatState(boolean showControl, boolean transformationApplied,
1926             ICompatCameraControlCallback callback) {
1927         if (!isCameraCompatControlEnabled()) {
1928             // Feature is disabled by config_isCameraCompatControlForStretchedIssuesEnabled.
1929             return;
1930         }
1931         if (mCameraCompatControlClickedByUser && (showControl
1932                 || mCameraCompatControlState == CAMERA_COMPAT_CONTROL_DISMISSED)) {
1933             // The user already applied treatment on this activity or dismissed control.
1934             // Respecting their choice.
1935             return;
1936         }
1937         mCompatCameraControlCallback = callback;
1938         int newCameraCompatControlState = !showControl
1939                 ? CAMERA_COMPAT_CONTROL_HIDDEN
1940                 : transformationApplied
1941                         ? CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED
1942                         : CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
1943         boolean changed = setCameraCompatControlState(newCameraCompatControlState);
1944         if (!changed) {
1945             return;
1946         }
1947         mTaskSupervisor.getActivityMetricsLogger().logCameraCompatControlAppearedEventReported(
1948                 newCameraCompatControlState, info.applicationInfo.uid);
1949         if (newCameraCompatControlState == CAMERA_COMPAT_CONTROL_HIDDEN) {
1950             mCameraCompatControlClickedByUser = false;
1951             mCompatCameraControlCallback = null;
1952         }
1953         // Trigger TaskInfoChanged to update the camera compat UI.
1954         getTask().dispatchTaskInfoChangedIfNeeded(true /* force */);
1955         // TaskOrganizerController#onTaskInfoChanged adds pending task events to the queue waiting
1956         // for the surface placement to be ready. So need to trigger surface placement to dispatch
1957         // events to avoid stale state for the camera compat control.
1958         getDisplayContent().setLayoutNeeded();
1959         mWmService.mWindowPlacerLocked.performSurfacePlacement();
1960     }
1961 
updateCameraCompatStateFromUser(@ameraCompatControlState int state)1962     void updateCameraCompatStateFromUser(@CameraCompatControlState int state) {
1963         if (!isCameraCompatControlEnabled()) {
1964             // Feature is disabled by config_isCameraCompatControlForStretchedIssuesEnabled.
1965             return;
1966         }
1967         if (state == CAMERA_COMPAT_CONTROL_HIDDEN) {
1968             Slog.w(TAG, "Unexpected hidden state in updateCameraCompatState");
1969             return;
1970         }
1971         boolean changed = setCameraCompatControlState(state);
1972         mCameraCompatControlClickedByUser = true;
1973         if (!changed) {
1974             return;
1975         }
1976         mTaskSupervisor.getActivityMetricsLogger().logCameraCompatControlClickedEventReported(
1977                 state, info.applicationInfo.uid);
1978         if (state == CAMERA_COMPAT_CONTROL_DISMISSED) {
1979             mCompatCameraControlCallback = null;
1980             return;
1981         }
1982         if (mCompatCameraControlCallback == null) {
1983             Slog.w(TAG, "Callback for a camera compat control is null");
1984             return;
1985         }
1986         try {
1987             if (state == CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED) {
1988                 mCompatCameraControlCallback.applyCameraCompatTreatment();
1989             } else {
1990                 mCompatCameraControlCallback.revertCameraCompatTreatment();
1991             }
1992         } catch (RemoteException e) {
1993             Slog.e(TAG, "Unable to apply or revert camera compat treatment", e);
1994         }
1995     }
1996 
setCameraCompatControlState(@ameraCompatControlState int state)1997     private boolean setCameraCompatControlState(@CameraCompatControlState int state) {
1998         if (!isCameraCompatControlEnabled()) {
1999             // Feature is disabled by config_isCameraCompatControlForStretchedIssuesEnabled.
2000             return false;
2001         }
2002         if (mCameraCompatControlState != state) {
2003             mCameraCompatControlState = state;
2004             return true;
2005         }
2006         return false;
2007     }
2008 
2009     @CameraCompatControlState
getCameraCompatControlState()2010     int getCameraCompatControlState() {
2011         return mCameraCompatControlState;
2012     }
2013 
2014     @VisibleForTesting
isCameraCompatControlEnabled()2015     boolean isCameraCompatControlEnabled() {
2016         return mCameraCompatControlEnabled;
2017     }
2018 
2019     /**
2020      * @return {@code true} if bar shown within a given rectangle is allowed to be fully transparent
2021      *     when the current activity is displayed.
2022      */
isFullyTransparentBarAllowed(Rect rect)2023     boolean isFullyTransparentBarAllowed(Rect rect) {
2024         return mLetterboxUiController.isFullyTransparentBarAllowed(rect);
2025     }
2026 
2027     private static class Token extends Binder {
2028         @NonNull WeakReference<ActivityRecord> mActivityRef;
2029 
2030         @Override
toString()2031         public String toString() {
2032             return "Token{" + Integer.toHexString(System.identityHashCode(this)) + " "
2033                     + mActivityRef.get() + "}";
2034         }
2035     }
2036 
2037     /** Gets the corresponding record by the token. Note that it may not exist in the hierarchy. */
2038     @Nullable
forToken(IBinder token)2039     static ActivityRecord forToken(IBinder token) {
2040         if (token == null) return null;
2041         final Token activityToken;
2042         try {
2043             activityToken = (Token) token;
2044         } catch (ClassCastException e) {
2045             Slog.w(TAG, "Bad activity token: " + token, e);
2046             return null;
2047         }
2048         return activityToken.mActivityRef.get();
2049     }
2050 
forTokenLocked(IBinder token)2051     static @Nullable ActivityRecord forTokenLocked(IBinder token) {
2052         final ActivityRecord r = forToken(token);
2053         return r == null || r.getRootTask() == null ? null : r;
2054     }
2055 
isResolverActivity(String className)2056     static boolean isResolverActivity(String className) {
2057         return ResolverActivity.class.getName().equals(className);
2058     }
2059 
isResolverOrDelegateActivity()2060     boolean isResolverOrDelegateActivity() {
2061         return isResolverActivity(mActivityComponent.getClassName()) || Objects.equals(
2062                 mActivityComponent, mAtmService.mTaskSupervisor.getSystemChooserActivity());
2063     }
2064 
isResolverOrChildActivity()2065     boolean isResolverOrChildActivity() {
2066         if (!"android".equals(packageName)) {
2067             return false;
2068         }
2069         try {
2070             return ResolverActivity.class.isAssignableFrom(
2071                     Object.class.getClassLoader().loadClass(mActivityComponent.getClassName()));
2072         } catch (ClassNotFoundException e) {
2073             return false;
2074         }
2075     }
2076 
hasCaller(IBinder callerToken)2077     boolean hasCaller(IBinder callerToken) {
2078         return mCallerState.hasCaller(callerToken);
2079     }
2080 
getCallerUid(IBinder callerToken)2081     int getCallerUid(IBinder callerToken) {
2082         return mCallerState.getUid(callerToken);
2083     }
2084 
getCallerPackage(IBinder callerToken)2085     String getCallerPackage(IBinder callerToken) {
2086         return mCallerState.getPackage(callerToken);
2087     }
2088 
isCallerShareIdentityEnabled(IBinder callerToken)2089     boolean isCallerShareIdentityEnabled(IBinder callerToken) {
2090         return mCallerState.isShareIdentityEnabled(callerToken);
2091     }
2092 
computeInitialCallerInfo()2093     void computeInitialCallerInfo() {
2094         computeCallerInfo(initialCallerInfoAccessToken, intent, launchedFromUid,
2095                 launchedFromPackage, mShareIdentity);
2096     }
2097 
computeCallerInfo(IBinder callerToken, Intent intent, int callerUid, String callerPackageName, boolean isCallerShareIdentityEnabled)2098     void computeCallerInfo(IBinder callerToken, Intent intent, int callerUid,
2099             String callerPackageName, boolean isCallerShareIdentityEnabled) {
2100         mCallerState.computeCallerInfo(callerToken, intent, callerUid, callerPackageName,
2101                 isCallerShareIdentityEnabled);
2102     }
2103 
checkContentUriPermission(IBinder callerToken, GrantUri grantUri, int modeFlags)2104     boolean checkContentUriPermission(IBinder callerToken, GrantUri grantUri, int modeFlags) {
2105         return mCallerState.checkContentUriPermission(callerToken, grantUri, modeFlags);
2106     }
2107 
ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller, int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified, boolean _rootVoiceInteraction, ActivityTaskSupervisor supervisor, ActivityOptions options, ActivityRecord sourceRecord, PersistableBundle persistentState, TaskDescription _taskDescription, long _createTime)2108     private ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
2109             int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,
2110             @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType,
2111             ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo,
2112             String _resultWho, int _reqCode, boolean _componentSpecified,
2113             boolean _rootVoiceInteraction, ActivityTaskSupervisor supervisor,
2114             ActivityOptions options, ActivityRecord sourceRecord, PersistableBundle persistentState,
2115             TaskDescription _taskDescription, long _createTime) {
2116         super(_service.mWindowManager, new Token(), TYPE_APPLICATION, true,
2117                 null /* displayContent */, false /* ownerCanManageAppTokens */);
2118 
2119         mAtmService = _service;
2120         ((Token) token).mActivityRef = new WeakReference<>(this);
2121         info = aInfo;
2122         mUserId = UserHandle.getUserId(info.applicationInfo.uid);
2123         packageName = info.applicationInfo.packageName;
2124         intent = _intent;
2125 
2126         // If the class name in the intent doesn't match that of the target, this is probably an
2127         // alias. We have to create a new ComponentName object to keep track of the real activity
2128         // name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly.
2129         if (info.targetActivity == null
2130                 || (info.targetActivity.equals(intent.getComponent().getClassName())
2131                 && (info.launchMode == LAUNCH_MULTIPLE
2132                 || info.launchMode == LAUNCH_SINGLE_TOP))) {
2133             mActivityComponent = intent.getComponent();
2134         } else {
2135             mActivityComponent =
2136                     new ComponentName(info.packageName, info.targetActivity);
2137         }
2138 
2139         // Don't move below setActivityType since it triggers onConfigurationChange ->
2140         // resolveOverrideConfiguration that requires having mLetterboxUiController initialised.
2141         // Don't move below setOrientation(info.screenOrientation) since it triggers
2142         // getOverrideOrientation that requires having mLetterboxUiController
2143         // initialised.
2144         mTransparentPolicy = new TransparentPolicy(this, mWmService.mLetterboxConfiguration);
2145         mLetterboxUiController = new LetterboxUiController(mWmService, this);
2146         mCameraCompatControlEnabled = mWmService.mContext.getResources()
2147                 .getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
2148         mResolveConfigHint = new TaskFragment.ConfigOverrideHint();
2149         if (mWmService.mFlags.mInsetsDecoupledConfiguration) {
2150             // When the stable configuration is the default behavior, override for the legacy apps
2151             // without forward override flag.
2152             mResolveConfigHint.mUseOverrideInsetsForConfig =
2153                     !info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED)
2154                             && !info.isChangeEnabled(
2155                                     OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
2156         } else {
2157             // When the stable configuration is not the default behavior, forward overriding the
2158             // listed apps.
2159             mResolveConfigHint.mUseOverrideInsetsForConfig =
2160                     info.isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
2161         }
2162 
2163         mTargetSdk = info.applicationInfo.targetSdkVersion;
2164 
2165         final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
2166         final UserProperties properties = umi.getUserProperties(mUserId);
2167         mIsUserAlwaysVisible =  properties != null && properties.getAlwaysVisible();
2168 
2169         mShowForAllUsers = (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0 || mIsUserAlwaysVisible;
2170         setOrientation(info.screenOrientation);
2171         mRotationAnimationHint = info.rotationAnimation;
2172 
2173         mShowWhenLocked = (aInfo.flags & ActivityInfo.FLAG_SHOW_WHEN_LOCKED) != 0;
2174         mInheritShownWhenLocked = (aInfo.privateFlags & FLAG_INHERIT_SHOW_WHEN_LOCKED) != 0;
2175         mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0;
2176 
2177         int realTheme = info.getThemeResource();
2178         if (realTheme == Resources.ID_NULL) {
2179             realTheme = aInfo.applicationInfo.targetSdkVersion < HONEYCOMB
2180                     ? android.R.style.Theme : android.R.style.Theme_Holo;
2181         }
2182 
2183         final AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
2184                 realTheme, com.android.internal.R.styleable.Window, mUserId);
2185 
2186         if (ent != null) {
2187             mOccludesParent = !ActivityInfo.isTranslucentOrFloating(ent.array)
2188                     // This style is propagated to the main window attributes with
2189                     // FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout.
2190                     || ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
2191             mStyleFillsParent = mOccludesParent;
2192             noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
2193             mOptOutEdgeToEdge = ent.array.getBoolean(
2194                     R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false);
2195         } else {
2196             mStyleFillsParent = mOccludesParent = true;
2197             noDisplay = false;
2198             mOptOutEdgeToEdge = false;
2199         }
2200 
2201         if (options != null) {
2202             mLaunchTaskBehind = options.getLaunchTaskBehind();
2203 
2204             final int rotationAnimation = options.getRotationAnimationHint();
2205             // Only override manifest supplied option if set.
2206             if (rotationAnimation >= 0) {
2207                 mRotationAnimationHint = rotationAnimation;
2208             }
2209 
2210             if (options.getLaunchIntoPipParams() != null) {
2211                 pictureInPictureArgs = options.getLaunchIntoPipParams();
2212                 if (sourceRecord != null) {
2213                     adjustPictureInPictureParamsIfNeeded(sourceRecord.getBounds());
2214                 }
2215             }
2216 
2217             mOverrideTaskTransition = options.getOverrideTaskTransition();
2218             mDismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure();
2219             mShareIdentity = options.isShareIdentityEnabled();
2220         }
2221 
2222         ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
2223                 ColorDisplayService.ColorDisplayServiceInternal.class);
2224         cds.attachColorTransformController(packageName, mUserId,
2225                 new WeakReference<>(mColorTransformController));
2226 
2227         mRootWindowContainer = _service.mRootWindowContainer;
2228         launchedFromPid = _launchedFromPid;
2229         launchedFromUid = _launchedFromUid;
2230         launchedFromPackage = _launchedFromPackage;
2231         launchedFromFeatureId = _launchedFromFeature;
2232         mLaunchSourceType = determineLaunchSourceType(_launchedFromUid, _caller);
2233         shortComponentName = _intent.getComponent().flattenToShortString();
2234         resolvedType = _resolvedType;
2235         componentSpecified = _componentSpecified;
2236         rootVoiceInteraction = _rootVoiceInteraction;
2237         mLastReportedConfiguration = new MergedConfiguration(_configuration);
2238         resultTo = _resultTo;
2239         resultWho = _resultWho;
2240         requestCode = _reqCode;
2241         setState(INITIALIZING, "ActivityRecord ctor");
2242         launchFailed = false;
2243         delayedResume = false;
2244         finishing = false;
2245         keysPaused = false;
2246         inHistory = false;
2247         nowVisible = false;
2248         super.setClientVisible(true);
2249         idle = false;
2250         hasBeenLaunched = false;
2251         mTaskSupervisor = supervisor;
2252 
2253         info.taskAffinity = computeTaskAffinity(info.taskAffinity, info.applicationInfo.uid);
2254         taskAffinity = info.taskAffinity;
2255         final String uid = Integer.toString(info.applicationInfo.uid);
2256         if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
2257                 && !info.windowLayout.windowLayoutAffinity.startsWith(uid)) {
2258             info.windowLayout.windowLayoutAffinity =
2259                     uid + ":" + info.windowLayout.windowLayoutAffinity;
2260         }
2261         // Initialize once, when we know all system services are available.
2262         if (sConstrainDisplayApisConfig == null) {
2263             sConstrainDisplayApisConfig = new ConstrainDisplayApisConfig();
2264         }
2265         stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
2266         theme = aInfo.getThemeResource();
2267         if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null
2268                 && (aInfo.applicationInfo.uid == SYSTEM_UID
2269                     || aInfo.applicationInfo.uid == _caller.mInfo.uid)) {
2270             processName = _caller.mName;
2271         } else {
2272             processName = aInfo.processName;
2273         }
2274 
2275         if ((aInfo.flags & FLAG_EXCLUDE_FROM_RECENTS) != 0) {
2276             intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
2277         }
2278 
2279         launchMode = aInfo.launchMode;
2280 
2281         setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord);
2282 
2283         immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0;
2284 
2285         requestedVrComponent = (aInfo.requestedVrComponent == null) ?
2286                 null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
2287 
2288         lockTaskLaunchMode = getLockTaskLaunchMode(aInfo, options);
2289 
2290         if (options != null) {
2291             setOptions(options);
2292             // The result receiver is the transition receiver, which will handle the shared element
2293             // exit transition.
2294             mHasSceneTransition = options.getAnimationType() == ANIM_SCENE_TRANSITION
2295                     && options.getSceneTransitionInfo() != null
2296                     && options.getSceneTransitionInfo().getResultReceiver() != null;
2297             final PendingIntent usageReport = options.getUsageTimeReport();
2298             if (usageReport != null) {
2299                 appTimeTracker = new AppTimeTracker(usageReport);
2300             }
2301             // Gets launch task display area and display id from options. Returns
2302             // null/INVALID_DISPLAY if not set.
2303             final WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
2304             mHandoverTaskDisplayArea = daToken != null
2305                     ? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
2306             mHandoverLaunchDisplayId = options.getLaunchDisplayId();
2307             mLaunchCookie = options.getLaunchCookie();
2308             mLaunchRootTask = options.getLaunchRootTask();
2309         } else {
2310             mHasSceneTransition = false;
2311         }
2312 
2313         mPersistentState = persistentState;
2314         taskDescription = _taskDescription;
2315 
2316         shouldDockBigOverlays = mWmService.mContext.getResources()
2317                 .getBoolean(R.bool.config_dockBigOverlayWindows);
2318 
2319         if (_createTime > 0) {
2320             createTime = _createTime;
2321         }
2322         mAtmService.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, packageName);
2323 
2324         mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
2325 
2326         mAppActivityEmbeddingSplitsEnabled = isAppActivityEmbeddingSplitsEnabled();
2327         mAllowUntrustedEmbeddingStateSharing = getAllowUntrustedEmbeddingStateSharingProperty();
2328 
2329         mOptInOnBackInvoked = WindowOnBackInvokedDispatcher
2330                 .isOnBackInvokedCallbackEnabled(info, info.applicationInfo,
2331                         () -> {
2332                             Context appContext = null;
2333                             try {
2334                                 appContext = mAtmService.mContext.createPackageContextAsUser(
2335                                         info.packageName, CONTEXT_RESTRICTED,
2336                                         UserHandle.of(mUserId));
2337                                 appContext.setTheme(theme);
2338                             } catch (PackageManager.NameNotFoundException ignore) {
2339                             }
2340                             return appContext;
2341                         });
2342         mCallerState = new ActivityCallerState(mAtmService);
2343     }
2344 
isAppActivityEmbeddingSplitsEnabled()2345     private boolean isAppActivityEmbeddingSplitsEnabled() {
2346         if (!hasWindowExtensionsEnabled()) {
2347             // WM Extensions disabled.
2348             return false;
2349         }
2350         if (ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 && !CompatChanges.isChangeEnabled(
2351                 ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15,
2352                 info.packageName,
2353                 UserHandle.getUserHandleForUid(getUid()))) {
2354             // Activity Embedding is guarded with Android 15+, but this app is not qualified.
2355             return false;
2356         }
2357         try {
2358             return mAtmService.mContext.getPackageManager()
2359                     .getProperty(PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED, packageName)
2360                     .getBoolean();
2361         } catch (PackageManager.NameNotFoundException e) {
2362             // No such property name.
2363             return false;
2364         }
2365     }
2366 
2367     /**
2368      * Generate the task affinity with uid and activity launch mode. For b/35954083, Limit task
2369      * affinity to uid to avoid issues associated with sharing affinity across uids.
2370      *
2371      * @param affinity The affinity of the activity.
2372      * @param uid The user-ID that has been assigned to this application.
2373      * @return The task affinity
2374      */
computeTaskAffinity(String affinity, int uid)2375     static String computeTaskAffinity(String affinity, int uid) {
2376         final String uidStr = Integer.toString(uid);
2377         if (affinity != null && !affinity.startsWith(uidStr)) {
2378             affinity = uidStr + ":" + affinity;
2379         }
2380         return affinity;
2381     }
2382 
getLockTaskLaunchMode(ActivityInfo aInfo, @Nullable ActivityOptions options)2383     static int getLockTaskLaunchMode(ActivityInfo aInfo, @Nullable ActivityOptions options) {
2384         int lockTaskLaunchMode = aInfo.lockTaskLaunchMode;
2385         // Non-priv apps are not allowed to use always or never, fall back to default
2386         if (!aInfo.applicationInfo.isPrivilegedApp()
2387                 && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
2388                 || lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
2389             lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
2390         }
2391         if (options != null) {
2392             final boolean useLockTask = options.getLockTaskMode();
2393             if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
2394                 lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
2395             }
2396         }
2397         return lockTaskLaunchMode;
2398     }
2399 
getInputApplicationHandle(boolean update)2400     @NonNull InputApplicationHandle getInputApplicationHandle(boolean update) {
2401         if (mInputApplicationHandle == null) {
2402             mInputApplicationHandle = new InputApplicationHandle(token, toString(),
2403                     mInputDispatchingTimeoutMillis);
2404         } else if (update) {
2405             final String name = toString();
2406             if (mInputDispatchingTimeoutMillis != mInputApplicationHandle.dispatchingTimeoutMillis
2407                     || !name.equals(mInputApplicationHandle.name)) {
2408                 mInputApplicationHandle = new InputApplicationHandle(token, name,
2409                         mInputDispatchingTimeoutMillis);
2410             }
2411         }
2412         return mInputApplicationHandle;
2413     }
2414 
2415     @Override
asActivityRecord()2416     ActivityRecord asActivityRecord() {
2417         // I am an activity record!
2418         return this;
2419     }
2420 
2421     @Override
hasActivity()2422     boolean hasActivity() {
2423         // I am an activity!
2424         return true;
2425     }
2426 
setProcess(WindowProcessController proc)2427     void setProcess(WindowProcessController proc) {
2428         app = proc;
2429         final ActivityRecord root = task != null ? task.getRootActivity() : null;
2430         if (root == this) {
2431             task.setRootProcess(proc);
2432         }
2433         proc.addActivityIfNeeded(this);
2434         mInputDispatchingTimeoutMillis = getInputDispatchingTimeoutMillisLocked(this);
2435 
2436         // Update the associated task fragment after setting the process, since it's required for
2437         // filtering to only report activities that belong to the same process.
2438         final TaskFragment tf = getTaskFragment();
2439         if (tf != null) {
2440             tf.sendTaskFragmentInfoChanged();
2441         }
2442     }
2443 
hasProcess()2444     boolean hasProcess() {
2445         return app != null;
2446     }
2447 
attachedToProcess()2448     boolean attachedToProcess() {
2449         return hasProcess() && app.hasThread();
2450     }
2451 
2452     /**
2453      * Evaluate the theme for a starting window.
2454      * @param prev Previous activity which may have a starting window.
2455      * @param originalTheme The original theme which read from activity or application.
2456      * @param replaceTheme The replace theme which requested from starter.
2457      * @return Resolved theme.
2458      */
evaluateStartingWindowTheme(ActivityRecord prev, String pkg, int originalTheme, int replaceTheme)2459     private int evaluateStartingWindowTheme(ActivityRecord prev, String pkg, int originalTheme,
2460             int replaceTheme) {
2461         // Skip if the package doesn't want a starting window.
2462         if (!validateStartingWindowTheme(prev, pkg, originalTheme)) {
2463             return 0;
2464         }
2465         int selectedTheme = originalTheme;
2466         if (replaceTheme != 0 && validateStartingWindowTheme(prev, pkg, replaceTheme)) {
2467             // allow to replace theme
2468             selectedTheme = replaceTheme;
2469         }
2470         return selectedTheme;
2471     }
2472 
2473     /**
2474      * @return Whether this {@link ActivityRecord} was launched from a system surface (e.g
2475      * Launcher, Notification,...)
2476      */
launchedFromSystemSurface()2477     private boolean launchedFromSystemSurface() {
2478         return mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEM
2479                 || mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME
2480                 || mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI;
2481     }
2482 
isLaunchSourceType(@aunchSourceType int type)2483     boolean isLaunchSourceType(@LaunchSourceType int type) {
2484         return mLaunchSourceType == type;
2485     }
2486 
determineLaunchSourceType(int launchFromUid, WindowProcessController caller)2487     private int determineLaunchSourceType(int launchFromUid, WindowProcessController caller) {
2488         if (launchFromUid == Process.SYSTEM_UID || launchFromUid == Process.ROOT_UID) {
2489             return LAUNCH_SOURCE_TYPE_SYSTEM;
2490         }
2491         if (caller != null) {
2492             if (caller.isHomeProcess()) {
2493                 return LAUNCH_SOURCE_TYPE_HOME;
2494             }
2495             if (mAtmService.getSysUiServiceComponentLocked().getPackageName()
2496                     .equals(caller.mInfo.packageName)) {
2497                 return LAUNCH_SOURCE_TYPE_SYSTEMUI;
2498             }
2499         }
2500         return LAUNCH_SOURCE_TYPE_APPLICATION;
2501     }
2502 
validateStartingWindowTheme(ActivityRecord prev, String pkg, int theme)2503     private boolean validateStartingWindowTheme(ActivityRecord prev, String pkg, int theme) {
2504         // If this is a translucent window, then don't show a starting window -- the current
2505         // effect (a full-screen opaque starting window that fades away to the real contents
2506         // when it is ready) does not work for this.
2507         ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Checking theme of starting window: 0x%x", theme);
2508         if (theme == 0) {
2509             return false;
2510         }
2511 
2512         final AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
2513                 com.android.internal.R.styleable.Window, mWmService.mCurrentUserId);
2514         if (ent == null) {
2515             // Whoops!  App doesn't exist. Um. Okay. We'll just pretend like we didn't
2516             // see that.
2517             return false;
2518         }
2519         final boolean windowIsTranslucent = ent.array.getBoolean(
2520                 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
2521         final boolean windowIsFloating = ent.array.getBoolean(
2522                 com.android.internal.R.styleable.Window_windowIsFloating, false);
2523         final boolean windowShowWallpaper = ent.array.getBoolean(
2524                 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
2525         final boolean windowDisableStarting = ent.array.getBoolean(
2526                 com.android.internal.R.styleable.Window_windowDisablePreview, false);
2527         ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
2528                 "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
2529                 windowIsTranslucent, windowIsFloating, windowShowWallpaper,
2530                 windowDisableStarting);
2531         // If this activity is launched from system surface, ignore windowDisableStarting
2532         if (windowIsTranslucent || windowIsFloating) {
2533             return false;
2534         }
2535         if (windowShowWallpaper
2536                 && getDisplayContent().mWallpaperController.getWallpaperTarget() != null) {
2537             return false;
2538         }
2539         if (windowDisableStarting && !launchedFromSystemSurface()) {
2540             // Check if previous activity can transfer the starting window to this activity.
2541             return prev != null && prev.getActivityType() == ACTIVITY_TYPE_STANDARD
2542                     && prev.mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_IDLE
2543                     && (prev.mStartingData != null
2544                     || (prev.mStartingWindow != null && prev.mStartingSurface != null));
2545         }
2546         return true;
2547     }
2548 
2549     @VisibleForTesting
addStartingWindow(String pkg, int resolvedTheme, ActivityRecord from, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean isSimple, boolean activityAllDrawn)2550     boolean addStartingWindow(String pkg, int resolvedTheme, ActivityRecord from, boolean newTask,
2551             boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot,
2552             boolean activityCreated, boolean isSimple,
2553             boolean activityAllDrawn) {
2554         // If the display is frozen, we won't do anything until the actual window is
2555         // displayed so there is no reason to put in the starting window.
2556         if (!okToDisplay()) {
2557             return false;
2558         }
2559 
2560         if (hasStartingWindow()) {
2561             return false;
2562         }
2563 
2564         final WindowState mainWin = findMainWindow(false /* includeStartingApp */);
2565         if (mainWin != null && mainWin.isDrawn()) {
2566             // App already has a visible window...why would you want a starting window?
2567             return false;
2568         }
2569 
2570         final TaskSnapshot snapshot =
2571                 mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
2572                         false /* restoreFromDisk */, false /* isLowResolution */);
2573         final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
2574                 allowTaskSnapshot, activityCreated, activityAllDrawn, snapshot);
2575 
2576         //TODO(191787740) Remove for V+
2577         final boolean useLegacy = type == STARTING_WINDOW_TYPE_SPLASH_SCREEN
2578                 && mWmService.mStartingSurfaceController.isExceptionApp(packageName, mTargetSdk,
2579                     () -> {
2580                         ActivityInfo activityInfo = intent.resolveActivityInfo(
2581                                 mAtmService.mContext.getPackageManager(),
2582                                 PackageManager.GET_META_DATA);
2583                         return activityInfo != null ? activityInfo.applicationInfo : null;
2584                     });
2585 
2586         final int typeParameter = StartingSurfaceController
2587                 .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning,
2588                         allowTaskSnapshot, activityCreated, isSimple, useLegacy, activityAllDrawn,
2589                         type, isIconStylePreferred(resolvedTheme), packageName, mUserId);
2590 
2591         if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
2592             if (isActivityTypeHome()) {
2593                 // The snapshot of home is only used once because it won't be updated while screen
2594                 // is on (see {@link TaskSnapshotController#screenTurningOff}).
2595                 mWmService.mTaskSnapshotController.removeSnapshotCache(task.mTaskId);
2596                 if ((mDisplayContent.mAppTransition.getTransitFlags()
2597                         & WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
2598                     // Only use snapshot of home as starting window when unlocking directly.
2599                     return false;
2600                 }
2601             }
2602             return createSnapshot(snapshot, typeParameter);
2603         }
2604 
2605         // Original theme can be 0 if developer doesn't request any theme. So if resolved theme is 0
2606         // but original theme is not 0, means this package doesn't want a starting window.
2607         if (resolvedTheme == 0 && theme != 0) {
2608             return false;
2609         }
2610 
2611         if (from != null && transferStartingWindow(from)) {
2612             return true;
2613         }
2614 
2615         // There is no existing starting window, and we don't want to create a splash screen, so
2616         // that's it!
2617         if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
2618             return false;
2619         }
2620 
2621         ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData");
2622         mStartingData = new SplashScreenStartingData(mWmService, resolvedTheme, typeParameter);
2623         scheduleAddStartingWindow();
2624         return true;
2625     }
2626 
createSnapshot(TaskSnapshot snapshot, int typeParams)2627     private boolean createSnapshot(TaskSnapshot snapshot, int typeParams) {
2628         if (snapshot == null) {
2629             return false;
2630         }
2631 
2632         ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData");
2633         mStartingData = new SnapshotStartingData(mWmService, snapshot, typeParams);
2634         if ((!mStyleFillsParent && task.getChildCount() > 1)
2635                 || task.forAllLeafTaskFragments(TaskFragment::isEmbedded)) {
2636             // Case 1:
2637             // If it is moving a Task{[0]=main activity, [1]=translucent activity} to front, use
2638             // shared starting window so that the transition doesn't need to wait for the activity
2639             // behind the translucent activity. Also, onFirstWindowDrawn will check all visible
2640             // activities are drawn in the task to remove the snapshot starting window.
2641             // Case 2:
2642             // Associate with the task so if this activity is resized by task fragment later, the
2643             // starting window can keep the same bounds as the task.
2644             associateStartingDataWithTask();
2645         }
2646         scheduleAddStartingWindow();
2647         return true;
2648     }
2649 
scheduleAddStartingWindow()2650     private void scheduleAddStartingWindow() {
2651         ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Add starting %s: startingData=%s",
2652                 this, mStartingData);
2653 
2654         mStartingSurface = mStartingData.createStartingSurface(ActivityRecord.this);
2655         if (mStartingSurface != null) {
2656             ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
2657                     "Added starting %s: startingWindow=%s startingView=%s",
2658                     ActivityRecord.this, mStartingWindow, mStartingSurface);
2659         } else {
2660             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s",
2661                     ActivityRecord.this);
2662         }
2663     }
2664 
getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean activityAllDrawn, TaskSnapshot snapshot)2665     private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
2666             boolean allowTaskSnapshot, boolean activityCreated, boolean activityAllDrawn,
2667             TaskSnapshot snapshot) {
2668         // A special case that a new activity is launching to an existing task which is moving to
2669         // front. If the launching activity is the one that started the task, it could be a
2670         // trampoline that will be always created and finished immediately. Then give a chance to
2671         // see if the snapshot is usable for the current running activity so the transition will
2672         // look smoother, instead of showing a splash screen on the second launch.
2673         if (!newTask && taskSwitch && processRunning && !activityCreated && task.intent != null
2674                 && mActivityComponent.equals(task.intent.getComponent())) {
2675             final ActivityRecord topAttached = task.getActivity(ActivityRecord::attachedToProcess);
2676             if (topAttached != null) {
2677                 if (topAttached.isSnapshotCompatible(snapshot)
2678                         // This trampoline must be the same rotation.
2679                         && mDisplayContent.getDisplayRotation().rotationForOrientation(
2680                                 getOverrideOrientation(),
2681                                 mDisplayContent.getRotation()) == snapshot.getRotation()) {
2682                     return STARTING_WINDOW_TYPE_SNAPSHOT;
2683                 }
2684                 // No usable snapshot. And a splash screen may also be weird because an existing
2685                 // activity may be shown right after the trampoline is finished.
2686                 return STARTING_WINDOW_TYPE_NONE;
2687             }
2688         }
2689         final boolean isActivityHome = isActivityTypeHome();
2690         if ((newTask || !processRunning || (taskSwitch && !activityCreated))
2691                 && !isActivityHome) {
2692             return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
2693         }
2694         if (taskSwitch) {
2695             if (allowTaskSnapshot) {
2696                 if (isSnapshotCompatible(snapshot)) {
2697                     return STARTING_WINDOW_TYPE_SNAPSHOT;
2698                 }
2699                 if (!isActivityHome) {
2700                     return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
2701                 }
2702             }
2703             if (!activityAllDrawn && !isActivityHome) {
2704                 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
2705             }
2706         }
2707         return STARTING_WINDOW_TYPE_NONE;
2708     }
2709 
2710     /**
2711      * Returns {@code true} if the task snapshot is compatible with this activity (at least the
2712      * rotation must be the same).
2713      */
2714     @VisibleForTesting
isSnapshotCompatible(TaskSnapshot snapshot)2715     boolean isSnapshotCompatible(TaskSnapshot snapshot) {
2716         if (snapshot == null) {
2717             return false;
2718         }
2719         return isSnapshotComponentCompatible(snapshot) && isSnapshotOrientationCompatible(snapshot);
2720     }
2721 
2722     /**
2723      * Returns {@code true} if the top activity component of task snapshot equals to this activity.
2724      */
isSnapshotComponentCompatible(@onNull TaskSnapshot snapshot)2725     boolean isSnapshotComponentCompatible(@NonNull TaskSnapshot snapshot) {
2726         return snapshot.getTopActivityComponent().equals(mActivityComponent);
2727     }
2728 
2729     /**
2730      * Returns {@code true} if the orientation of task snapshot is compatible with this activity.
2731      */
isSnapshotOrientationCompatible(@onNull TaskSnapshot snapshot)2732     boolean isSnapshotOrientationCompatible(@NonNull TaskSnapshot snapshot) {
2733         final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation(this);
2734         final int currentRotation = task.getWindowConfiguration().getRotation();
2735         final int targetRotation = rotation != ROTATION_UNDEFINED
2736                 // The display may rotate according to the orientation of this activity.
2737                 ? rotation
2738                 // The activity won't change display orientation.
2739                 : currentRotation;
2740         if (snapshot.getRotation() != targetRotation) {
2741             return false;
2742         }
2743         final Rect taskBounds = task.getBounds();
2744         int w = taskBounds.width();
2745         int h = taskBounds.height();
2746         final Point taskSize = snapshot.getTaskSize();
2747         if ((Math.abs(currentRotation - targetRotation) % 2) == 1) {
2748             // Flip the size if the activity will show in 90 degree difference.
2749             final int t = w;
2750             w = h;
2751             h = t;
2752         }
2753         // Task size might be changed with the same rotation such as on a foldable device.
2754         return Math.abs(((float) taskSize.x / Math.max(taskSize.y, 1))
2755                 - ((float) w / Math.max(h, 1))) <= 0.01f;
2756     }
2757 
2758     /**
2759      * See {@link SplashScreen#setOnExitAnimationListener}.
2760      */
setCustomizeSplashScreenExitAnimation(boolean enable)2761     void setCustomizeSplashScreenExitAnimation(boolean enable) {
2762         if (mHandleExitSplashScreen == enable) {
2763             return;
2764         }
2765         mHandleExitSplashScreen = enable;
2766     }
2767 
2768     private final Runnable mTransferSplashScreenTimeoutRunnable = new Runnable() {
2769         @Override
2770         public void run() {
2771             synchronized (mAtmService.mGlobalLock) {
2772                 Slog.w(TAG, "Activity transferring splash screen timeout for "
2773                         + ActivityRecord.this + " state " + mTransferringSplashScreenState);
2774                 if (isTransferringSplashScreen()) {
2775                     mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
2776                     removeStartingWindow();
2777                 }
2778             }
2779         }
2780     };
2781 
scheduleTransferSplashScreenTimeout()2782     private void scheduleTransferSplashScreenTimeout() {
2783         mAtmService.mH.postDelayed(mTransferSplashScreenTimeoutRunnable,
2784                 TRANSFER_SPLASH_SCREEN_TIMEOUT);
2785     }
2786 
removeTransferSplashScreenTimeout()2787     private void removeTransferSplashScreenTimeout() {
2788         mAtmService.mH.removeCallbacks(mTransferSplashScreenTimeoutRunnable);
2789     }
2790 
transferSplashScreenIfNeeded()2791     private boolean transferSplashScreenIfNeeded() {
2792         if (finishing || !mHandleExitSplashScreen || mStartingSurface == null
2793                 || mStartingWindow == null
2794                 || mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH
2795                 // skip copy splash screen to client if it was resized
2796                 || (mStartingData != null && mStartingData.mResizedFromTransfer)) {
2797             return false;
2798         }
2799         if (isTransferringSplashScreen()) {
2800             return true;
2801         }
2802         // Only do transfer after transaction has done when starting window exist.
2803         if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommit) {
2804             mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_COPY_TO_CLIENT;
2805             return true;
2806         }
2807         requestCopySplashScreen();
2808         return isTransferringSplashScreen();
2809     }
2810 
isTransferringSplashScreen()2811     private boolean isTransferringSplashScreen() {
2812         return mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_ATTACH_TO_CLIENT
2813                 || mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_COPYING;
2814     }
2815 
requestCopySplashScreen()2816     private void requestCopySplashScreen() {
2817         mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_COPYING;
2818         if (mStartingSurface == null || !mAtmService.mTaskOrganizerController.copySplashScreenView(
2819                 getTask(), mStartingSurface.mTaskOrganizer)) {
2820             mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
2821             removeStartingWindow();
2822         }
2823         scheduleTransferSplashScreenTimeout();
2824     }
2825 
2826     /**
2827      * Receive the splash screen data from shell, sending to client.
2828      * @param parcelable The data to reconstruct the splash screen view, null mean unable to copy.
2829      */
onCopySplashScreenFinish(@ullable SplashScreenViewParcelable parcelable)2830     void onCopySplashScreenFinish(@Nullable SplashScreenViewParcelable parcelable) {
2831         removeTransferSplashScreenTimeout();
2832         final SurfaceControl windowAnimationLeash = (parcelable == null
2833                 || mTransferringSplashScreenState != TRANSFER_SPLASH_SCREEN_COPYING
2834                 || mStartingWindow == null || mStartingWindow.mRemoved
2835                 || finishing) ? null
2836                 : TaskOrganizerController.applyStartingWindowAnimation(mStartingWindow);
2837         if (windowAnimationLeash == null) {
2838             // Unable to copy from shell, maybe it's not a splash screen, or something went wrong.
2839             // Either way, abort and reset the sequence.
2840             if (parcelable != null) {
2841                 parcelable.clearIfNeeded();
2842             }
2843             mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
2844             removeStartingWindow();
2845             return;
2846         }
2847         try {
2848             mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_ATTACH_TO_CLIENT;
2849             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
2850                     TransferSplashScreenViewStateItem.obtain(token, parcelable,
2851                             windowAnimationLeash));
2852             scheduleTransferSplashScreenTimeout();
2853         } catch (Exception e) {
2854             Slog.w(TAG, "onCopySplashScreenComplete fail: " + this);
2855             mStartingWindow.cancelAnimation();
2856             parcelable.clearIfNeeded();
2857             mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
2858         }
2859     }
2860 
onSplashScreenAttachComplete()2861     private void onSplashScreenAttachComplete() {
2862         removeTransferSplashScreenTimeout();
2863         // Client has draw the splash screen, so we can remove the starting window.
2864         if (mStartingWindow != null) {
2865             mStartingWindow.cancelAnimation();
2866             mStartingWindow.hide(false, false);
2867         }
2868         // no matter what, remove the starting window.
2869         mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
2870         removeStartingWindowAnimation(false /* prepareAnimation */);
2871     }
2872 
2873     /**
2874      * Notify the shell ({@link com.android.wm.shell.ShellTaskOrganizer} it should clean up any
2875      * remaining reference to this {@link ActivityRecord}'s splash screen.
2876      * @see com.android.wm.shell.ShellTaskOrganizer#onAppSplashScreenViewRemoved(int)
2877      * @see SplashScreenView#remove()
2878      */
cleanUpSplashScreen()2879     void cleanUpSplashScreen() {
2880         // We only clean up the splash screen if we were supposed to handle it. If it was
2881         // transferred to another activity, the next one will handle the clean up.
2882         if (mHandleExitSplashScreen && !startingMoved
2883                 && (mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH
2884                 || mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_IDLE)) {
2885             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Cleaning splash screen token=%s", this);
2886             mAtmService.mTaskOrganizerController.onAppSplashScreenViewRemoved(getTask(),
2887                     mStartingSurface != null ? mStartingSurface.mTaskOrganizer : null);
2888         }
2889     }
2890 
isStartingWindowDisplayed()2891     boolean isStartingWindowDisplayed() {
2892         final StartingData data = mStartingData != null ? mStartingData : task != null
2893                 ? task.mSharedStartingData : null;
2894         return data != null && data.mIsDisplayed;
2895     }
2896 
2897     /** Called when the starting window is added to this activity. */
attachStartingWindow(@onNull WindowState startingWindow)2898     void attachStartingWindow(@NonNull WindowState startingWindow) {
2899         startingWindow.mStartingData = mStartingData;
2900         mStartingWindow = startingWindow;
2901         if (mStartingData != null) {
2902             if (mStartingData.mAssociatedTask != null) {
2903                 // The snapshot type may have called associateStartingDataWithTask().
2904                 attachStartingSurfaceToAssociatedTask();
2905             } else if (isEmbedded()) {
2906                 associateStartingWindowWithTaskIfNeeded();
2907             }
2908             if (mTransitionController.isCollecting()) {
2909                 mStartingData.mTransitionId = mTransitionController.getCollectingTransitionId();
2910             }
2911         }
2912     }
2913 
2914     /** Makes starting window always fill the associated task. */
attachStartingSurfaceToAssociatedTask()2915     private void attachStartingSurfaceToAssociatedTask() {
2916         if (mSyncState == SYNC_STATE_NONE && isEmbedded()) {
2917             // Collect this activity since it's starting window will reparent to task. To ensure
2918             // any starting window's transaction will occur in order.
2919             mTransitionController.collect(this);
2920         }
2921         // Associate the configuration of starting window with the task.
2922         overrideConfigurationPropagation(mStartingWindow, mStartingData.mAssociatedTask);
2923         getSyncTransaction().reparent(mStartingWindow.mSurfaceControl,
2924                 mStartingData.mAssociatedTask.mSurfaceControl);
2925     }
2926 
2927     /** Called when the starting window is not added yet but its data is known to fill the task. */
associateStartingDataWithTask()2928     private void associateStartingDataWithTask() {
2929         mStartingData.mAssociatedTask = task;
2930         task.mSharedStartingData = mStartingData;
2931     }
2932 
2933     /** Associates and attaches an added starting window to the current task. */
associateStartingWindowWithTaskIfNeeded()2934     void associateStartingWindowWithTaskIfNeeded() {
2935         if (mStartingWindow == null || mStartingData == null
2936                 || mStartingData.mAssociatedTask != null) {
2937             return;
2938         }
2939         associateStartingDataWithTask();
2940         attachStartingSurfaceToAssociatedTask();
2941     }
2942 
removeStartingWindow()2943     void removeStartingWindow() {
2944         boolean prevEligibleForLetterboxEducation = isEligibleForLetterboxEducation();
2945 
2946         if (transferSplashScreenIfNeeded()) {
2947             return;
2948         }
2949         removeStartingWindowAnimation(true /* prepareAnimation */);
2950 
2951         final Task task = getTask();
2952         if (prevEligibleForLetterboxEducation != isEligibleForLetterboxEducation()
2953                 && task != null) {
2954             // Trigger TaskInfoChanged to update the letterbox education.
2955             task.dispatchTaskInfoChangedIfNeeded(true /* force */);
2956         }
2957     }
2958 
2959     @Override
waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit)2960     void waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit) {
2961         super.waitForSyncTransactionCommit(wcAwaitingCommit);
2962         if (mStartingData != null) {
2963             mStartingData.mWaitForSyncTransactionCommit = true;
2964         }
2965     }
2966 
2967     @Override
onSyncTransactionCommitted(SurfaceControl.Transaction t)2968     void onSyncTransactionCommitted(SurfaceControl.Transaction t) {
2969         super.onSyncTransactionCommitted(t);
2970         if (mStartingData == null) {
2971             return;
2972         }
2973         final StartingData lastData = mStartingData;
2974         lastData.mWaitForSyncTransactionCommit = false;
2975         if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_REMOVE_DIRECTLY) {
2976             removeStartingWindowAnimation(lastData.mPrepareRemoveAnimation);
2977         } else if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_COPY_TO_CLIENT) {
2978             removeStartingWindow();
2979         }
2980     }
2981 
removeStartingWindowAnimation(boolean prepareAnimation)2982     void removeStartingWindowAnimation(boolean prepareAnimation) {
2983         mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
2984         if (mStartingData != null && task != null) {
2985             task.mSharedStartingData = null;
2986         }
2987         if (mStartingWindow == null) {
2988             if (mStartingData != null) {
2989                 // Starting window has not been added yet, but it is scheduled to be added.
2990                 // Go ahead and cancel the request.
2991                 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Clearing startingData for token=%s", this);
2992                 mStartingData = null;
2993                 // Clean surface up since we don't want the window to be added back, so we don't
2994                 // need to keep the surface to remove it.
2995                 mStartingSurface = null;
2996             }
2997             return;
2998         }
2999 
3000         final StartingSurfaceController.StartingSurface surface;
3001         final boolean animate;
3002         final boolean hasImeSurface;
3003         if (mStartingData != null) {
3004             if (mStartingData.mWaitForSyncTransactionCommit
3005                     || mTransitionController.isCollecting(this)) {
3006                 mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_REMOVE_DIRECTLY;
3007                 mStartingData.mPrepareRemoveAnimation = prepareAnimation;
3008                 return;
3009             }
3010             animate = prepareAnimation && mStartingData.needRevealAnimation()
3011                     && mStartingWindow.isVisibleByPolicy();
3012             hasImeSurface = mStartingData.hasImeSurface();
3013             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s"
3014                             + " animate=%b Callers=%s", this, mStartingWindow, animate,
3015                     Debug.getCallers(5));
3016             surface = mStartingSurface;
3017             mStartingData = null;
3018             mStartingSurface = null;
3019             mStartingWindow = null;
3020             mTransitionChangeFlags &= ~FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
3021             if (surface == null) {
3022                 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "startingWindow was set but "
3023                         + "startingSurface==null, couldn't remove");
3024                 return;
3025             }
3026         } else {
3027             ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
3028                     "Tried to remove starting window but startingWindow was null: %s",
3029                     this);
3030             return;
3031         }
3032         surface.remove(animate, hasImeSurface);
3033     }
3034 
3035     /**
3036      * Reparents this activity into {@param newTaskFrag} at the provided {@param position}. The
3037      * caller should ensure that the {@param newTaskFrag} is not already the parent of this
3038      * activity.
3039      */
reparent(TaskFragment newTaskFrag, int position, String reason)3040     void reparent(TaskFragment newTaskFrag, int position, String reason) {
3041         if (getParent() == null) {
3042             Slog.w(TAG, "reparent: Attempted to reparent non-existing app token: " + token);
3043             return;
3044         }
3045         final TaskFragment prevTaskFrag = getTaskFragment();
3046         if (prevTaskFrag == newTaskFrag) {
3047             throw new IllegalArgumentException(reason + ": task fragment =" + newTaskFrag
3048                     + " is already the parent of r=" + this);
3049         }
3050 
3051         ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s"
3052                 + " to new task fragment in task=%d at %d", this, task.mTaskId, position);
3053         reparent(newTaskFrag, position);
3054     }
3055 
isHomeIntent(Intent intent)3056     static boolean isHomeIntent(Intent intent) {
3057         return ACTION_MAIN.equals(intent.getAction())
3058                 && (intent.hasCategory(CATEGORY_HOME)
3059                 || intent.hasCategory(CATEGORY_SECONDARY_HOME))
3060                 && intent.getCategories().size() == 1
3061                 && intent.getData() == null
3062                 && intent.getType() == null;
3063     }
3064 
isMainIntent(Intent intent)3065     static boolean isMainIntent(Intent intent) {
3066         return ACTION_MAIN.equals(intent.getAction())
3067                 && intent.hasCategory(CATEGORY_LAUNCHER)
3068                 && intent.getCategories().size() == 1
3069                 && intent.getData() == null
3070                 && intent.getType() == null;
3071     }
3072 
3073     @VisibleForTesting
canLaunchHomeActivity(int uid, ActivityRecord sourceRecord)3074     boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
3075         if (uid == SYSTEM_UID || uid == 0) {
3076             // System process can launch home activity.
3077             return true;
3078         }
3079         // Allow the recents component to launch the home activity.
3080         final RecentTasks recentTasks = mTaskSupervisor.mService.getRecentTasks();
3081         if (recentTasks != null && recentTasks.isCallerRecents(uid)) {
3082             return true;
3083         }
3084         // Resolver or system chooser activity can launch home activity.
3085         return sourceRecord != null && sourceRecord.isResolverOrDelegateActivity();
3086     }
3087 
3088     /**
3089      * @return whether the given package name can launch an assist activity.
3090      */
canLaunchAssistActivity(String packageName)3091     private boolean canLaunchAssistActivity(String packageName) {
3092         final ComponentName assistComponent =
3093                 mAtmService.mActiveVoiceInteractionServiceComponent;
3094         if (assistComponent != null) {
3095             return assistComponent.getPackageName().equals(packageName);
3096         }
3097         return false;
3098     }
3099 
setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent, ActivityOptions options, ActivityRecord sourceRecord)3100     private void setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent,
3101             ActivityOptions options, ActivityRecord sourceRecord) {
3102         int activityType = ACTIVITY_TYPE_UNDEFINED;
3103         if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord))
3104                 && isHomeIntent(intent) && !isResolverOrDelegateActivity()) {
3105             // This sure looks like a home activity!
3106             activityType = ACTIVITY_TYPE_HOME;
3107 
3108             if (info.resizeMode == RESIZE_MODE_FORCE_RESIZEABLE
3109                     || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
3110                 // We only allow home activities to be resizeable if they explicitly requested it.
3111                 info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
3112             }
3113         } else if (mAtmService.getRecentTasks().isRecentsComponent(mActivityComponent,
3114                 info.applicationInfo.uid)) {
3115             activityType = ACTIVITY_TYPE_RECENTS;
3116         } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT
3117                 && canLaunchAssistActivity(launchedFromPackage)) {
3118             activityType = ACTIVITY_TYPE_ASSISTANT;
3119         } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_DREAM
3120                 && mAtmService.canLaunchDreamActivity(launchedFromPackage)
3121                 && DreamActivity.class.getName() == info.name) {
3122             activityType = ACTIVITY_TYPE_DREAM;
3123         }
3124         setActivityType(activityType);
3125     }
3126 
setTaskToAffiliateWith(Task taskToAffiliateWith)3127     void setTaskToAffiliateWith(Task taskToAffiliateWith) {
3128         if (launchMode != LAUNCH_SINGLE_INSTANCE && launchMode != LAUNCH_SINGLE_TASK) {
3129             task.setTaskToAffiliateWith(taskToAffiliateWith);
3130         }
3131     }
3132 
3133     /** @return Root task of this activity, null if there is no task. */
3134     @Nullable
getRootTask()3135     Task getRootTask() {
3136         return task != null ? task.getRootTask() : null;
3137     }
3138 
getRootTaskId()3139     int getRootTaskId() {
3140         return task != null ? task.getRootTaskId() : INVALID_TASK_ID;
3141     }
3142 
3143     /** @return the first organized parent task. */
3144     @Nullable
getOrganizedTask()3145     Task getOrganizedTask() {
3146         return task != null ? task.getOrganizedTask() : null;
3147     }
3148 
3149     /** Returns the organized parent {@link TaskFragment}. */
3150     @Nullable
getOrganizedTaskFragment()3151     TaskFragment getOrganizedTaskFragment() {
3152         final TaskFragment parent = getTaskFragment();
3153         return parent != null ? parent.getOrganizedTaskFragment() : null;
3154     }
3155 
3156     @Override
isEmbedded()3157     boolean isEmbedded() {
3158         final TaskFragment parent = getTaskFragment();
3159         return parent != null && parent.isEmbedded();
3160     }
3161 
3162     /**
3163      * Returns {@code true} if the system is allowed to share this activity's state with the host
3164      * app when this activity is embedded in untrusted mode.
3165      */
isUntrustedEmbeddingStateSharingAllowed()3166     boolean isUntrustedEmbeddingStateSharingAllowed() {
3167         if (!Flags.untrustedEmbeddingStateSharing()) {
3168             return false;
3169         }
3170         return mAllowUntrustedEmbeddingStateSharing;
3171     }
3172 
getAllowUntrustedEmbeddingStateSharingProperty()3173     private boolean getAllowUntrustedEmbeddingStateSharingProperty() {
3174         if (!Flags.untrustedEmbeddingStateSharing()) {
3175             return false;
3176         }
3177         try {
3178             return mAtmService.mContext.getPackageManager()
3179                     .getProperty(PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING,
3180                             mActivityComponent)
3181                     .getBoolean();
3182         } catch (PackageManager.NameNotFoundException e) {
3183             // No such property name.
3184             return false;
3185         }
3186     }
3187 
3188     /**
3189      * This is different from {@link #isEmbedded()}.
3190      * {@link #isEmbedded()} is {@code true} when any of the parent {@link TaskFragment} is created
3191      * by a {@link android.window.TaskFragmentOrganizer}, while this method is {@code true} when
3192      * the parent {@link TaskFragment} is embedded and has bounds override that does not fill the
3193      * leaf {@link Task}.
3194      */
isEmbeddedInHostContainer()3195     boolean isEmbeddedInHostContainer() {
3196         final TaskFragment taskFragment = getOrganizedTaskFragment();
3197         return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride();
3198     }
3199 
3200     @NonNull
getActivityWindowInfo()3201     ActivityWindowInfo getActivityWindowInfo() {
3202         if (!Flags.activityWindowInfoFlag() || !isAttached()) {
3203             return mTmpActivityWindowInfo;
3204         }
3205         if (isFixedRotationTransforming()) {
3206             // Fixed rotation only applied to fullscreen activity, thus using the activity bounds
3207             // for Task/TaskFragment so that it is "pre-rotated" and in sync with the Configuration
3208             // update.
3209             final Rect bounds = getBounds();
3210             mTmpActivityWindowInfo.set(false /* isEmbedded */, bounds, bounds);
3211         } else {
3212             mTmpActivityWindowInfo.set(
3213                     isEmbeddedInHostContainer(),
3214                     getTask().getBounds(),
3215                     getTaskFragment().getBounds());
3216         }
3217         return mTmpActivityWindowInfo;
3218     }
3219 
3220     @Override
3221     @Nullable
getDisplayArea()3222     TaskDisplayArea getDisplayArea() {
3223         return (TaskDisplayArea) super.getDisplayArea();
3224     }
3225 
3226     @Override
providesOrientation()3227     boolean providesOrientation() {
3228         return mStyleFillsParent || mOccludesParent;
3229     }
3230 
3231     @Override
fillsParent()3232     boolean fillsParent() {
3233         return occludesParent(true /* includingFinishing */);
3234     }
3235 
3236     /** Returns true if this activity is not finishing, is opaque and fills the entire space of
3237      * this task. */
occludesParent()3238     boolean occludesParent() {
3239         return occludesParent(false /* includingFinishing */);
3240     }
3241 
3242     @VisibleForTesting
occludesParent(boolean includingFinishing)3243     boolean occludesParent(boolean includingFinishing) {
3244         if (!includingFinishing && finishing) {
3245             return false;
3246         }
3247         return mOccludesParent || showWallpaper();
3248     }
3249 
setOccludesParent(boolean occludesParent)3250     boolean setOccludesParent(boolean occludesParent) {
3251         final boolean changed = occludesParent != mOccludesParent;
3252         mOccludesParent = occludesParent;
3253         setMainWindowOpaque(occludesParent);
3254 
3255         if (changed && task != null) {
3256             if (!occludesParent) {
3257                 getRootTask().convertActivityToTranslucent(this);
3258             } else {
3259                 getRootTask().convertActivityFromTranslucent(this);
3260             }
3261         }
3262         // Always ensure visibility if this activity doesn't occlude parent, so the
3263         // {@link #returningOptions} of the activity under this one can be applied in
3264         // {@link #handleAlreadyVisible()}.
3265         if (changed || !occludesParent) {
3266             mRootWindowContainer.ensureActivitiesVisible();
3267         }
3268         return changed;
3269     }
3270 
setMainWindowOpaque(boolean isOpaque)3271     void setMainWindowOpaque(boolean isOpaque) {
3272         final WindowState win = findMainWindow();
3273         if (win == null) {
3274             return;
3275         }
3276         isOpaque = isOpaque & !PixelFormat.formatHasAlpha(win.getAttrs().format);
3277         win.mWinAnimator.setOpaqueLocked(isOpaque);
3278     }
3279 
takeFromHistory()3280     void takeFromHistory() {
3281         if (inHistory) {
3282             inHistory = false;
3283             if (task != null && !finishing) {
3284                 task = null;
3285             }
3286             abortAndClearOptionsAnimation();
3287         }
3288     }
3289 
isInHistory()3290     boolean isInHistory() {
3291         return inHistory;
3292     }
3293 
isInRootTaskLocked()3294     boolean isInRootTaskLocked() {
3295         final Task rootTask = getRootTask();
3296         return rootTask != null && rootTask.isInTask(this) != null;
3297     }
3298 
isPersistable()3299     boolean isPersistable() {
3300         return (info.persistableMode == PERSIST_ROOT_ONLY ||
3301                 info.persistableMode == PERSIST_ACROSS_REBOOTS) &&
3302                 (intent == null || (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
3303     }
3304 
3305     @Override
isFocusable()3306     boolean isFocusable() {
3307         return super.isFocusable() && (canReceiveKeys() || isAlwaysFocusable());
3308     }
3309 
canReceiveKeys()3310     boolean canReceiveKeys() {
3311         return getWindowConfiguration().canReceiveKeys() && !mWaitForEnteringPinnedMode;
3312     }
3313 
isResizeable()3314     boolean isResizeable() {
3315         return isResizeable(/* checkPictureInPictureSupport */ true);
3316     }
3317 
isResizeable(boolean checkPictureInPictureSupport)3318     boolean isResizeable(boolean checkPictureInPictureSupport) {
3319         return mAtmService.mForceResizableActivities
3320                 || ActivityInfo.isResizeableMode(info.resizeMode)
3321                 || (info.supportsPictureInPicture() && checkPictureInPictureSupport)
3322                 // If the activity can be embedded, it should inherit the bounds of task fragment.
3323                 || isEmbedded();
3324     }
3325 
3326     /** @return whether this activity is non-resizeable but is forced to be resizable. */
canForceResizeNonResizable(int windowingMode)3327     boolean canForceResizeNonResizable(int windowingMode) {
3328         if (windowingMode == WINDOWING_MODE_PINNED && info.supportsPictureInPicture()) {
3329             return false;
3330         }
3331         // Activity should be resizable if the task is.
3332         final boolean supportsMultiWindow = task != null
3333                 ? task.supportsMultiWindow() || supportsMultiWindow()
3334                 : supportsMultiWindow();
3335         if (WindowConfiguration.inMultiWindowMode(windowingMode) && supportsMultiWindow
3336                 && !mAtmService.mForceResizableActivities) {
3337             // The non resizable app will be letterboxed instead of being forced resizable.
3338             return false;
3339         }
3340         return info.resizeMode != RESIZE_MODE_RESIZEABLE
3341                 && info.resizeMode != RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
3342     }
3343 
3344     /**
3345      * @return whether this activity supports PiP multi-window and can be put in the root pinned
3346      * task.
3347      */
supportsPictureInPicture()3348     boolean supportsPictureInPicture() {
3349         return mAtmService.mSupportsPictureInPicture && isActivityTypeStandardOrUndefined()
3350                 && info.supportsPictureInPicture();
3351     }
3352 
supportsFreeform()3353     boolean supportsFreeform() {
3354         return supportsFreeformInDisplayArea(getDisplayArea());
3355     }
3356 
3357     /**
3358      * @return whether this activity supports freeform multi-window and can be put in the freeform
3359      *         windowing mode if it is in the given {@link TaskDisplayArea}.
3360      */
supportsFreeformInDisplayArea(@ullable TaskDisplayArea tda)3361     boolean supportsFreeformInDisplayArea(@Nullable TaskDisplayArea tda) {
3362         return mAtmService.mSupportsFreeformWindowManagement
3363                 && supportsMultiWindowInDisplayArea(tda);
3364     }
3365 
supportsMultiWindow()3366     boolean supportsMultiWindow() {
3367         return supportsMultiWindowInDisplayArea(getDisplayArea());
3368     }
3369 
3370     /**
3371      * @return whether this activity supports multi-window if it is in the given
3372      *         {@link TaskDisplayArea}.
3373      */
supportsMultiWindowInDisplayArea(@ullable TaskDisplayArea tda)3374     boolean supportsMultiWindowInDisplayArea(@Nullable TaskDisplayArea tda) {
3375         if (isActivityTypeHome()) {
3376             return false;
3377         }
3378         if (!mAtmService.mSupportsMultiWindow) {
3379             return false;
3380         }
3381         if (tda == null) {
3382             return false;
3383         }
3384 
3385         if (!isResizeable() && !tda.supportsNonResizableMultiWindow()) {
3386             // Not support non-resizable in multi window.
3387             return false;
3388         }
3389 
3390         final ActivityInfo.WindowLayout windowLayout = info.windowLayout;
3391         return windowLayout == null
3392                 || tda.supportsActivityMinWidthHeightMultiWindow(windowLayout.minWidth,
3393                 windowLayout.minHeight, info);
3394     }
3395 
3396     /**
3397      * Check whether this activity can be launched on the specified display.
3398      *
3399      * @param displayId Target display id.
3400      * @return {@code true} if either it is the default display or this activity can be put on a
3401      *         secondary screen.
3402      */
canBeLaunchedOnDisplay(int displayId)3403     boolean canBeLaunchedOnDisplay(int displayId) {
3404         return mAtmService.mTaskSupervisor.canPlaceEntityOnDisplay(displayId, launchedFromPid,
3405                 launchedFromUid, info);
3406     }
3407 
3408     /**
3409      * @param beforeStopping Whether this check is for an auto-enter-pip operation, that is to say
3410      *         the activity has requested to enter PiP when it would otherwise be stopped.
3411      *
3412      * @return whether this activity is currently allowed to enter PIP.
3413      */
checkEnterPictureInPictureState(String caller, boolean beforeStopping)3414     boolean checkEnterPictureInPictureState(String caller, boolean beforeStopping) {
3415         if (!supportsPictureInPicture()) {
3416             return false;
3417         }
3418 
3419         // Check app-ops and see if PiP is supported for this package
3420         if (!checkEnterPictureInPictureAppOpsState()) {
3421             return false;
3422         }
3423 
3424         // Check to see if we are in VR mode, and disallow PiP if so
3425         if (mAtmService.shouldDisableNonVrUiLocked()) {
3426             return false;
3427         }
3428 
3429         // Check to see if PiP is supported for the display this container is on.
3430         if (mDisplayContent != null && !mDisplayContent.mDwpcHelper.isEnteringPipAllowed(
3431                 getUid())) {
3432             Slog.w(TAG, "Display " + mDisplayContent.getDisplayId()
3433                     + " doesn't support enter picture-in-picture mode. caller = " + caller);
3434             return false;
3435         }
3436 
3437         boolean isCurrentAppLocked =
3438                 mAtmService.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
3439         final TaskDisplayArea taskDisplayArea = getDisplayArea();
3440         boolean hasRootPinnedTask = taskDisplayArea != null && taskDisplayArea.hasPinnedTask();
3441         // Don't return early if !isNotLocked, since we want to throw an exception if the activity
3442         // is in an incorrect state
3443         boolean isNotLockedOrOnKeyguard = !isKeyguardLocked() && !isCurrentAppLocked;
3444 
3445         // We don't allow auto-PiP when something else is already pipped.
3446         if (beforeStopping && hasRootPinnedTask) {
3447             return false;
3448         }
3449 
3450         switch (mState) {
3451             case RESUMED:
3452                 // When visible, allow entering PiP if the app is not locked.  If it is over the
3453                 // keyguard, then we will prompt to unlock in the caller before entering PiP.
3454                 return !isCurrentAppLocked &&
3455                         (supportsEnterPipOnTaskSwitch || !beforeStopping);
3456             case PAUSING:
3457             case PAUSED:
3458                 // When pausing, then only allow enter PiP as in the resume state, and in addition,
3459                 // require that there is not an existing PiP activity and that the current system
3460                 // state supports entering PiP
3461                 return isNotLockedOrOnKeyguard && !hasRootPinnedTask
3462                         && supportsEnterPipOnTaskSwitch;
3463             case STOPPING:
3464                 // When stopping in a valid state, then only allow enter PiP as in the pause state.
3465                 // Otherwise, fall through to throw an exception if the caller is trying to enter
3466                 // PiP in an invalid stopping state.
3467                 if (supportsEnterPipOnTaskSwitch) {
3468                     return isNotLockedOrOnKeyguard && !hasRootPinnedTask;
3469                 }
3470             default:
3471                 return false;
3472         }
3473     }
3474 
3475     /**
3476      * Sets if this {@link ActivityRecord} is in the process of closing or entering PIP.
3477      * {@link #mWillCloseOrEnterPip}}
3478      */
setWillCloseOrEnterPip(boolean willCloseOrEnterPip)3479     void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
3480         mWillCloseOrEnterPip = willCloseOrEnterPip;
3481     }
3482 
willCloseOrEnterPip()3483     boolean willCloseOrEnterPip() {
3484         return mWillCloseOrEnterPip;
3485     }
3486 
3487     /**
3488      * @return Whether AppOps allows this package to enter picture-in-picture.
3489      */
checkEnterPictureInPictureAppOpsState()3490     boolean checkEnterPictureInPictureAppOpsState() {
3491         return mAtmService.getAppOpsManager().checkOpNoThrow(
3492                 OP_PICTURE_IN_PICTURE, info.applicationInfo.uid, packageName) == MODE_ALLOWED;
3493     }
3494 
isAlwaysFocusable()3495     private boolean isAlwaysFocusable() {
3496         return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
3497     }
3498 
windowsAreFocusable()3499     boolean windowsAreFocusable() {
3500         return windowsAreFocusable(false /* fromUserTouch */);
3501     }
3502 
3503     // TODO: Does this really need to be different from isAlwaysFocusable()? For the activity side
3504     // focusable means resumeable. I guess with that in mind maybe we should rename the other
3505     // method to isResumeable() or something like that.
windowsAreFocusable(boolean fromUserTouch)3506     boolean windowsAreFocusable(boolean fromUserTouch) {
3507         if (!fromUserTouch && mTargetSdk < Build.VERSION_CODES.Q) {
3508             final int pid = getPid();
3509             final ActivityRecord topFocusedAppOfMyProcess =
3510                     mWmService.mRoot.mTopFocusedAppByProcess.get(pid);
3511             if (topFocusedAppOfMyProcess != null && topFocusedAppOfMyProcess != this) {
3512                 // For the apps below Q, there can be only one app which has the focused window per
3513                 // process, because legacy apps may not be ready for a multi-focus system.
3514                 return false;
3515 
3516             }
3517         }
3518         // Check isAttached() because the method may be called when removing this activity from
3519         // display, and WindowContainer#compareTo will throw exception if it doesn't have a parent
3520         // when updating focused window from DisplayContent#findFocusedWindow.
3521         return (canReceiveKeys() || isAlwaysFocusable()) && isAttached();
3522     }
3523 
3524     /**
3525      * Move activity with its root task to front and make the root task focused.
3526      * @param reason the reason to move to top
3527      * @return {@code true} if the root task is focusable and has been moved to top or the activity
3528      *         is not yet resumed while the root task is already on top, {@code false} otherwise.
3529      */
moveFocusableActivityToTop(String reason)3530     boolean moveFocusableActivityToTop(String reason) {
3531         if (!isFocusable()) {
3532             ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: unfocusable "
3533                     + "activity=%s", this);
3534             return false;
3535         }
3536 
3537         final Task rootTask = getRootTask();
3538         if (rootTask == null) {
3539             Slog.w(TAG, "moveFocusableActivityToTop: invalid root task: activity="
3540                     + this + " task=" + task);
3541             return false;
3542         }
3543 
3544         // If this activity already positions on the top focused task, moving the task to front
3545         // is not needed. But we still need to ensure this activity is focused because the
3546         // current focused activity could be another activity in the same Task if activities are
3547         // displayed on adjacent TaskFragments.
3548         final ActivityRecord currentFocusedApp = mDisplayContent.mFocusedApp;
3549         final int topFocusedDisplayId = mRootWindowContainer.getTopFocusedDisplayContent() != null
3550                 ? mRootWindowContainer.getTopFocusedDisplayContent().getDisplayId()
3551                 : INVALID_DISPLAY;
3552         if (currentFocusedApp != null && currentFocusedApp.task == task
3553                 && topFocusedDisplayId == mDisplayContent.getDisplayId()) {
3554             final Task topFocusableTask = mDisplayContent.getTask(
3555                     (t) -> t.isLeafTask() && t.isFocusable() && !t.inPinnedWindowingMode(),
3556                     true /*  traverseTopToBottom */);
3557             if (task == topFocusableTask) {
3558                 if (currentFocusedApp == this) {
3559                     ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: already on top "
3560                             + "and focused, activity=%s", this);
3561                 } else {
3562                     ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: set focused, "
3563                             + "activity=%s", this);
3564                     mDisplayContent.setFocusedApp(this);
3565                     mAtmService.mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
3566                             true /* updateInputWindows */);
3567                 }
3568                 return !isState(RESUMED);
3569             }
3570         }
3571 
3572         ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: activity=%s", this);
3573 
3574         rootTask.moveToFront(reason, task);
3575         // Report top activity change to tracking services and WM
3576         if (mState == RESUMED && mRootWindowContainer.getTopResumedActivity() == this) {
3577             mAtmService.setLastResumedActivityUncheckLocked(this, reason);
3578         }
3579         return true;
3580     }
3581 
finishIfSubActivity(ActivityRecord parent, String otherResultWho, int otherRequestCode)3582     void finishIfSubActivity(ActivityRecord parent, String otherResultWho, int otherRequestCode) {
3583         if (resultTo != parent
3584                 || requestCode != otherRequestCode
3585                 || !Objects.equals(resultWho, otherResultWho)) return;
3586 
3587         finishIfPossible("request-sub", false /* oomAdj */);
3588     }
3589 
3590     /** Finish all activities in the task with the same affinity as this one. */
finishIfSameAffinity(ActivityRecord r)3591     boolean finishIfSameAffinity(ActivityRecord r) {
3592         // End search once we get to the activity that doesn't have the same affinity.
3593         if (!Objects.equals(r.taskAffinity, taskAffinity)) return true;
3594 
3595         r.finishIfPossible("request-affinity", true /* oomAdj */);
3596         return false;
3597     }
3598 
3599     /**
3600      * Sets the result for activity that started this one, clears the references to activities
3601      * started for result from this one, and clears new intents.
3602      */
finishActivityResults(int resultCode, Intent resultData, NeededUriGrants resultGrants)3603     private void finishActivityResults(int resultCode, Intent resultData,
3604             NeededUriGrants resultGrants) {
3605         // Send the result if needed
3606         if (resultTo != null) {
3607             if (DEBUG_RESULTS) {
3608                 Slog.v(TAG_RESULTS, "Adding result to " + resultTo
3609                         + " who=" + resultWho + " req=" + requestCode
3610                         + " res=" + resultCode + " data=" + resultData);
3611             }
3612             if (resultTo.mUserId != mUserId) {
3613                 if (resultData != null) {
3614                     resultData.prepareToLeaveUser(mUserId);
3615                 }
3616             }
3617             if (info.applicationInfo.uid > 0) {
3618                 mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(resultGrants,
3619                         resultTo.getUriPermissionsLocked());
3620             }
3621             IBinder callerToken = new Binder();
3622             if (android.security.Flags.contentUriPermissionApis()) {
3623                 try {
3624                     resultTo.computeCallerInfo(callerToken, resultData, this.getUid(),
3625                             mAtmService.getPackageManager().getNameForUid(this.getUid()),
3626                             /* isShareIdentityEnabled */ false);
3627                     // Result callers cannot share their identity via
3628                     // {@link ActivityOptions#setShareIdentityEnabled(boolean)} since
3629                     // {@link android.app.Activity#setResult} doesn't have a
3630                     // {@link android.os.Bundle}.
3631                 } catch (RemoteException e) {
3632                     throw new RuntimeException(e);
3633                 }
3634             }
3635             if (mForceSendResultForMediaProjection || resultTo.isState(RESUMED)) {
3636                 // Sending the result to the resultTo activity asynchronously to prevent the
3637                 // resultTo activity getting results before this Activity paused.
3638                 final ActivityRecord resultToActivity = resultTo;
3639                 mAtmService.mH.post(() -> {
3640                     synchronized (mAtmService.mGlobalLock) {
3641                         resultToActivity.sendResult(this.getUid(), resultWho, requestCode,
3642                                 resultCode, resultData, callerToken, resultGrants,
3643                                 mForceSendResultForMediaProjection);
3644                     }
3645                 });
3646             } else {
3647                 resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData,
3648                         callerToken);
3649             }
3650             resultTo = null;
3651         } else if (DEBUG_RESULTS) {
3652             Slog.v(TAG_RESULTS, "No result destination from " + this);
3653         }
3654 
3655         // Make sure this HistoryRecord is not holding on to other resources,
3656         // because clients have remote IPC references to this object so we
3657         // can't assume that will go away and want to avoid circular IPC refs.
3658         results = null;
3659         pendingResults = null;
3660         newIntents = null;
3661         setSavedState(null /* savedState */);
3662     }
3663 
3664     /** Activity finish request was not executed. */
3665     static final int FINISH_RESULT_CANCELLED = 0;
3666     /** Activity finish was requested, activity will be fully removed later. */
3667     static final int FINISH_RESULT_REQUESTED = 1;
3668     /** Activity finish was requested, activity was removed from history. */
3669     static final int FINISH_RESULT_REMOVED = 2;
3670 
3671     /** Definition of possible results for activity finish request. */
3672     @IntDef(prefix = { "FINISH_RESULT_" }, value = {
3673             FINISH_RESULT_CANCELLED,
3674             FINISH_RESULT_REQUESTED,
3675             FINISH_RESULT_REMOVED,
3676     })
3677     @interface FinishRequest {}
3678 
3679     /**
3680      * See {@link #finishIfPossible(int, Intent, NeededUriGrants, String, boolean)}
3681      */
finishIfPossible(String reason, boolean oomAdj)3682     @FinishRequest int finishIfPossible(String reason, boolean oomAdj) {
3683         return finishIfPossible(Activity.RESULT_CANCELED,
3684                 null /* resultData */, null /* resultGrants */, reason, oomAdj);
3685     }
3686 
3687     /**
3688      * Finish activity if possible. If activity was resumed - we must first pause it to make the
3689      * activity below resumed. Otherwise we will try to complete the request immediately by calling
3690      * {@link #completeFinishing(String)}.
3691      * @return One of {@link FinishRequest} values:
3692      * {@link #FINISH_RESULT_REMOVED} if this activity has been removed from the history list.
3693      * {@link #FINISH_RESULT_REQUESTED} if removal process was started, but it is still in the list
3694      * and will be removed from history later.
3695      * {@link #FINISH_RESULT_CANCELLED} if activity is already finishing or in invalid state and the
3696      * request to finish it was not ignored.
3697      */
finishIfPossible(int resultCode, Intent resultData, NeededUriGrants resultGrants, String reason, boolean oomAdj)3698     @FinishRequest int finishIfPossible(int resultCode, Intent resultData,
3699             NeededUriGrants resultGrants, String reason, boolean oomAdj) {
3700         ProtoLog.v(WM_DEBUG_STATES, "Finishing activity r=%s, result=%d, data=%s, "
3701                 + "reason=%s", this, resultCode, resultData, reason);
3702 
3703         if (finishing) {
3704             Slog.w(TAG, "Duplicate finish request for r=" + this);
3705             return FINISH_RESULT_CANCELLED;
3706         }
3707 
3708         if (!isInRootTaskLocked()) {
3709             Slog.w(TAG, "Finish request when not in root task for r=" + this);
3710             return FINISH_RESULT_CANCELLED;
3711         }
3712 
3713         final Task rootTask = getRootTask();
3714         final boolean mayAdjustTop = (isState(RESUMED) || rootTask.getTopResumedActivity() == null)
3715                 && rootTask.isFocusedRootTaskOnDisplay()
3716                 // Do not adjust focus task because the task will be reused to launch new activity.
3717                 && !task.isClearingToReuseTask();
3718         final boolean shouldAdjustGlobalFocus = mayAdjustTop
3719                 // It must be checked before {@link #makeFinishingLocked} is called, because a
3720                 // root task is not visible if it only contains finishing activities.
3721                 && mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask);
3722 
3723         mAtmService.deferWindowLayout();
3724         try {
3725             mTaskSupervisor.mNoHistoryActivities.remove(this);
3726             makeFinishingLocked();
3727             // Make a local reference to its task since this.task could be set to null once this
3728             // activity is destroyed and detached from task.
3729             final Task task = getTask();
3730             EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
3731                     task.mTaskId, shortComponentName, reason);
3732             ActivityRecord next = task.getActivityAbove(this);
3733             if (next != null) {
3734                 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
3735                     // If the caller asked that this activity (and all above it)
3736                     // be cleared when the task is reset, don't lose that information,
3737                     // but propagate it up to the next activity.
3738                     next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
3739                 }
3740             }
3741 
3742             pauseKeyDispatchingLocked();
3743 
3744             // We are finishing the top focused activity and its task has nothing to be focused so
3745             // the next focusable task should be focused.
3746             if (mayAdjustTop && task.topRunningActivity(true /* focusableOnly */)
3747                     == null) {
3748                 task.adjustFocusToNextFocusableTask("finish-top", false /* allowFocusSelf */,
3749                             shouldAdjustGlobalFocus);
3750             }
3751 
3752             finishActivityResults(resultCode, resultData, resultGrants);
3753 
3754             final boolean endTask = task.getTopNonFinishingActivity() == null
3755                     && !task.isClearingToReuseTask();
3756             final WindowContainer<?> trigger = endTask ? task : this;
3757             final Transition newTransition =
3758                     mTransitionController.requestCloseTransitionIfNeeded(trigger);
3759             if (newTransition != null) {
3760                 newTransition.collectClose(trigger);
3761             } else if (mTransitionController.isCollecting()) {
3762                 mTransitionController.getCollectingTransition().collectClose(trigger);
3763             }
3764             if (isState(RESUMED)) {
3765                 if (endTask) {
3766                     mAtmService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
3767                             task.getTaskInfo());
3768                 }
3769                 // Prepare app close transition, but don't execute just yet. It is possible that
3770                 // an activity that will be made resumed in place of this one will immediately
3771                 // launch another new activity. In this case current closing transition will be
3772                 // combined with open transition for the new activity.
3773                 if (DEBUG_VISIBILITY || DEBUG_TRANSITION) {
3774                     Slog.v(TAG_TRANSITION, "Prepare close transition: finishing " + this);
3775                 }
3776                 mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
3777 
3778                 // When finishing the activity preemptively take the snapshot before the app window
3779                 // is marked as hidden and any configuration changes take place
3780                 // Note that RecentsAnimation will handle task snapshot while switching apps with
3781                 // the best capture timing (e.g. IME window capture),
3782                 // No need additional task capture while task is controlled by RecentsAnimation.
3783                 if (!mTransitionController.isShellTransitionsEnabled()
3784                         && !task.isAnimatingByRecents()) {
3785                     final ArraySet<Task> tasks = Sets.newArraySet(task);
3786                     mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks);
3787                     mAtmService.mWindowManager.mTaskSnapshotController
3788                             .addSkipClosingAppSnapshotTasks(tasks);
3789                 }
3790 
3791                 // Tell window manager to prepare for this one to be removed.
3792                 setVisibility(false);
3793                 // Propagate the last IME visibility in the same task, so the IME can show
3794                 // automatically if the next activity has a focused editable view.
3795                 if (mLastImeShown && mTransitionController.isShellTransitionsEnabled()) {
3796                     final ActivityRecord nextRunning = task.topRunningActivity();
3797                     if (nextRunning != null) {
3798                         nextRunning.mLastImeShown = true;
3799                     }
3800                 }
3801 
3802                 if (getTaskFragment().getPausingActivity() == null) {
3803                     ProtoLog.v(WM_DEBUG_STATES, "Finish needs to pause: %s", this);
3804                     if (DEBUG_USER_LEAVING) {
3805                         Slog.v(TAG_USER_LEAVING, "finish() => pause with userLeaving=false");
3806                     }
3807                     getTaskFragment().startPausing(false /* userLeaving */, false /* uiSleeping */,
3808                             null /* resuming */, "finish");
3809                 }
3810 
3811                 if (endTask) {
3812                     mAtmService.getLockTaskController().clearLockedTask(task);
3813                     // This activity was in the top focused root task and this is the last
3814                     // activity in that task, give this activity a higher layer so it can stay on
3815                     // top before the closing task transition be executed.
3816                     if (mayAdjustTop) {
3817                         mNeedsZBoost = true;
3818                         mDisplayContent.assignWindowLayers(false /* setLayoutNeeded */);
3819                     }
3820                 }
3821             } else if (!isState(PAUSING)) {
3822                 if (mVisibleRequested) {
3823                     // Prepare and execute close transition.
3824                     if (mTransitionController.isShellTransitionsEnabled()) {
3825                         setVisibility(false);
3826                         if (newTransition != null) {
3827                             // This is a transition specifically for this close operation, so set
3828                             // ready now.
3829                             newTransition.setReady(mDisplayContent, true);
3830                         }
3831                     } else {
3832                         prepareActivityHideTransitionAnimation();
3833                     }
3834                 }
3835 
3836                 final boolean removedActivity = completeFinishing("finishIfPossible") == null;
3837                 // Performance optimization - only invoke OOM adjustment if the state changed to
3838                 // 'STOPPING'. Otherwise it will not change the OOM scores.
3839                 if (oomAdj && isState(STOPPING)) {
3840                     mAtmService.updateOomAdj();
3841                 }
3842 
3843                 // The following code is an optimization. When the last non-task overlay activity
3844                 // is removed from the task, we remove the entire task from the root task. However,
3845                 // since that is done after the scheduled destroy callback from the activity, that
3846                 // call to change the visibility of the task overlay activities would be out of
3847                 // sync with the activity visibility being set for this finishing activity above.
3848                 // In this case, we can set the visibility of all the task overlay activities when
3849                 // we detect the last one is finishing to keep them in sync.
3850                 if (task.onlyHasTaskOverlayActivities(false /* includeFinishing */)) {
3851                     task.forAllActivities((r) -> {
3852                         r.prepareActivityHideTransitionAnimationIfOvarlay();
3853                     });
3854                 }
3855                 return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED;
3856             } else {
3857                 ProtoLog.v(WM_DEBUG_STATES, "Finish waiting for pause of: %s", this);
3858             }
3859 
3860             return FINISH_RESULT_REQUESTED;
3861         } finally {
3862             mAtmService.continueWindowLayout();
3863         }
3864     }
3865 
setForceSendResultForMediaProjection()3866     void setForceSendResultForMediaProjection() {
3867         mForceSendResultForMediaProjection = true;
3868     }
3869 
prepareActivityHideTransitionAnimationIfOvarlay()3870     private void prepareActivityHideTransitionAnimationIfOvarlay() {
3871         if (mTaskOverlay) {
3872             prepareActivityHideTransitionAnimation();
3873         }
3874     }
3875 
prepareActivityHideTransitionAnimation()3876     private void prepareActivityHideTransitionAnimation() {
3877         final DisplayContent dc = mDisplayContent;
3878         dc.prepareAppTransition(TRANSIT_CLOSE);
3879         setVisibility(false);
3880         dc.executeAppTransition();
3881     }
3882 
completeFinishing(String reason)3883     ActivityRecord completeFinishing(String reason) {
3884         return completeFinishing(true /* updateVisibility */, reason);
3885     }
3886 
3887     /**
3888      * Complete activity finish request that was initiated earlier. If the activity is still
3889      * pausing we will wait for it to complete its transition. If the activity that should appear in
3890      * place of this one is not visible yet - we'll wait for it first. Otherwise - activity can be
3891      * destroyed right away.
3892      * @param updateVisibility Indicate if need to update activity visibility.
3893      * @param reason Reason for finishing the activity.
3894      * @return Flag indicating whether the activity was removed from history.
3895      */
completeFinishing(boolean updateVisibility, String reason)3896     ActivityRecord completeFinishing(boolean updateVisibility, String reason) {
3897         if (!finishing || isState(RESUMED)) {
3898             throw new IllegalArgumentException(
3899                     "Activity must be finishing and not resumed to complete, r=" + this
3900                             + ", finishing=" + finishing + ", state=" + mState);
3901         }
3902 
3903         if (isState(PAUSING)) {
3904             // Activity is marked as finishing and will be processed once it completes.
3905             return this;
3906         }
3907 
3908         final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED, STARTED);
3909         if (updateVisibility && isCurrentVisible
3910                 // Avoid intermediate lifecycle change when launching with clearing task.
3911                 && !task.isClearingToReuseTask()) {
3912             boolean ensureVisibility = false;
3913             if (occludesParent(true /* includingFinishing */)) {
3914                 // If the current activity is not opaque, we need to make sure the visibilities of
3915                 // activities be updated, they may be seen by users.
3916                 ensureVisibility = true;
3917             } else if (isKeyguardLocked()
3918                     && mTaskSupervisor.getKeyguardController().topActivityOccludesKeyguard(this)) {
3919                 // Ensure activity visibilities and update lockscreen occluded/dismiss state when
3920                 // finishing the top activity that occluded keyguard. So that, the
3921                 // ActivityStack#mTopActivityOccludesKeyguard can be updated and the activity below
3922                 // won't be resumed.
3923                 ensureVisibility = true;
3924             }
3925 
3926             if (ensureVisibility) {
3927                 mDisplayContent.ensureActivitiesVisible(null /* starting */,
3928                         true /* notifyClients */);
3929             }
3930         }
3931 
3932         boolean activityRemoved = false;
3933 
3934         // If this activity is currently visible, and the resumed activity is not yet visible, then
3935         // hold off on finishing until the resumed one becomes visible.
3936         // The activity that we are finishing may be over the lock screen. In this case, we do not
3937         // want to consider activities that cannot be shown on the lock screen as running and should
3938         // proceed with finishing the activity if there is no valid next top running activity.
3939         // Note that if this finishing activity is floating task, we don't need to wait the
3940         // next activity resume and can destroy it directly.
3941         // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere
3942         final ActivityRecord next = getDisplayArea().topRunningActivity(
3943                 true /* considerKeyguardState */);
3944 
3945         // If the finishing activity is the last activity of an organized TaskFragment and has an
3946         // adjacent TaskFragment, check if the activity removal should be delayed.
3947         boolean delayRemoval = false;
3948         final TaskFragment taskFragment = getTaskFragment();
3949         if (next != null && taskFragment != null && taskFragment.isEmbedded()) {
3950             final TaskFragment organized = taskFragment.getOrganizedTaskFragment();
3951             final TaskFragment adjacent =
3952                     organized != null ? organized.getAdjacentTaskFragment() : null;
3953             if (adjacent != null && next.isDescendantOf(adjacent)
3954                     && organized.topRunningActivity() == null) {
3955                 delayRemoval = organized.isDelayLastActivityRemoval();
3956             }
3957         }
3958 
3959         // isNextNotYetVisible is to check if the next activity is invisible, or it has been
3960         // requested to be invisible but its windows haven't reported as invisible.  If so, it
3961         // implied that the current finishing activity should be added into stopping list rather
3962         // than destroy immediately.
3963         final boolean isNextNotYetVisible = next != null
3964                 && (!next.nowVisible || !next.isVisibleRequested());
3965 
3966         // Clear last paused activity to ensure top activity can be resumed during sleeping.
3967         if (isNextNotYetVisible && mDisplayContent.isSleeping()
3968                 && next == next.getTaskFragment().mLastPausedActivity) {
3969             next.getTaskFragment().clearLastPausedActivity();
3970         }
3971 
3972         if (isCurrentVisible) {
3973             if (isNextNotYetVisible || delayRemoval || (next != null && isInTransition())) {
3974                 // Add this activity to the list of stopping activities. It will be processed and
3975                 // destroyed when the next activity reports idle.
3976                 addToStopping(false /* scheduleIdle */, false /* idleDelayed */,
3977                         "completeFinishing");
3978                 setState(STOPPING, "completeFinishing");
3979             } else if (addToFinishingAndWaitForIdle()) {
3980                 // We added this activity to the finishing list and something else is becoming
3981                 // resumed. The activity will complete finishing when the next activity reports
3982                 // idle. No need to do anything else here.
3983             } else {
3984                 // Not waiting for the next one to become visible, and nothing else will be
3985                 // resumed in place of this activity - requesting destruction right away.
3986                 activityRemoved = destroyIfPossible(reason);
3987             }
3988         } else {
3989             // Just need to make sure the next activities can be resumed (if needed) and is free
3990             // to destroy this activity since it is currently not visible.
3991             addToFinishingAndWaitForIdle();
3992             activityRemoved = destroyIfPossible(reason);
3993         }
3994 
3995         return activityRemoved ? null : this;
3996     }
3997 
3998     /**
3999      * Destroy and cleanup the activity both on client and server if possible. If activity is the
4000      * last one left on display with home root task and there is no other running activity - delay
4001      * destroying it until the next one starts.
4002      */
destroyIfPossible(String reason)4003     boolean destroyIfPossible(String reason) {
4004         setState(FINISHING, "destroyIfPossible");
4005 
4006         // Make sure the record is cleaned out of other places.
4007         mTaskSupervisor.mStoppingActivities.remove(this);
4008 
4009         final Task rootTask = getRootTask();
4010         final TaskDisplayArea taskDisplayArea = getDisplayArea();
4011         // TODO(b/137329632): Exclude current activity when looking for the next one with
4012         // DisplayContent#topRunningActivity().
4013         final ActivityRecord next = taskDisplayArea.topRunningActivity();
4014         final boolean isLastRootTaskOverEmptyHome =
4015                 next == null && rootTask.isFocusedRootTaskOnDisplay()
4016                         && taskDisplayArea.getOrCreateRootHomeTask() != null;
4017         if (isLastRootTaskOverEmptyHome) {
4018             // Don't destroy activity immediately if this is the last activity on the display and
4019             // the display contains root home task. Although there is no next activity at the
4020             // moment, another home activity should be started later. Keep this activity alive
4021             // until next home activity is resumed. This way the user won't see a temporary black
4022             // screen.
4023             addToFinishingAndWaitForIdle();
4024             return false;
4025         }
4026         makeFinishingLocked();
4027 
4028         final boolean activityRemoved = destroyImmediately("finish-imm:" + reason);
4029 
4030         // If the display does not have running activity, the configuration may need to be
4031         // updated for restoring original orientation of the display.
4032         if (next == null) {
4033             mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */, mDisplayContent,
4034                     true /* deferResume */);
4035             if (mDisplayContent.topRunningActivity() == null) {
4036                 // The transition is ready on a display with no running activities.
4037                 mTransitionController.setReady(mDisplayContent);
4038             }
4039         }
4040         if (activityRemoved) {
4041             mRootWindowContainer.resumeFocusedTasksTopActivities();
4042         }
4043 
4044         ProtoLog.d(WM_DEBUG_CONTAINERS, "destroyIfPossible: r=%s destroy returned "
4045                 + "removed=%s", this, activityRemoved);
4046 
4047         return activityRemoved;
4048     }
4049 
4050     /**
4051      * Add this activity to the list of finishing and trigger resuming of activities in focused
4052      * root tasks.
4053      * @return {@code true} if some other activity is being resumed as a result of this call.
4054      */
4055     @VisibleForTesting
addToFinishingAndWaitForIdle()4056     boolean addToFinishingAndWaitForIdle() {
4057         ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending finish: %s", this);
4058         setState(FINISHING, "addToFinishingAndWaitForIdle");
4059         if (!mTaskSupervisor.mFinishingActivities.contains(this)) {
4060             mTaskSupervisor.mFinishingActivities.add(this);
4061         }
4062         resumeKeyDispatchingLocked();
4063         return mRootWindowContainer.resumeFocusedTasksTopActivities();
4064     }
4065 
4066     /**
4067      * Destroy the current CLIENT SIDE instance of an activity. This may be called both when
4068      * actually finishing an activity, or when performing a configuration switch where we destroy
4069      * the current client-side object but then create a new client-side object for this same
4070      * HistoryRecord.
4071      * Normally the server-side record will be removed when the client reports back after
4072      * destruction. If, however, at this point there is no client process attached, the record will
4073      * be removed immediately.
4074      *
4075      * @return {@code true} if activity was immediately removed from history, {@code false}
4076      * otherwise.
4077      */
destroyImmediately(String reason)4078     boolean destroyImmediately(String reason) {
4079         if (DEBUG_SWITCH || DEBUG_CLEANUP) {
4080             Slog.v(TAG_SWITCH, "Removing activity from " + reason + ": token=" + this
4081                     + ", app=" + (hasProcess() ? app.mName : "(null)"));
4082         }
4083 
4084         if (isState(DESTROYING, DESTROYED)) {
4085             ProtoLog.v(WM_DEBUG_STATES, "activity %s already destroying, skipping "
4086                     + "request with reason:%s", this, reason);
4087             return false;
4088         }
4089 
4090         EventLogTags.writeWmDestroyActivity(mUserId, System.identityHashCode(this),
4091                 task.mTaskId, shortComponentName, reason);
4092 
4093         boolean removedFromHistory = false;
4094 
4095         cleanUp(false /* cleanServices */, false /* setState */);
4096         setVisibleRequested(false);
4097 
4098         if (hasProcess()) {
4099             app.removeActivity(this, true /* keepAssociation */);
4100             if (!app.hasActivities()) {
4101                 mAtmService.clearHeavyWeightProcessIfEquals(app);
4102             }
4103 
4104             boolean skipDestroy = false;
4105 
4106             try {
4107                 if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + this);
4108                 mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
4109                         DestroyActivityItem.obtain(token, finishing));
4110             } catch (Exception e) {
4111                 // We can just ignore exceptions here...  if the process has crashed, our death
4112                 // notification will clean things up.
4113                 if (finishing) {
4114                     removeFromHistory(reason + " exceptionInScheduleDestroy");
4115                     removedFromHistory = true;
4116                     skipDestroy = true;
4117                 }
4118             }
4119 
4120             nowVisible = false;
4121 
4122             // If the activity is finishing, we need to wait on removing it from the list to give it
4123             // a chance to do its cleanup.  During that time it may make calls back with its token
4124             // so we need to be able to find it on the list and so we don't want to remove it from
4125             // the list yet.  Otherwise, we can just immediately put it in the destroyed state since
4126             // we are not removing it from the list.
4127             if (finishing && !skipDestroy) {
4128                 ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYING: %s (destroy requested)", this);
4129                 setState(DESTROYING,
4130                         "destroyActivityLocked. finishing and not skipping destroy");
4131                 mAtmService.mH.postDelayed(mDestroyTimeoutRunnable, DESTROY_TIMEOUT);
4132             } else {
4133                 ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s "
4134                         + "(destroy skipped)", this);
4135                 setState(DESTROYED,
4136                         "destroyActivityLocked. not finishing or skipping destroy");
4137                 if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + this);
4138                 detachFromProcess();
4139             }
4140         } else {
4141             // Remove this record from the history.
4142             if (finishing) {
4143                 removeFromHistory(reason + " hadNoApp");
4144                 removedFromHistory = true;
4145             } else {
4146                 ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s (no app)", this);
4147                 setState(DESTROYED, "destroyActivityLocked. not finishing and had no app");
4148             }
4149         }
4150 
4151         return removedFromHistory;
4152     }
4153 
4154     /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */
removeFromHistory(String reason)4155     void removeFromHistory(String reason) {
4156         finishActivityResults(Activity.RESULT_CANCELED,
4157                 null /* resultData */, null /* resultGrants */);
4158         makeFinishingLocked();
4159 
4160         ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s, reason= %s "
4161                         + "callers=%s", this, reason, Debug.getCallers(5));
4162 
4163         takeFromHistory();
4164         removeTimeouts();
4165         ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s (removed from history)",
4166                 this);
4167         setState(DESTROYED, "removeFromHistory");
4168         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
4169         detachFromProcess();
4170         // Resume key dispatching if it is currently paused before we remove the container.
4171         resumeKeyDispatchingLocked();
4172         mDisplayContent.removeAppToken(token);
4173 
4174         cleanUpActivityServices();
4175         removeUriPermissionsLocked();
4176     }
4177 
detachFromProcess()4178     void detachFromProcess() {
4179         if (app != null) {
4180             app.removeActivity(this, false /* keepAssociation */);
4181         }
4182         app = null;
4183         mInputDispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
4184     }
4185 
makeFinishingLocked()4186     void makeFinishingLocked() {
4187         if (finishing) {
4188             return;
4189         }
4190         finishing = true;
4191 
4192         // Transfer the launch cookie to the next running activity above this in the same task.
4193         if (mLaunchCookie != null && mState != RESUMED && task != null && !task.mInRemoveTask
4194                 && !task.isClearingToReuseTask()) {
4195             final ActivityRecord nextCookieTarget = task.getActivity(
4196                     // Intend to only associate the same app by checking uid.
4197                     r -> r.mLaunchCookie == null && !r.finishing && r.isUid(getUid()),
4198                     this, false /* includeBoundary */, false /* traverseTopToBottom */);
4199             if (nextCookieTarget != null) {
4200                 nextCookieTarget.mLaunchCookie = mLaunchCookie;
4201                 mLaunchCookie = null;
4202             }
4203         }
4204 
4205         final TaskFragment taskFragment = getTaskFragment();
4206         if (taskFragment != null) {
4207             final Task task = taskFragment.getTask();
4208             if (task != null && task.isClearingToReuseTask()
4209                     && taskFragment.getTopNonFinishingActivity() == null) {
4210                 taskFragment.mClearedTaskForReuse = true;
4211             }
4212             taskFragment.sendTaskFragmentInfoChanged();
4213         }
4214         if (mAppStopped) {
4215             abortAndClearOptionsAnimation();
4216         }
4217         if (mDisplayContent != null) {
4218             mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
4219         }
4220     }
4221 
4222     /**
4223      * This method is to only be called from the client via binder when the activity is destroyed
4224      * AND finished.
4225      */
destroyed(String reason)4226     void destroyed(String reason) {
4227         removeDestroyTimeout();
4228 
4229         ProtoLog.d(WM_DEBUG_CONTAINERS, "activityDestroyedLocked: r=%s", this);
4230 
4231         if (!isState(DESTROYING, DESTROYED)) {
4232             throw new IllegalStateException(
4233                     "Reported destroyed for activity that is not destroying: r=" + this);
4234         }
4235 
4236         mTaskSupervisor.killTaskProcessesOnDestroyedIfNeeded(task);
4237         if (isInRootTaskLocked()) {
4238             cleanUp(true /* cleanServices */, false /* setState */);
4239             removeFromHistory(reason);
4240         }
4241 
4242         mRootWindowContainer.resumeFocusedTasksTopActivities();
4243     }
4244 
4245     /**
4246      * Perform the common clean-up of an activity record.  This is called both as part of
4247      * destroyActivityLocked() (when destroying the client-side representation) and cleaning things
4248      * up as a result of its hosting processing going away, in which case there is no remaining
4249      * client-side state to destroy so only the cleanup here is needed.
4250      *
4251      * Note: Call before {@link #removeFromHistory(String)}.
4252      */
cleanUp(boolean cleanServices, boolean setState)4253     void cleanUp(boolean cleanServices, boolean setState) {
4254         getTaskFragment().cleanUpActivityReferences(this);
4255         clearLastParentBeforePip();
4256 
4257         // Abort and reset state if the scence transition is playing.
4258         final Task rootTask = getRootTask();
4259         if (rootTask != null) {
4260             rootTask.abortTranslucentActivityWaiting(this);
4261         }
4262 
4263         // Clean up the splash screen if it was still displayed.
4264         cleanUpSplashScreen();
4265 
4266         if (setState) {
4267             setState(DESTROYED, "cleanUp");
4268             if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + this);
4269             detachFromProcess();
4270         }
4271 
4272         // Inform supervisor the activity has been removed.
4273         mTaskSupervisor.cleanupActivity(this);
4274 
4275         // Remove any pending results.
4276         if (finishing && pendingResults != null) {
4277             for (WeakReference<PendingIntentRecord> apr : pendingResults) {
4278                 PendingIntentRecord rec = apr.get();
4279                 if (rec != null) {
4280                     mAtmService.mPendingIntentController.cancelIntentSender(rec,
4281                             false /* cleanActivity */,
4282                             PendingIntentRecord.CANCEL_REASON_HOSTING_ACTIVITY_DESTROYED);
4283                 }
4284             }
4285             pendingResults = null;
4286         }
4287 
4288         if (cleanServices) {
4289             cleanUpActivityServices();
4290         }
4291 
4292         // Get rid of any pending idle timeouts.
4293         removeTimeouts();
4294         // Clean-up activities are no longer relaunching (e.g. app process died). Notify window
4295         // manager so it can update its bookkeeping.
4296         clearRelaunching();
4297     }
4298 
isRelaunching()4299     boolean isRelaunching() {
4300         return mPendingRelaunchCount > 0;
4301     }
4302 
4303     @VisibleForTesting
startRelaunching()4304     void startRelaunching() {
4305         if (mPendingRelaunchCount == 0) {
4306             mRelaunchStartTime = SystemClock.elapsedRealtime();
4307             if (mVisibleRequested) {
4308                 mDisplayContent.getDisplayPolicy().addRelaunchingApp(this);
4309             }
4310         }
4311         clearAllDrawn();
4312 
4313         mPendingRelaunchCount++;
4314     }
4315 
finishRelaunching()4316     void finishRelaunching() {
4317         mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(false);
4318         mTaskSupervisor.getActivityMetricsLogger().notifyActivityRelaunched(this);
4319 
4320         if (mPendingRelaunchCount > 0) {
4321             mPendingRelaunchCount--;
4322             if (mPendingRelaunchCount == 0 && !isClientVisible()) {
4323                 // Don't count if the client won't report drawn.
4324                 finishOrAbortReplacingWindow();
4325             }
4326         } else {
4327             // Update keyguard flags upon finishing relaunch.
4328             checkKeyguardFlagsChanged();
4329         }
4330 
4331         final Task rootTask = getRootTask();
4332         if (rootTask != null && rootTask.shouldSleepOrShutDownActivities()) {
4333             // Activity is always relaunched to either resumed or paused state. If it was
4334             // relaunched while hidden (by keyguard or smth else), it should be stopped.
4335             rootTask.ensureActivitiesVisible(null /* starting */);
4336         }
4337     }
4338 
clearRelaunching()4339     void clearRelaunching() {
4340         if (mPendingRelaunchCount == 0) {
4341             return;
4342         }
4343         mPendingRelaunchCount = 0;
4344         finishOrAbortReplacingWindow();
4345     }
4346 
finishOrAbortReplacingWindow()4347     void finishOrAbortReplacingWindow() {
4348         mRelaunchStartTime = 0;
4349         mDisplayContent.getDisplayPolicy().removeRelaunchingApp(this);
4350     }
4351 
getOrCreateServiceConnectionsHolder()4352     ActivityServiceConnectionsHolder getOrCreateServiceConnectionsHolder() {
4353         synchronized (this) {
4354             if (mServiceConnectionsHolder == null) {
4355                 mServiceConnectionsHolder = new ActivityServiceConnectionsHolder(this);
4356             }
4357             return mServiceConnectionsHolder;
4358         }
4359     }
4360 
4361     /**
4362      * Perform clean-up of service connections in an activity record.
4363      */
cleanUpActivityServices()4364     private void cleanUpActivityServices() {
4365         synchronized (this) {
4366             if (mServiceConnectionsHolder == null) {
4367                 return;
4368             }
4369             // Throw away any services that have been bound by this activity.
4370             mServiceConnectionsHolder.disconnectActivityFromServices();
4371             // This activity record is removing, make sure not to disconnect twice.
4372             mServiceConnectionsHolder = null;
4373         }
4374     }
4375 
updateVisibleForServiceConnection()4376     private void updateVisibleForServiceConnection() {
4377         mVisibleForServiceConnection = mVisibleRequested || mState == RESUMED || mState == PAUSING;
4378     }
4379 
4380     /**
4381      * Detach this activity from process and clear the references to it. If the activity is
4382      * finishing or has no saved state or crashed many times, it will also be removed from history.
4383      */
handleAppDied()4384     void handleAppDied() {
4385         final boolean remove;
4386         if (Process.isSdkSandboxUid(getUid())) {
4387             // Sandbox activities are created for SDKs run in the sandbox process, when the sandbox
4388             // process dies, the SDKs are unloaded and can not handle the activity, so sandbox
4389             // activity records should be removed.
4390             remove = true;
4391         } else if ((mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE
4392                 || mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE)
4393                 && launchCount < 3 && !finishing) {
4394             // If the process crashed during a resize, always try to relaunch it, unless it has
4395             // failed more than twice. Skip activities that's already finishing cleanly by itself.
4396             remove = false;
4397         } else if ((!mHaveState && !stateNotNeeded
4398                 && !isState(State.RESTARTING_PROCESS)) || finishing) {
4399             // Don't currently have state for the activity, or it is finishing -- always remove it.
4400             remove = true;
4401         } else if (!mVisibleRequested && launchCount > 2
4402                 && lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
4403             // We have launched this activity too many times since it was able to run, so give up
4404             // and remove it.
4405             remove = true;
4406         } else {
4407             // The process may be gone, but the activity lives on!
4408             remove = false;
4409         }
4410         if (remove) {
4411             ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s hasSavedState=%b "
4412                     + "stateNotNeeded=%s finishing=%b state=%s callers=%s", this,
4413                     mHaveState, stateNotNeeded, finishing, mState, Debug.getCallers(5));
4414             if (!finishing || (app != null && app.isRemoved())) {
4415                 Slog.w(TAG, "Force removing " + this + ": app died, no saved state");
4416                 EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
4417                         task != null ? task.mTaskId : -1, shortComponentName,
4418                         "proc died without state saved");
4419             }
4420         } else {
4421             // We have the current state for this activity, so it can be restarted later
4422             // when needed.
4423             if (DEBUG_APP) {
4424                 Slog.v(TAG_APP, "Keeping entry during removeHistory for activity " + this);
4425             }
4426         }
4427         if (task != null && task.mKillProcessesOnDestroyed) {
4428             mTaskSupervisor.removeTimeoutOfKillProcessesOnProcessDied(this, task);
4429         }
4430         // upgrade transition trigger to task if this is the last activity since it means we are
4431         // closing the task.
4432         final WindowContainer trigger = remove && task != null && task.getChildCount() == 1
4433                 ? task : this;
4434         final Transition newTransit = mTransitionController.requestCloseTransitionIfNeeded(trigger);
4435         if (newTransit != null) {
4436             newTransit.collectClose(trigger);
4437         } else if (mTransitionController.isCollecting()) {
4438             mTransitionController.getCollectingTransition().collectClose(trigger);
4439         }
4440         cleanUp(true /* cleanServices */, true /* setState */);
4441         if (remove) {
4442             if (mStartingData != null && mVisible && task != null) {
4443                 // A corner case that the app terminates its trampoline activity on a separated
4444                 // process by killing itself. Transfer the starting window to the next activity
4445                 // which will be visible, so the dead activity can be removed immediately (no
4446                 // longer animating) and the reveal animation can play normally on next activity.
4447                 final ActivityRecord top = task.topRunningActivity();
4448                 if (top != null && !top.mVisible && top.shouldBeVisible()) {
4449                     top.transferStartingWindow(this);
4450                 }
4451             }
4452             removeFromHistory("appDied");
4453         }
4454     }
4455 
4456     @Override
removeImmediately()4457     void removeImmediately() {
4458         if (mState != DESTROYED) {
4459             Slog.w(TAG, "Force remove immediately " + this + " state=" + mState);
4460             // If Task#removeImmediately is called directly with alive activities, ensure that the
4461             // activities are destroyed and detached from process.
4462             destroyImmediately("removeImmediately");
4463             // Complete the destruction immediately because this activity will not be found in
4464             // hierarchy, it is unable to report completion.
4465             destroyed("removeImmediately");
4466         } else {
4467             onRemovedFromDisplay();
4468         }
4469         mActivityRecordInputSink.releaseSurfaceControl();
4470 
4471         super.removeImmediately();
4472     }
4473 
4474     @Override
removeIfPossible()4475     void removeIfPossible() {
4476         mIsExiting = false;
4477         removeAllWindowsIfPossible();
4478         removeImmediately();
4479     }
4480 
4481     @Override
handleCompleteDeferredRemoval()4482     boolean handleCompleteDeferredRemoval() {
4483         if (mIsExiting) {
4484             removeIfPossible();
4485         }
4486         return super.handleCompleteDeferredRemoval();
4487     }
4488 
onRemovedFromDisplay()4489     void onRemovedFromDisplay() {
4490         if (mRemovingFromDisplay) {
4491             return;
4492         }
4493         mRemovingFromDisplay = true;
4494 
4495         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Removing app token: %s", this);
4496 
4497         getDisplayContent().mOpeningApps.remove(this);
4498         getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
4499         mWmService.mSnapshotController.onAppRemoved(this);
4500         mAtmService.mStartingProcessActivities.remove(this);
4501 
4502         mTaskSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
4503         mTaskSupervisor.mStoppingActivities.remove(this);
4504         mLetterboxUiController.destroy();
4505 
4506         // Defer removal of this activity when either a child is animating, or app transition is on
4507         // going. App transition animation might be applied on the parent task not on the activity,
4508         // but the actual frame buffer is associated with the activity, so we have to keep the
4509         // activity while a parent is animating.
4510         boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN,
4511                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION);
4512         if (getDisplayContent().mClosingApps.contains(this)) {
4513             delayed = true;
4514         } else if (getDisplayContent().mAppTransition.isTransitionSet()) {
4515             getDisplayContent().mClosingApps.add(this);
4516             delayed = true;
4517         } else if (mTransitionController.inTransition()) {
4518             delayed = true;
4519         }
4520 
4521         // Don't commit visibility if it is waiting to animate. It will be set post animation.
4522         if (!delayed) {
4523             commitVisibility(false /* visible */, true /* performLayout */);
4524         } else {
4525             setVisibleRequested(false /* visible */);
4526         }
4527 
4528         // TODO(b/169035022): move to a more-appropriate place.
4529         mTransitionController.collect(this);
4530 
4531         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
4532                 "Removing app %s delayed=%b animation=%s animating=%b", this, delayed,
4533                 getAnimation(),
4534                 isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION));
4535 
4536         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "removeAppToken: %s"
4537                 + " delayed=%b Callers=%s", this, delayed, Debug.getCallers(4));
4538 
4539         if (mStartingData != null) {
4540             removeStartingWindow();
4541         }
4542 
4543         // If app transition animation was running for this activity, then we need to ensure that
4544         // the app transition notifies that animations have completed in
4545         // DisplayContent.handleAnimatingStoppedAndTransition(), so add to that list now
4546         if (isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
4547             getDisplayContent().mNoAnimationNotifyOnTransitionFinished.add(token);
4548         }
4549 
4550         if (delayed && !isEmpty()) {
4551             // set the token aside because it has an active animation to be finished
4552             ProtoLog.v(WM_DEBUG_ADD_REMOVE,
4553                     "removeAppToken make exiting: %s", this);
4554             mIsExiting = true;
4555         } else {
4556             // Make sure there is no animation running on this token, so any windows associated
4557             // with it will be removed as soon as their animations are complete
4558             cancelAnimation();
4559             removeIfPossible();
4560         }
4561 
4562         stopFreezingScreen(true, true);
4563 
4564         final DisplayContent dc = getDisplayContent();
4565         if (dc.mFocusedApp == this) {
4566             ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
4567                     "Removing focused app token:%s displayId=%d", this,
4568                     dc.getDisplayId());
4569             dc.setFocusedApp(null);
4570             mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
4571         }
4572 
4573         if (!delayed) {
4574             updateReportedVisibilityLocked();
4575         }
4576 
4577         // Reset the last saved PiP snap fraction on removal.
4578         mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
4579         mDisplayContent.onRunningActivityChanged();
4580         mRemovingFromDisplay = false;
4581     }
4582 
4583     /**
4584      * Returns true if the new child window we are adding to this token is considered greater than
4585      * the existing child window in this token in terms of z-order.
4586      */
4587     @Override
isFirstChildWindowGreaterThanSecond(WindowState newWindow, WindowState existingWindow)4588     protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
4589             WindowState existingWindow) {
4590         final int type1 = newWindow.mAttrs.type;
4591         final int type2 = existingWindow.mAttrs.type;
4592 
4593         // Base application windows should be z-ordered BELOW all other windows in the app token.
4594         if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) {
4595             return false;
4596         } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) {
4597             return true;
4598         }
4599 
4600         // Starting windows should be z-ordered ABOVE all other windows in the app token.
4601         if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) {
4602             return true;
4603         } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) {
4604             return false;
4605         }
4606 
4607         // Otherwise the new window is greater than the existing window.
4608         return true;
4609     }
4610 
4611     /**
4612      * @return {@code true} if starting window is in app's hierarchy.
4613      */
hasStartingWindow()4614     boolean hasStartingWindow() {
4615         if (mStartingData != null) {
4616             return true;
4617         }
4618         for (int i = mChildren.size() - 1; i >= 0; i--) {
4619             if (getChildAt(i).mAttrs.type == TYPE_APPLICATION_STARTING) {
4620                 return true;
4621             }
4622         }
4623         return false;
4624     }
4625 
isLastWindow(WindowState win)4626     boolean isLastWindow(WindowState win) {
4627         return mChildren.size() == 1 && mChildren.get(0) == win;
4628     }
4629 
4630     @Override
addWindow(WindowState w)4631     void addWindow(WindowState w) {
4632         super.addWindow(w);
4633         checkKeyguardFlagsChanged();
4634     }
4635 
4636     @Override
removeChild(WindowState child)4637     void removeChild(WindowState child) {
4638         if (!mChildren.contains(child)) {
4639             // This can be true when testing.
4640             return;
4641         }
4642         super.removeChild(child);
4643         checkKeyguardFlagsChanged();
4644         updateLetterboxSurfaceIfNeeded(child);
4645     }
4646 
setAppLayoutChanges(int changes, String reason)4647     void setAppLayoutChanges(int changes, String reason) {
4648         if (!mChildren.isEmpty()) {
4649             final DisplayContent dc = getDisplayContent();
4650             dc.pendingLayoutChanges |= changes;
4651             if (DEBUG_LAYOUT_REPEATS) {
4652                 mWmService.mWindowPlacerLocked.debugLayoutRepeats(reason, dc.pendingLayoutChanges);
4653             }
4654         }
4655     }
4656 
transferStartingWindow(@onNull ActivityRecord fromActivity)4657     private boolean transferStartingWindow(@NonNull ActivityRecord fromActivity) {
4658         final WindowState tStartingWindow = fromActivity.mStartingWindow;
4659         if (tStartingWindow != null && fromActivity.mStartingSurface != null) {
4660             if (tStartingWindow.getParent() == null) {
4661                 // The window has been detached from the parent, so the window cannot be transfer
4662                 // to another activity because it may be in the remove process.
4663                 // Don't need to remove the starting window at this point because that will happen
4664                 // at #postWindowRemoveCleanupLocked
4665                 return false;
4666             }
4667             // Do not transfer if the orientation doesn't match, redraw starting window while it is
4668             // on top will cause flicker.
4669             if (fromActivity.getRequestedConfigurationOrientation()
4670                     != getRequestedConfigurationOrientation()) {
4671                 return false;
4672             }
4673             // In this case, the starting icon has already been displayed, so start
4674             // letting windows get shown immediately without any more transitions.
4675             if (fromActivity.mVisible) {
4676                 mDisplayContent.mSkipAppTransitionAnimation = true;
4677             }
4678 
4679             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Moving existing starting %s"
4680                     + " from %s to %s", tStartingWindow, fromActivity, this);
4681 
4682             final long origId = Binder.clearCallingIdentity();
4683             try {
4684                 // Link the fixed rotation transform to this activity since we are transferring the
4685                 // starting window.
4686                 if (fromActivity.hasFixedRotationTransform()) {
4687                     mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
4688                             false /* checkOpening */);
4689                 }
4690 
4691                 // Transfer the starting window over to the new token.
4692                 mStartingData = fromActivity.mStartingData;
4693                 mStartingSurface = fromActivity.mStartingSurface;
4694                 mStartingWindow = tStartingWindow;
4695                 reportedVisible = fromActivity.reportedVisible;
4696                 fromActivity.mStartingData = null;
4697                 fromActivity.mStartingSurface = null;
4698                 fromActivity.mStartingWindow = null;
4699                 fromActivity.startingMoved = true;
4700                 tStartingWindow.mToken = this;
4701                 tStartingWindow.mActivityRecord = this;
4702 
4703                 ProtoLog.v(WM_DEBUG_ADD_REMOVE,
4704                         "Removing starting %s from %s", tStartingWindow, fromActivity);
4705                 mTransitionController.collect(tStartingWindow);
4706                 tStartingWindow.reparent(this, POSITION_TOP);
4707 
4708                 // Clear the frozen insets state when transferring the existing starting window to
4709                 // the next target activity.  In case the frozen state from a trampoline activity
4710                 // affecting the starting window frame computation to see the window being
4711                 // clipped if the rotation change during the transition animation.
4712                 tStartingWindow.clearFrozenInsetsState();
4713 
4714                 // Propagate other interesting state between the tokens. If the old token is
4715                 // displayed, we should immediately force the new one to be displayed. If it is
4716                 // animating, we need to move that animation to the new one.
4717                 if (fromActivity.allDrawn) {
4718                     allDrawn = true;
4719                 }
4720                 if (fromActivity.firstWindowDrawn) {
4721                     firstWindowDrawn = true;
4722                 }
4723                 if (fromActivity.isVisible()) {
4724                     setVisible(true);
4725                     setVisibleRequested(true);
4726                     mVisibleSetFromTransferredStartingWindow = true;
4727                 }
4728                 setClientVisible(fromActivity.isClientVisible());
4729 
4730                 if (fromActivity.isAnimating()) {
4731                     transferAnimation(fromActivity);
4732 
4733                     // When transferring an animation, we no longer need to apply an animation to
4734                     // the token we transfer the animation over. Thus, set this flag to indicate
4735                     // we've transferred the animation.
4736                     mTransitionChangeFlags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
4737                 } else if (mTransitionController.getTransitionPlayer() != null) {
4738                     // In the new transit system, just set this every time we transfer the window
4739                     mTransitionChangeFlags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
4740                 }
4741                 // Post cleanup after the visibility and animation are transferred.
4742                 fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow);
4743                 fromActivity.mVisibleSetFromTransferredStartingWindow = false;
4744 
4745                 mWmService.updateFocusedWindowLocked(
4746                         UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
4747                 getDisplayContent().setLayoutNeeded();
4748                 mWmService.mWindowPlacerLocked.performSurfacePlacement();
4749             } finally {
4750                 Binder.restoreCallingIdentity(origId);
4751             }
4752             return true;
4753         } else if (fromActivity.mStartingData != null) {
4754             // The previous app was getting ready to show a
4755             // starting window, but hasn't yet done so.  Steal it!
4756             ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
4757                     "Moving pending starting from %s to %s", fromActivity, this);
4758             mStartingData = fromActivity.mStartingData;
4759             fromActivity.mStartingData = null;
4760             fromActivity.startingMoved = true;
4761             scheduleAddStartingWindow();
4762             return true;
4763         }
4764 
4765         // TODO: Transfer thumbnail
4766 
4767         return false;
4768     }
4769 
4770     /**
4771      * Tries to transfer the starting window from a token that's above ourselves in the task but
4772      * not visible anymore. This is a common scenario apps use: Trampoline activity T start main
4773      * activity M in the same task. Now, when reopening the task, T starts on top of M but then
4774      * immediately finishes after, so we have to transfer T to M.
4775      */
transferStartingWindowFromHiddenAboveTokenIfNeeded()4776     void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
4777         final WindowState mainWin = findMainWindow(false);
4778         if (mainWin != null && mainWin.mWinAnimator.getShown()) {
4779             // This activity already has a visible window, so doesn't need to transfer the starting
4780             // window from above activity to here. The starting window will be removed with above
4781             // activity.
4782             return;
4783         }
4784         task.forAllActivities(fromActivity -> {
4785             if (fromActivity == this) return true;
4786             // The snapshot starting window could remove itself when receive resized request without
4787             // redraw, so transfer it to a different size activity could only cause flicker.
4788             // By schedule remove snapshot starting window, the remove process will happen when
4789             // transition ready, transition ready means the app window is drawn.
4790             final StartingData tmpStartingData = fromActivity.mStartingData;
4791             if (tmpStartingData != null && tmpStartingData.mAssociatedTask == null
4792                     && mTransitionController.isCollecting(fromActivity)
4793                     && tmpStartingData instanceof SnapshotStartingData) {
4794                 final Rect fromBounds = fromActivity.getBounds();
4795                 final Rect myBounds = getBounds();
4796                 if (!fromBounds.equals(myBounds)) {
4797                     // Mark as no animation, so these changes won't merge into playing transition.
4798                     if (mTransitionController.inPlayingTransition(fromActivity)) {
4799                         mTransitionController.setNoAnimation(this);
4800                         mTransitionController.setNoAnimation(fromActivity);
4801                     }
4802                     fromActivity.removeStartingWindow();
4803                     return true;
4804                 }
4805             }
4806             return !fromActivity.isVisibleRequested() && transferStartingWindow(fromActivity);
4807         });
4808     }
4809 
isKeyguardLocked()4810     boolean isKeyguardLocked() {
4811         return (mDisplayContent != null) ? mDisplayContent.isKeyguardLocked() :
4812                 mRootWindowContainer.getDefaultDisplay().isKeyguardLocked();
4813     }
4814 
checkKeyguardFlagsChanged()4815     void checkKeyguardFlagsChanged() {
4816         final boolean containsDismissKeyguard = containsDismissKeyguardWindow();
4817         final boolean containsShowWhenLocked = containsShowWhenLockedWindow();
4818         if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow
4819                 || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) {
4820             mDisplayContent.notifyKeyguardFlagsChanged();
4821         }
4822         mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
4823         mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
4824         mLastContainsTurnScreenOnWindow = containsTurnScreenOnWindow();
4825     }
4826 
containsDismissKeyguardWindow()4827     boolean containsDismissKeyguardWindow() {
4828         // Window state is transient during relaunch. We are not guaranteed to be frozen during the
4829         // entirety of the relaunch.
4830         if (isRelaunching()) {
4831             return mLastContainsDismissKeyguardWindow;
4832         }
4833 
4834         for (int i = mChildren.size() - 1; i >= 0; i--) {
4835             if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
4836                 return true;
4837             }
4838         }
4839         return false;
4840     }
4841 
containsShowWhenLockedWindow()4842     boolean containsShowWhenLockedWindow() {
4843         // When we are relaunching, it is possible for us to be unfrozen before our previous
4844         // windows have been added back. Using the cached value ensures that our previous
4845         // showWhenLocked preference is honored until relaunching is complete.
4846         if (isRelaunching()) {
4847             return mLastContainsShowWhenLockedWindow;
4848         }
4849 
4850         for (int i = mChildren.size() - 1; i >= 0; i--) {
4851             if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
4852                 return true;
4853             }
4854         }
4855 
4856         return false;
4857     }
4858 
setShowWhenLocked(boolean showWhenLocked)4859     void setShowWhenLocked(boolean showWhenLocked) {
4860         mShowWhenLocked = showWhenLocked;
4861         mAtmService.mRootWindowContainer.ensureActivitiesVisible();
4862     }
4863 
setInheritShowWhenLocked(boolean inheritShowWhenLocked)4864     void setInheritShowWhenLocked(boolean inheritShowWhenLocked) {
4865         mInheritShownWhenLocked = inheritShowWhenLocked;
4866         mAtmService.mRootWindowContainer.ensureActivitiesVisible();
4867     }
4868 
4869     /**
4870      * @return {@code true} if the activity windowing mode is not in
4871      *         {@link android.app.WindowConfiguration#WINDOWING_MODE_PINNED} and a) activity
4872      *         contains windows that have {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the
4873      *         activity has set {@link #mShowWhenLocked}, or if its user
4874      *         is {@link #mIsUserAlwaysVisible always-visible} or b) if the activity has set
4875      *         {@link #mInheritShownWhenLocked} and the activity behind this satisfies the
4876      *         conditions a) above.
4877      *         Multi-windowing mode will be exited if {@code true} is returned.
4878      */
canShowWhenLocked(ActivityRecord r)4879     private static boolean canShowWhenLocked(ActivityRecord r) {
4880         if (r == null || r.getTaskFragment() == null) {
4881             return false;
4882         }
4883         if (canShowWhenLockedInner(r)) {
4884             return true;
4885         } else if (r.mInheritShownWhenLocked) {
4886             final ActivityRecord activity = r.getTaskFragment().getActivityBelow(r);
4887             return activity != null && canShowWhenLockedInner(activity);
4888         } else {
4889             return false;
4890         }
4891     }
4892 
4893     /** @see #canShowWhenLocked(ActivityRecord) */
canShowWhenLockedInner(@onNull ActivityRecord r)4894     private static boolean canShowWhenLockedInner(@NonNull ActivityRecord r) {
4895         return !r.inPinnedWindowingMode() &&
4896                 (r.mShowWhenLocked || r.containsShowWhenLockedWindow() || r.mIsUserAlwaysVisible);
4897     }
4898 
4899     /**
4900      *  Determines if the activity can show while lock-screen is displayed. System displays
4901      *  activities while lock-screen is displayed only if all activities
4902      *  {@link #canShowWhenLocked(ActivityRecord)}.
4903      *  @see #canShowWhenLocked(ActivityRecord)
4904      */
canShowWhenLocked()4905     boolean canShowWhenLocked() {
4906         final TaskFragment taskFragment = getTaskFragment();
4907         if (taskFragment != null && taskFragment.getAdjacentTaskFragment() != null
4908                 && taskFragment.isEmbedded()) {
4909             final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
4910             final ActivityRecord r = adjacentTaskFragment.getTopNonFinishingActivity();
4911             return canShowWhenLocked(this) && canShowWhenLocked(r);
4912         } else {
4913             return canShowWhenLocked(this);
4914         }
4915     }
4916 
4917     /**
4918      * @return Whether we are allowed to show non-starting windows at the moment.
4919      */
canShowWindows()4920     boolean canShowWindows() {
4921         return mTransitionController.isShellTransitionsEnabled()
4922                 ? mSyncState != SYNC_STATE_WAITING_FOR_DRAW : allDrawn;
4923     }
4924 
4925     @Override
forAllActivities(Predicate<ActivityRecord> callback, boolean traverseTopToBottom)4926     boolean forAllActivities(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) {
4927         return callback.test(this);
4928     }
4929 
4930     @Override
forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom)4931     void forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom) {
4932         callback.accept(this);
4933     }
4934 
4935     @Override
getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom, ActivityRecord boundary)4936     ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom,
4937             ActivityRecord boundary) {
4938         return callback.test(this) ? this : null;
4939     }
4940 
logStartActivity(int tag, Task task)4941     void logStartActivity(int tag, Task task) {
4942         final Uri data = intent.getData();
4943         final String strData = data != null ? data.toSafeString() : null;
4944 
4945         EventLog.writeEvent(tag,
4946                 mUserId, System.identityHashCode(this), task.mTaskId,
4947                 shortComponentName, intent.getAction(),
4948                 intent.getType(), strData, intent.getFlags());
4949     }
4950 
getUriPermissionsLocked()4951     UriPermissionOwner getUriPermissionsLocked() {
4952         if (uriPermissions == null) {
4953             uriPermissions = new UriPermissionOwner(mAtmService.mUgmInternal, this);
4954         }
4955         return uriPermissions;
4956     }
4957 
addResultLocked(ActivityRecord from, String resultWho, int requestCode, int resultCode, Intent resultData, IBinder callerToken)4958     void addResultLocked(ActivityRecord from, String resultWho,
4959             int requestCode, int resultCode,
4960             Intent resultData, IBinder callerToken) {
4961         ActivityResult r = new ActivityResult(from, resultWho,
4962                 requestCode, resultCode, resultData, callerToken);
4963         if (results == null) {
4964             results = new ArrayList<ResultInfo>();
4965         }
4966         results.add(r);
4967     }
4968 
removeResultsLocked(ActivityRecord from, String resultWho, int requestCode)4969     void removeResultsLocked(ActivityRecord from, String resultWho,
4970             int requestCode) {
4971         if (results != null) {
4972             for (int i=results.size()-1; i>=0; i--) {
4973                 ActivityResult r = (ActivityResult)results.get(i);
4974                 if (r.mFrom != from) continue;
4975                 if (r.mResultWho == null) {
4976                     if (resultWho != null) continue;
4977                 } else {
4978                     if (!r.mResultWho.equals(resultWho)) continue;
4979                 }
4980                 if (r.mRequestCode != requestCode) continue;
4981 
4982                 results.remove(i);
4983             }
4984         }
4985     }
4986 
sendResult(int callingUid, String resultWho, int requestCode, int resultCode, Intent data, IBinder callerToken, NeededUriGrants dataGrants)4987     void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
4988             Intent data, IBinder callerToken, NeededUriGrants dataGrants) {
4989         sendResult(callingUid, resultWho, requestCode, resultCode, data, callerToken, dataGrants,
4990                 false /* forceSendForMediaProjection */);
4991     }
4992 
sendResult(int callingUid, String resultWho, int requestCode, int resultCode, Intent data, IBinder callerToken, NeededUriGrants dataGrants, boolean forceSendForMediaProjection)4993     void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
4994             Intent data, IBinder callerToken, NeededUriGrants dataGrants,
4995             boolean forceSendForMediaProjection) {
4996         if (android.security.Flags.contentUriPermissionApis()
4997                 && !mCallerState.hasCaller(callerToken)) {
4998             try {
4999                 computeCallerInfo(callerToken, data, callingUid,
5000                         mAtmService.getPackageManager().getNameForUid(callingUid),
5001                         false /* isShareIdentityEnabled */);
5002                 // Result callers cannot share their identity via
5003                 // {@link ActivityOptions#setShareIdentityEnabled(boolean)} since
5004                 // {@link android.app.Activity#setResult} doesn't have a {@link android.os.Bundle}.
5005             } catch (RemoteException e) {
5006                 throw new RuntimeException(e);
5007             }
5008         }
5009         if (callingUid > 0) {
5010             mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(dataGrants,
5011                     getUriPermissionsLocked());
5012         }
5013 
5014         if (DEBUG_RESULTS) {
5015             Slog.v(TAG, "Send activity result to " + this
5016                     + " : who=" + resultWho + " req=" + requestCode
5017                     + " res=" + resultCode + " data=" + data
5018                     + " forceSendForMediaProjection=" + forceSendForMediaProjection);
5019         }
5020 
5021         if (isState(RESUMED) && attachedToProcess()) {
5022             try {
5023                 final ArrayList<ResultInfo> list = new ArrayList<>();
5024                 list.add(new ResultInfo(resultWho, requestCode, resultCode, data, callerToken));
5025                 mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
5026                         ActivityResultItem.obtain(token, list));
5027                 return;
5028             } catch (Exception e) {
5029                 Slog.w(TAG, "Exception thrown sending result to " + this, e);
5030             }
5031         }
5032 
5033         // Schedule sending results now for Media Projection setup.
5034         if (forceSendForMediaProjection && attachedToProcess() && isState(STARTED, PAUSING, PAUSED,
5035                 STOPPING, STOPPED)) {
5036             // Build result to be returned immediately.
5037             final ActivityResultItem activityResultItem = ActivityResultItem.obtain(
5038                     token, List.of(new ResultInfo(resultWho, requestCode, resultCode, data,
5039                             callerToken)));
5040             // When the activity result is delivered, the activity will transition to RESUMED.
5041             // Since the activity is only resumed so the result can be immediately delivered,
5042             // return it to its original lifecycle state.
5043             final ActivityLifecycleItem lifecycleItem = getLifecycleItemForCurrentStateForResult();
5044             try {
5045                 if (lifecycleItem != null) {
5046                     mAtmService.getLifecycleManager().scheduleTransactionAndLifecycleItems(
5047                             app.getThread(), activityResultItem, lifecycleItem);
5048                 } else {
5049                     Slog.w(TAG, "Unable to get the lifecycle item for state " + mState
5050                             + " so couldn't immediately send result");
5051                     mAtmService.getLifecycleManager().scheduleTransactionItem(
5052                             app.getThread(), activityResultItem);
5053                 }
5054             } catch (RemoteException e) {
5055                 Slog.w(TAG, "Exception thrown sending result to " + this, e);
5056             }
5057             // We return here to ensure that result for media projection setup is not stored as a
5058             // pending result after being scheduled. This is to prevent this stored result being
5059             // sent again when the destination component is resumed.
5060             return;
5061         }
5062 
5063         addResultLocked(null /* from */, resultWho, requestCode, resultCode, data, callerToken);
5064     }
5065 
5066     /**
5067      * Provides a lifecycle item for the current stat. Only to be used when force sending an
5068      * activity result (as part of MediaProjection setup). Does not support the following states:
5069      * {@link State#INITIALIZING}, {@link State#RESTARTING_PROCESS},
5070      * {@link State#FINISHING}, {@link State#DESTROYING}, {@link State#DESTROYED}. It does not make
5071      * sense to force send a result to an activity in these states. Does not support
5072      * {@link State#RESUMED} since a resumed activity will end in the resumed state after handling
5073      * the result.
5074      *
5075      * @return an {@link ActivityLifecycleItem} for the current state, or {@code null} if the
5076      * state is not valid.
5077      */
5078     @Nullable
getLifecycleItemForCurrentStateForResult()5079     private ActivityLifecycleItem getLifecycleItemForCurrentStateForResult() {
5080         switch (mState) {
5081             case STARTED:
5082                 return StartActivityItem.obtain(token, null);
5083             case PAUSING:
5084             case PAUSED:
5085                 return PauseActivityItem.obtain(token);
5086             case STOPPING:
5087             case STOPPED:
5088                 return StopActivityItem.obtain(token);
5089             default:
5090                 // Do not send a result immediately if the activity is in state INITIALIZING,
5091                 // RESTARTING_PROCESS, FINISHING, DESTROYING, or DESTROYED.
5092                 return null;
5093         }
5094     }
5095 
addNewIntentLocked(ReferrerIntent intent)5096     private void addNewIntentLocked(ReferrerIntent intent) {
5097         if (newIntents == null) {
5098             newIntents = new ArrayList<>();
5099         }
5100         newIntents.add(intent);
5101     }
5102 
isSleeping()5103     final boolean isSleeping() {
5104         final Task rootTask = getRootTask();
5105         return rootTask != null ? rootTask.shouldSleepActivities() : mAtmService.isSleepingLocked();
5106     }
5107 
5108     /**
5109      * Deliver a new Intent to an existing activity, so that its onNewIntent()
5110      * method will be called at the proper time.
5111      */
deliverNewIntentLocked(int callingUid, Intent intent, NeededUriGrants intentGrants, String referrer, boolean isShareIdentityEnabled, int userId, int recipientAppId)5112     final void deliverNewIntentLocked(int callingUid, Intent intent, NeededUriGrants intentGrants,
5113             String referrer, boolean isShareIdentityEnabled, int userId, int recipientAppId) {
5114         IBinder callerToken = new Binder();
5115         if (android.security.Flags.contentUriPermissionApis()) {
5116             computeCallerInfo(callerToken, intent, callingUid, referrer, isShareIdentityEnabled);
5117         }
5118         // The activity now gets access to the data associated with this Intent.
5119         mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
5120                 getUriPermissionsLocked());
5121         if (isShareIdentityEnabled && android.security.Flags.contentUriPermissionApis()) {
5122             final PackageManagerInternal pmInternal = mAtmService.getPackageManagerInternalLocked();
5123             pmInternal.grantImplicitAccess(userId, intent, recipientAppId /*recipient*/,
5124                     callingUid /*visible*/, true /*direct*/);
5125         }
5126         final ReferrerIntent rintent = new ReferrerIntent(intent, getFilteredReferrer(referrer),
5127                 callerToken);
5128         boolean unsent = true;
5129         final boolean isTopActivityWhileSleeping = isTopRunningActivity() && isSleeping();
5130 
5131         // We want to immediately deliver the intent to the activity if:
5132         // - It is currently resumed or paused. i.e. it is currently visible to the user and we want
5133         //   the user to see the visual effects caused by the intent delivery now.
5134         // - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
5135         if ((mState == RESUMED || mState == PAUSED || isTopActivityWhileSleeping)
5136                 && attachedToProcess()) {
5137             try {
5138                 ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
5139                 ar.add(rintent);
5140                 // Making sure the client state is RESUMED after transaction completed and doing
5141                 // so only if activity is currently RESUMED. Otherwise, client may have extra
5142                 // life-cycle calls to RESUMED (and PAUSED later).
5143                 mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
5144                         NewIntentItem.obtain(token, ar, mState == RESUMED));
5145                 unsent = false;
5146             } catch (RemoteException e) {
5147                 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
5148             } catch (NullPointerException e) {
5149                 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
5150             }
5151         }
5152         if (unsent) {
5153             addNewIntentLocked(rintent);
5154         }
5155     }
5156 
updateOptionsLocked(ActivityOptions options)5157     void updateOptionsLocked(ActivityOptions options) {
5158         if (options != null) {
5159             if (DEBUG_TRANSITION) Slog.i(TAG, "Update options for " + this);
5160             if (mPendingOptions != null) {
5161                 mPendingOptions.abort();
5162             }
5163             setOptions(options);
5164         }
5165     }
5166 
getLaunchedFromBubble()5167     boolean getLaunchedFromBubble() {
5168         return mLaunchedFromBubble;
5169     }
5170 
setOptions(@onNull ActivityOptions options)5171     private void setOptions(@NonNull ActivityOptions options) {
5172         mLaunchedFromBubble = options.getLaunchedFromBubble();
5173         mPendingOptions = options;
5174         if (options.getAnimationType() == ANIM_REMOTE_ANIMATION) {
5175             mPendingRemoteAnimation = options.getRemoteAnimationAdapter();
5176         }
5177         mPendingRemoteTransition = options.getRemoteTransition();
5178     }
5179 
applyOptionsAnimation()5180     void applyOptionsAnimation() {
5181         if (DEBUG_TRANSITION) Slog.i(TAG, "Applying options for " + this);
5182         if (mPendingRemoteAnimation != null) {
5183             mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(
5184                     mPendingRemoteAnimation);
5185             mTransitionController.setStatusBarTransitionDelay(
5186                     mPendingRemoteAnimation.getStatusBarTransitionDelay());
5187         } else {
5188             if (mPendingOptions == null) {
5189                 return;
5190             } else if (mPendingOptions.getAnimationType() == ANIM_SCENE_TRANSITION) {
5191                 // Scene transition will run on the client side, so just notify transition
5192                 // controller but don't clear the animation information from the options since they
5193                 // need to be sent to the animating activity.
5194                 mTransitionController.setOverrideAnimation(
5195                         AnimationOptions.makeSceneTransitionAnimOptions(), null, null);
5196                 return;
5197             }
5198             applyOptionsAnimation(mPendingOptions, intent);
5199         }
5200         clearOptionsAnimationForSiblings();
5201     }
5202 
5203     /**
5204      * Apply override app transition base on options & animation type.
5205      */
applyOptionsAnimation(ActivityOptions pendingOptions, Intent intent)5206     private void applyOptionsAnimation(ActivityOptions pendingOptions, Intent intent) {
5207         final int animationType = pendingOptions.getAnimationType();
5208         final DisplayContent displayContent = getDisplayContent();
5209         AnimationOptions options = null;
5210         IRemoteCallback startCallback = null;
5211         IRemoteCallback finishCallback = null;
5212         switch (animationType) {
5213             case ANIM_CUSTOM:
5214                 displayContent.mAppTransition.overridePendingAppTransition(
5215                         pendingOptions.getPackageName(),
5216                         pendingOptions.getCustomEnterResId(),
5217                         pendingOptions.getCustomExitResId(),
5218                         pendingOptions.getCustomBackgroundColor(),
5219                         pendingOptions.getAnimationStartedListener(),
5220                         pendingOptions.getAnimationFinishedListener(),
5221                         pendingOptions.getOverrideTaskTransition());
5222                 options = AnimationOptions.makeCustomAnimOptions(pendingOptions.getPackageName(),
5223                         pendingOptions.getCustomEnterResId(), pendingOptions.getCustomExitResId(),
5224                         pendingOptions.getCustomBackgroundColor(),
5225                         pendingOptions.getOverrideTaskTransition());
5226                 startCallback = pendingOptions.getAnimationStartedListener();
5227                 finishCallback = pendingOptions.getAnimationFinishedListener();
5228                 break;
5229             case ANIM_CLIP_REVEAL:
5230                 displayContent.mAppTransition.overridePendingAppTransitionClipReveal(
5231                         pendingOptions.getStartX(), pendingOptions.getStartY(),
5232                         pendingOptions.getWidth(), pendingOptions.getHeight());
5233                 options = AnimationOptions.makeClipRevealAnimOptions(
5234                         pendingOptions.getStartX(), pendingOptions.getStartY(),
5235                         pendingOptions.getWidth(), pendingOptions.getHeight());
5236                 if (intent.getSourceBounds() == null) {
5237                     intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
5238                             pendingOptions.getStartY(),
5239                             pendingOptions.getStartX() + pendingOptions.getWidth(),
5240                             pendingOptions.getStartY() + pendingOptions.getHeight()));
5241                 }
5242                 break;
5243             case ANIM_SCALE_UP:
5244                 displayContent.mAppTransition.overridePendingAppTransitionScaleUp(
5245                         pendingOptions.getStartX(), pendingOptions.getStartY(),
5246                         pendingOptions.getWidth(), pendingOptions.getHeight());
5247                 options = AnimationOptions.makeScaleUpAnimOptions(
5248                         pendingOptions.getStartX(), pendingOptions.getStartY(),
5249                         pendingOptions.getWidth(), pendingOptions.getHeight());
5250                 if (intent.getSourceBounds() == null) {
5251                     intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
5252                             pendingOptions.getStartY(),
5253                             pendingOptions.getStartX() + pendingOptions.getWidth(),
5254                             pendingOptions.getStartY() + pendingOptions.getHeight()));
5255                 }
5256                 break;
5257             case ANIM_THUMBNAIL_SCALE_UP:
5258             case ANIM_THUMBNAIL_SCALE_DOWN:
5259                 final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP);
5260                 final HardwareBuffer buffer = pendingOptions.getThumbnail();
5261                 displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer,
5262                         pendingOptions.getStartX(), pendingOptions.getStartY(),
5263                         pendingOptions.getAnimationStartedListener(),
5264                         scaleUp);
5265                 options = AnimationOptions.makeThumbnailAnimOptions(buffer,
5266                         pendingOptions.getStartX(), pendingOptions.getStartY(), scaleUp);
5267                 startCallback = pendingOptions.getAnimationStartedListener();
5268                 if (intent.getSourceBounds() == null && buffer != null) {
5269                     intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
5270                             pendingOptions.getStartY(),
5271                             pendingOptions.getStartX() + buffer.getWidth(),
5272                             pendingOptions.getStartY() + buffer.getHeight()));
5273                 }
5274                 break;
5275             case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
5276             case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
5277                 final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
5278                 final IAppTransitionAnimationSpecsFuture specsFuture =
5279                         pendingOptions.getSpecsFuture();
5280                 if (specsFuture != null) {
5281                     displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture(
5282                             specsFuture, pendingOptions.getAnimationStartedListener(),
5283                             animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP);
5284                 } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
5285                         && specs != null) {
5286                     displayContent.mAppTransition.overridePendingAppTransitionMultiThumb(
5287                             specs, pendingOptions.getAnimationStartedListener(),
5288                             pendingOptions.getAnimationFinishedListener(), false);
5289                 } else {
5290                     displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb(
5291                             pendingOptions.getThumbnail(),
5292                             pendingOptions.getStartX(), pendingOptions.getStartY(),
5293                             pendingOptions.getWidth(), pendingOptions.getHeight(),
5294                             pendingOptions.getAnimationStartedListener(),
5295                             (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP));
5296                     if (intent.getSourceBounds() == null) {
5297                         intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
5298                                 pendingOptions.getStartY(),
5299                                 pendingOptions.getStartX() + pendingOptions.getWidth(),
5300                                 pendingOptions.getStartY() + pendingOptions.getHeight()));
5301                     }
5302                 }
5303                 break;
5304             case ANIM_OPEN_CROSS_PROFILE_APPS:
5305                 displayContent.mAppTransition
5306                         .overridePendingAppTransitionStartCrossProfileApps();
5307                 options = AnimationOptions.makeCrossProfileAnimOptions();
5308                 break;
5309             case ANIM_NONE:
5310             case ANIM_UNDEFINED:
5311                 break;
5312             default:
5313                 Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
5314                 break;
5315         }
5316 
5317         if (options != null) {
5318             mTransitionController.setOverrideAnimation(options, startCallback, finishCallback);
5319         }
5320     }
5321 
clearAllDrawn()5322     void clearAllDrawn() {
5323         allDrawn = false;
5324         mLastAllDrawn = false;
5325     }
5326 
5327     /**
5328      * Returns whether the drawn window states of this {@link ActivityRecord} has considered every
5329      * child {@link WindowState}. A child is considered if it has been passed into
5330      * {@link #updateDrawnWindowStates(WindowState)} after being added. This is used to determine
5331      * whether states, such as {@code allDrawn}, can be set, which relies on state variables such as
5332      * {@code mNumInterestingWindows}, which depend on all {@link WindowState}s being considered.
5333      *
5334      * @return {@code true} If all children have been considered, {@code false}.
5335      */
allDrawnStatesConsidered()5336     private boolean allDrawnStatesConsidered() {
5337         for (int i = mChildren.size() - 1; i >= 0; --i) {
5338             final WindowState child = mChildren.get(i);
5339             if (child.mightAffectAllDrawn() && !child.getDrawnStateEvaluated()) {
5340                 return false;
5341             }
5342         }
5343         return true;
5344     }
5345 
5346     /**
5347      *  Determines if the token has finished drawing. This should only be called from
5348      *  {@link DisplayContent#applySurfaceChangesTransaction}
5349      */
updateAllDrawn()5350     void updateAllDrawn() {
5351         if (!allDrawn) {
5352             // Number of drawn windows can be less when a window is being relaunched, wait for
5353             // all windows to be launched and drawn for this token be considered all drawn.
5354             final int numInteresting = mNumInterestingWindows;
5355 
5356             // We must make sure that all present children have been considered (determined by
5357             // {@link #allDrawnStatesConsidered}) before evaluating whether everything has been
5358             // drawn.
5359             if (numInteresting > 0 && allDrawnStatesConsidered()
5360                     && mNumDrawnWindows >= numInteresting && !isRelaunching()) {
5361                 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this
5362                         + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows);
5363                 allDrawn = true;
5364                 // Force an additional layout pass where
5365                 // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked().
5366                 if (mDisplayContent != null) {
5367                     mDisplayContent.setLayoutNeeded();
5368                 }
5369                 mWmService.mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, this).sendToTarget();
5370             }
5371         }
5372     }
5373 
abortAndClearOptionsAnimation()5374     void abortAndClearOptionsAnimation() {
5375         if (mPendingOptions != null) {
5376             mPendingOptions.abort();
5377         }
5378         clearOptionsAnimation();
5379     }
5380 
clearOptionsAnimation()5381     void clearOptionsAnimation() {
5382         mPendingOptions = null;
5383         mPendingRemoteAnimation = null;
5384         mPendingRemoteTransition = null;
5385     }
5386 
clearOptionsAnimationForSiblings()5387     void clearOptionsAnimationForSiblings() {
5388         if (task == null) {
5389             clearOptionsAnimation();
5390         } else {
5391             // This will clear the options for all the ActivityRecords for this Task.
5392             task.forAllActivities(ActivityRecord::clearOptionsAnimation);
5393         }
5394     }
5395 
getOptions()5396     ActivityOptions getOptions() {
5397         return mPendingOptions;
5398     }
5399 
takeSceneTransitionInfo()5400     ActivityOptions.SceneTransitionInfo takeSceneTransitionInfo() {
5401         if (DEBUG_TRANSITION) {
5402             Slog.i(TAG, "Taking SceneTransitionInfo for " + this + " callers="
5403                     + Debug.getCallers(6));
5404         }
5405         if (mPendingOptions == null) return null;
5406         final ActivityOptions opts = mPendingOptions;
5407         mPendingOptions = null;
5408         return opts.getSceneTransitionInfo();
5409     }
5410 
takeRemoteTransition()5411     RemoteTransition takeRemoteTransition() {
5412         RemoteTransition out = mPendingRemoteTransition;
5413         mPendingRemoteTransition = null;
5414         return out;
5415     }
5416 
allowMoveToFront()5417     boolean allowMoveToFront() {
5418         return mPendingOptions == null || !mPendingOptions.getAvoidMoveToFront();
5419     }
5420 
removeUriPermissionsLocked()5421     void removeUriPermissionsLocked() {
5422         if (uriPermissions != null) {
5423             uriPermissions.removeUriPermissions();
5424             uriPermissions = null;
5425         }
5426     }
5427 
pauseKeyDispatchingLocked()5428     void pauseKeyDispatchingLocked() {
5429         if (!keysPaused) {
5430             keysPaused = true;
5431 
5432             if (getDisplayContent() != null) {
5433                 getDisplayContent().getInputMonitor().pauseDispatchingLw(this);
5434             }
5435         }
5436     }
5437 
resumeKeyDispatchingLocked()5438     void resumeKeyDispatchingLocked() {
5439         if (keysPaused) {
5440             keysPaused = false;
5441 
5442             if (getDisplayContent() != null) {
5443                 getDisplayContent().getInputMonitor().resumeDispatchingLw(this);
5444             }
5445         }
5446     }
5447 
updateTaskDescription(CharSequence description)5448     private void updateTaskDescription(CharSequence description) {
5449         task.lastDescription = description;
5450     }
5451 
setDeferHidingClient(boolean deferHidingClient)5452     void setDeferHidingClient(boolean deferHidingClient) {
5453         if (mDeferHidingClient == deferHidingClient) {
5454             return;
5455         }
5456         mDeferHidingClient = deferHidingClient;
5457         if (!mDeferHidingClient && !mVisibleRequested) {
5458             // Hiding the client is no longer deferred and the app isn't visible still, go ahead and
5459             // update the visibility.
5460             setVisibility(false);
5461         }
5462     }
5463 
getDeferHidingClient()5464     boolean getDeferHidingClient() {
5465         return mDeferHidingClient;
5466     }
5467 
canAffectSystemUiFlags()5468     boolean canAffectSystemUiFlags() {
5469         return task != null && task.canAffectSystemUiFlags() && isVisible()
5470                 && !mWaitForEnteringPinnedMode && !inPinnedWindowingMode();
5471     }
5472 
5473     @Override
isVisible()5474     boolean isVisible() {
5475         // If the activity isn't hidden then it is considered visible and there is no need to check
5476         // its children windows to see if they are visible.
5477         return mVisible;
5478     }
5479 
setVisible(boolean visible)5480     void setVisible(boolean visible) {
5481         if (visible != mVisible) {
5482             mVisible = visible;
5483             if (app != null) {
5484                 mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
5485             }
5486             scheduleAnimation();
5487         }
5488     }
5489 
5490     /**
5491      * This is the only place that writes {@link #mVisibleRequested} (except unit test). The caller
5492      * outside of this class should use {@link #setVisibility}.
5493      */
5494     @Override
setVisibleRequested(boolean visible)5495     boolean setVisibleRequested(boolean visible) {
5496         if (!super.setVisibleRequested(visible)) return false;
5497         setInsetsFrozen(!visible);
5498         updateVisibleForServiceConnection();
5499         if (app != null) {
5500             mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
5501         }
5502         logAppCompatState();
5503         if (!visible) {
5504             final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget();
5505             mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null
5506                     && imeInputTarget.getWindowState().mActivityRecord == this
5507                     && mDisplayContent.mInputMethodWindow != null
5508                     && mDisplayContent.mInputMethodWindow.isVisible();
5509             finishOrAbortReplacingWindow();
5510         }
5511         return true;
5512     }
5513 
5514     @Override
onChildVisibleRequestedChanged(@ullable WindowContainer child)5515     protected boolean onChildVisibleRequestedChanged(@Nullable WindowContainer child) {
5516         // Activity manages visibleRequested directly (it's not determined by children)
5517         return false;
5518     }
5519 
5520     /**
5521      * Set visibility on this {@link ActivityRecord}
5522      *
5523      * <p class="note"><strong>Note: </strong>This function might not update the visibility of
5524      * this {@link ActivityRecord} immediately. In case we are preparing an app transition, we
5525      * delay changing the visibility of this {@link ActivityRecord} until we execute that
5526      * transition.</p>
5527      *
5528      * @param visible {@code true} if the {@link ActivityRecord} should become visible, otherwise
5529      *                this should become invisible.
5530      */
setVisibility(boolean visible)5531     void setVisibility(boolean visible) {
5532         if (getParent() == null) {
5533             Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
5534             return;
5535         }
5536         if (visible == mVisibleRequested && visible == mVisible && visible == isClientVisible()
5537                 && mTransitionController.isShellTransitionsEnabled()) {
5538             // For shell transition, it is no-op if there is no state change.
5539             return;
5540         }
5541         if (visible) {
5542             mDeferHidingClient = false;
5543         }
5544         setVisibility(visible, mDeferHidingClient);
5545         mAtmService.addWindowLayoutReasons(
5546                 ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED);
5547         mTaskSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
5548         mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
5549     }
5550 
setVisibility(boolean visible, boolean deferHidingClient)5551     private void setVisibility(boolean visible, boolean deferHidingClient) {
5552         final AppTransition appTransition = getDisplayContent().mAppTransition;
5553 
5554         // Don't set visibility to false if we were already not visible. This prevents WM from
5555         // adding the app to the closing app list which doesn't make sense for something that is
5556         // already not visible. However, set visibility to true even if we are already visible.
5557         // This makes sure the app is added to the opening apps list so that the right
5558         // transition can be selected.
5559         // TODO: Probably a good idea to separate the concept of opening/closing apps from the
5560         // concept of setting visibility...
5561         if (!visible && !mVisibleRequested) {
5562 
5563             if (!deferHidingClient && mLastDeferHidingClient) {
5564                 // We previously deferred telling the client to hide itself when visibility was
5565                 // initially set to false. Now we would like it to hide, so go ahead and set it.
5566                 mLastDeferHidingClient = deferHidingClient;
5567                 setClientVisible(false);
5568             }
5569             return;
5570         }
5571 
5572         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
5573                 "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
5574                 token, visible, appTransition, isVisible(), mVisibleRequested,
5575                 Debug.getCallers(6));
5576 
5577         // Before setting mVisibleRequested so we can track changes.
5578         boolean isCollecting = false;
5579         boolean inFinishingTransition = false;
5580         if (mTransitionController.isShellTransitionsEnabled()) {
5581             isCollecting = mTransitionController.isCollecting();
5582             if (isCollecting) {
5583                 mTransitionController.collect(this);
5584             } else {
5585                 // Failsafe to make sure that we show any activities that were incorrectly hidden
5586                 // during a transition. If this vis-change is a result of finishing, ignore it.
5587                 // Finish should only ever commit visibility=false, so we can check full containment
5588                 // rather than just direct membership.
5589                 inFinishingTransition = mTransitionController.inFinishingTransition(this);
5590                 if (!inFinishingTransition) {
5591                     if (visible) {
5592                         if (!mDisplayContent.isSleeping() || canShowWhenLocked()) {
5593                             mTransitionController.onVisibleWithoutCollectingTransition(this,
5594                                     Debug.getCallers(1, 1));
5595                         }
5596                     } else if (!mDisplayContent.isSleeping()) {
5597                         Slog.w(TAG, "Set invisible without transition " + this);
5598                     }
5599                 }
5600             }
5601         }
5602 
5603         onChildVisibilityRequested(visible);
5604 
5605         final DisplayContent displayContent = getDisplayContent();
5606         displayContent.mOpeningApps.remove(this);
5607         displayContent.mClosingApps.remove(this);
5608         setVisibleRequested(visible);
5609         mLastDeferHidingClient = deferHidingClient;
5610 
5611         if (!visible) {
5612             // Because starting window was transferred, this activity may be a trampoline which has
5613             // been occluded by next activity. If it has added windows, set client visibility
5614             // immediately to avoid the client getting RELAYOUT_RES_FIRST_TIME from relayout and
5615             // drawing an unnecessary frame.
5616             if (startingMoved && !firstWindowDrawn && hasChild()) {
5617                 setClientVisible(false);
5618             }
5619         } else {
5620             if (!appTransition.isTransitionSet()
5621                     && appTransition.isReady()) {
5622                 // Add the app mOpeningApps if transition is unset but ready. This means
5623                 // we're doing a screen freeze, and the unfreeze will wait for all opening
5624                 // apps to be ready.
5625                 displayContent.mOpeningApps.add(this);
5626             }
5627             startingMoved = false;
5628             // If the token is currently hidden (should be the common case), or has been
5629             // stopped, then we need to set up to wait for its windows to be ready.
5630             if (!isVisible() || mAppStopped) {
5631                 clearAllDrawn();
5632                 // Reset the draw state in order to prevent the starting window to be immediately
5633                 // dismissed when the app still has the surface.
5634                 if (!isVisible() && !isClientVisible()) {
5635                     forAllWindows(w -> {
5636                         if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
5637                             w.mWinAnimator.resetDrawState();
5638                             // Force add to mResizingWindows, so the window will report drawn.
5639                             w.forceReportingResized();
5640                         }
5641                     }, true /* traverseTopToBottom */);
5642                 }
5643             }
5644 
5645             // In the case where we are making an app visible but holding off for a transition,
5646             // we still need to tell the client to make its windows visible so they get drawn.
5647             // Otherwise, we will wait on performing the transition until all windows have been
5648             // drawn, they never will be, and we are sad.
5649             setClientVisible(true);
5650 
5651             requestUpdateWallpaperIfNeeded();
5652 
5653             ProtoLog.v(WM_DEBUG_ADD_REMOVE, "No longer Stopped: %s", this);
5654             mAppStopped = false;
5655 
5656             transferStartingWindowFromHiddenAboveTokenIfNeeded();
5657         }
5658 
5659         // Defer committing visibility until transition starts.
5660         if (isCollecting) {
5661             // It may be occluded by the activity above that calls convertFromTranslucent().
5662             // Or it may be restoring transient launch to invisible when finishing transition.
5663             if (!visible) {
5664                 if (mTransitionController.inPlayingTransition(this)) {
5665                     mTransitionChangeFlags |= FLAG_IS_OCCLUDED;
5666                 } else if (mTransitionController.inFinishingTransition(this)) {
5667                     mTransitionChangeFlags |= FLAGS_IS_OCCLUDED_NO_ANIMATION;
5668                 }
5669             } else {
5670                 mTransitionChangeFlags &= ~FLAG_IS_OCCLUDED;
5671             }
5672             return;
5673         }
5674         if (inFinishingTransition) {
5675             // Let the finishing transition commit the visibility, but let the controller know
5676             // about it so that we can recover from degenerate cases.
5677             mTransitionController.mValidateCommitVis.add(this);
5678             return;
5679         }
5680         // If we are preparing an app transition, then delay changing
5681         // the visibility of this token until we execute that transition.
5682         if (deferCommitVisibilityChange(visible)) {
5683             return;
5684         }
5685 
5686         commitVisibility(visible, true /* performLayout */);
5687         updateReportedVisibilityLocked();
5688     }
5689 
5690     /**
5691      * Returns {@code true} if this activity is either added to opening-apps or closing-apps.
5692      * Then its visibility will be committed until the transition is ready.
5693      */
deferCommitVisibilityChange(boolean visible)5694     private boolean deferCommitVisibilityChange(boolean visible) {
5695         if (mTransitionController.isShellTransitionsEnabled()) {
5696             // Shell transition doesn't use opening/closing sets.
5697             return false;
5698         }
5699         if (!mDisplayContent.mAppTransition.isTransitionSet()) {
5700             // Defer committing visibility for non-home app which is animating by recents.
5701             if (isActivityTypeHome() || !isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) {
5702                 return false;
5703             }
5704         }
5705         if (mWaitForEnteringPinnedMode && mVisible == visible) {
5706             // If the visibility is not changed during enter PIP, we don't want to include it in
5707             // app transition to affect the animation theme, because the Pip organizer will
5708             // animate the entering PIP instead.
5709             return false;
5710         }
5711 
5712         // The animation will be visible soon so do not skip by screen off.
5713         final boolean ignoreScreenOn = canTurnScreenOn() || mTaskSupervisor.getKeyguardController()
5714                 .isKeyguardGoingAway(mDisplayContent.mDisplayId);
5715         // Ignore display frozen so the opening / closing transition type can be updated correctly
5716         // even if the display is frozen. And it's safe since in applyAnimation will still check
5717         // DC#okToAnimate again if the transition animation is fine to apply.
5718         if (!okToAnimate(true /* ignoreFrozen */, ignoreScreenOn)) {
5719             return false;
5720         }
5721         if (visible) {
5722             mDisplayContent.mOpeningApps.add(this);
5723             mEnteringAnimation = true;
5724         } else if (mVisible) {
5725             mDisplayContent.mClosingApps.add(this);
5726             mEnteringAnimation = false;
5727         }
5728         if ((mDisplayContent.mAppTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0) {
5729             // Add the launching-behind activity to mOpeningApps.
5730             final WindowState win = mDisplayContent.findFocusedWindow();
5731             if (win != null) {
5732                 final ActivityRecord focusedActivity = win.mActivityRecord;
5733                 if (focusedActivity != null) {
5734                     ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
5735                             "TRANSIT_FLAG_OPEN_BEHIND,  adding %s to mOpeningApps",
5736                             focusedActivity);
5737                     // Force animation to be loaded.
5738                     mDisplayContent.mOpeningApps.add(focusedActivity);
5739                 }
5740             }
5741         }
5742         return true;
5743     }
5744 
5745     @Override
applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources)5746     boolean applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter,
5747             boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
5748         if ((mTransitionChangeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
5749             return false;
5750         }
5751         // If it was set to true, reset the last request to force the transition.
5752         mRequestForceTransition = false;
5753         return super.applyAnimation(lp, transit, enter, isVoiceInteraction, sources);
5754     }
5755 
5756     /**
5757      * Update visibility to this {@link ActivityRecord}.
5758      *
5759      * <p class="note"><strong>Note: </strong> Unlike {@link #setVisibility}, this immediately
5760      * updates the visibility without starting an app transition. Since this function may start
5761      * animation on {@link WindowState} depending on app transition animation status, an app
5762      * transition animation must be started before calling this function if necessary.</p>
5763      *
5764      * @param visible {@code true} if this {@link ActivityRecord} should become visible, otherwise
5765      *                this should become invisible.
5766      * @param performLayout if {@code true}, perform surface placement after committing visibility.
5767      * @param fromTransition {@code true} if this is part of finishing a transition.
5768      */
commitVisibility(boolean visible, boolean performLayout, boolean fromTransition)5769     void commitVisibility(boolean visible, boolean performLayout, boolean fromTransition) {
5770         // Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually
5771         // been set by the app now.
5772         mVisibleSetFromTransferredStartingWindow = false;
5773         if (visible == isVisible()) {
5774             return;
5775         }
5776 
5777         final int windowsCount = mChildren.size();
5778         // With Shell-Transition, the activity will running a transition when it is visible.
5779         // It won't be included when fromTransition is true means the call from finishTransition.
5780         final boolean runningAnimation = sEnableShellTransitions ? visible
5781                 : isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION);
5782         for (int i = 0; i < windowsCount; i++) {
5783             mChildren.get(i).onAppVisibilityChanged(visible, runningAnimation);
5784         }
5785         setVisible(visible);
5786         setVisibleRequested(visible);
5787         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "commitVisibility: %s: visible=%b"
5788                         + " visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s",
5789                 this, isVisible(), mVisibleRequested, isInTransition(), runningAnimation,
5790                 Debug.getCallers(5));
5791         if (!visible) {
5792             stopFreezingScreen(true, true);
5793         } else {
5794             // If we are being set visible, and the starting window is not yet displayed,
5795             // then make sure it doesn't get displayed.
5796             if (mStartingWindow != null && !mStartingWindow.isDrawn()
5797                     && (firstWindowDrawn || allDrawn)) {
5798                 mStartingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
5799                 mStartingWindow.mLegacyPolicyVisibilityAfterAnim = false;
5800             }
5801             // We are becoming visible, so better freeze the screen with the windows that are
5802             // getting visible so we also wait for them.
5803             forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true);
5804         }
5805         // dispatchTaskInfoChangedIfNeeded() right after ActivityRecord#setVisibility() can report
5806         // the stale visible state, because the state will be updated after the app transition.
5807         // So tries to report the actual visible state again where the state is changed.
5808         Task task = getOrganizedTask();
5809         while (task != null) {
5810             task.dispatchTaskInfoChangedIfNeeded(false /* force */);
5811             task = task.getParent().asTask();
5812         }
5813         final DisplayContent displayContent = getDisplayContent();
5814         displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
5815         if (performLayout) {
5816             mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
5817                     false /*updateInputWindows*/);
5818             mWmService.mWindowPlacerLocked.performSurfacePlacement();
5819         }
5820         displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
5821         mTransitionChangeFlags = 0;
5822 
5823         postApplyAnimation(visible, fromTransition);
5824     }
5825 
commitVisibility(boolean visible, boolean performLayout)5826     void commitVisibility(boolean visible, boolean performLayout) {
5827         commitVisibility(visible, performLayout, false /* fromTransition */);
5828     }
5829 
setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation)5830     void setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation) {
5831         mNeedsLetterboxedAnimation = needsLetterboxedAnimation;
5832     }
5833 
isNeedsLetterboxedAnimation()5834     boolean isNeedsLetterboxedAnimation() {
5835         return mNeedsLetterboxedAnimation;
5836     }
5837 
isInLetterboxAnimation()5838     boolean isInLetterboxAnimation() {
5839         return mNeedsLetterboxedAnimation && isAnimating();
5840     }
5841 
5842     /**
5843      * Post process after applying an app transition animation.
5844      *
5845      * <p class="note"><strong>Note: </strong> This function must be called after the animations
5846      * have been applied and {@link #commitVisibility}.</p>
5847      *
5848      * @param visible {@code true} if this {@link ActivityRecord} has become visible, otherwise
5849      *                this has become invisible.
5850      * @param fromTransition {@code true} if this call is part of finishing a transition. This is
5851      *                       needed because the shell transition is no-longer active by the time
5852      *                       commitVisibility is called.
5853      */
postApplyAnimation(boolean visible, boolean fromTransition)5854     private void postApplyAnimation(boolean visible, boolean fromTransition) {
5855         final boolean usingShellTransitions = mTransitionController.isShellTransitionsEnabled();
5856         final boolean delayed = !usingShellTransitions && isAnimating(PARENTS | CHILDREN,
5857                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION
5858                         | ANIMATION_TYPE_RECENTS);
5859         if (!delayed && !usingShellTransitions) {
5860             // We aren't delayed anything, but exiting windows rely on the animation finished
5861             // callback being called in case the ActivityRecord was pretending to be delayed,
5862             // which we might have done because we were in closing/opening apps list.
5863             onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, null /* AnimationAdapter */);
5864             if (visible) {
5865                 // The token was made immediately visible, there will be no entrance animation.
5866                 // We need to inform the client the enter animation was finished.
5867                 mEnteringAnimation = true;
5868                 mWmService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(
5869                         token);
5870             }
5871         }
5872 
5873         // If we're becoming visible, immediately change client visibility as well. there seem
5874         // to be some edge cases where we change our visibility but client visibility never gets
5875         // updated.
5876         // If we're becoming invisible, update the client visibility if we are not running an
5877         // animation and aren't in RESUMED state. Otherwise, we'll update client visibility in
5878         // onAnimationFinished or activityStopped.
5879         if (visible || (mState != RESUMED && (usingShellTransitions || !isAnimating(
5880                 PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)))) {
5881             setClientVisible(visible);
5882         }
5883 
5884         final DisplayContent displayContent = getDisplayContent();
5885         if (!visible) {
5886             mImeInsetsFrozenUntilStartInput = true;
5887         }
5888 
5889         if (!displayContent.mClosingApps.contains(this)
5890                 && !displayContent.mOpeningApps.contains(this)
5891                 && !fromTransition) {
5892             // Take the screenshot before possibly hiding the WSA, otherwise the screenshot
5893             // will not be taken.
5894             mWmService.mSnapshotController.notifyAppVisibilityChanged(this, visible);
5895         }
5896 
5897         // If we are hidden but there is no delay needed we immediately
5898         // apply the Surface transaction so that the ActivityManager
5899         // can have some guarantee on the Surface state following
5900         // setting the visibility. This captures cases like dismissing
5901         // the docked or root pinned task where there is no app transition.
5902         //
5903         // In the case of a "Null" animation, there will be
5904         // no animation but there will still be a transition set.
5905         // We still need to delay hiding the surface such that it
5906         // can be synchronized with showing the next surface in the transition.
5907         if (!usingShellTransitions && !isVisible() && !delayed
5908                 && !displayContent.mAppTransition.isTransitionSet()) {
5909             forAllWindows(win -> {
5910                 win.mWinAnimator.hide(getPendingTransaction(), "immediately hidden");
5911             }, true);
5912             scheduleAnimation();
5913         }
5914     }
5915 
5916     /** Updates draw state and shows drawn windows. */
commitFinishDrawing(SurfaceControl.Transaction t)5917     void commitFinishDrawing(SurfaceControl.Transaction t) {
5918         boolean committed = false;
5919         for (int i = mChildren.size() - 1; i >= 0; i--) {
5920             committed |= mChildren.get(i).commitFinishDrawing(t);
5921         }
5922         if (committed) {
5923             requestUpdateWallpaperIfNeeded();
5924         }
5925     }
5926 
5927     /**
5928      * Check if visibility of this {@link ActivityRecord} should be updated as part of an app
5929      * transition.
5930      *
5931      * <p class="note><strong>Note:</strong> If the visibility of this {@link ActivityRecord} is
5932      * already set to {@link #mVisible}, we don't need to update the visibility. So {@code false} is
5933      * returned.</p>
5934      *
5935      * @param visible {@code true} if this {@link ActivityRecord} should become visible,
5936      *                {@code false} if this should become invisible.
5937      * @return {@code true} if visibility of this {@link ActivityRecord} should be updated, and
5938      *         an app transition animation should be run.
5939      */
shouldApplyAnimation(boolean visible)5940     boolean shouldApplyAnimation(boolean visible) {
5941         // Allow for state update and animation to be applied if:
5942         // * activity is transitioning visibility state
5943         // * or the activity was marked as hidden and is exiting before we had a chance to play the
5944         // transition animation
5945         return isVisible() != visible || mRequestForceTransition || (!isVisible() && mIsExiting);
5946     }
5947 
5948     /**
5949      * See {@link Activity#setRecentsScreenshotEnabled}.
5950      */
setRecentsScreenshotEnabled(boolean enabled)5951     void setRecentsScreenshotEnabled(boolean enabled) {
5952         mEnableRecentsScreenshot = enabled;
5953     }
5954 
5955     /**
5956      * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
5957      * the case when preview screenshots are disabled {@link #setRecentsScreenshotEnabled} or when
5958      * we can't take a snapshot for other reasons, for example, if we have a secure window.
5959      *
5960      * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
5961      *         screenshot.
5962      */
shouldUseAppThemeSnapshot()5963     boolean shouldUseAppThemeSnapshot() {
5964         return !mEnableRecentsScreenshot || forAllWindows(WindowState::isSecureLocked,
5965                 true /* topToBottom */);
5966     }
5967 
5968     /**
5969      * Sets whether the current launch can turn the screen on.
5970      * @see #currentLaunchCanTurnScreenOn()
5971      */
setCurrentLaunchCanTurnScreenOn(boolean currentLaunchCanTurnScreenOn)5972     void setCurrentLaunchCanTurnScreenOn(boolean currentLaunchCanTurnScreenOn) {
5973         mCurrentLaunchCanTurnScreenOn = currentLaunchCanTurnScreenOn;
5974     }
5975 
5976     /**
5977      * Indicates whether the current launch can turn the screen on. This is to prevent multiple
5978      * relayouts from turning the screen back on. The screen should only turn on at most
5979      * once per activity resume.
5980      * <p>
5981      * Note this flag is only meaningful when {@link WindowManager.LayoutParams#FLAG_TURN_SCREEN_ON}
5982      * or {@link ActivityRecord#canTurnScreenOn} is set.
5983      *
5984      * @return {@code true} if the activity is ready to turn on the screen.
5985      */
currentLaunchCanTurnScreenOn()5986     boolean currentLaunchCanTurnScreenOn() {
5987         return mCurrentLaunchCanTurnScreenOn;
5988     }
5989 
setState(State state, String reason)5990     void setState(State state, String reason) {
5991         ProtoLog.v(WM_DEBUG_STATES, "State movement: %s from:%s to:%s reason:%s",
5992                 this, getState(), state, reason);
5993 
5994         if (state == mState) {
5995             // No need to do anything if state doesn't change.
5996             ProtoLog.v(WM_DEBUG_STATES, "State unchanged from:%s", state);
5997             return;
5998         }
5999 
6000         mState = state;
6001 
6002         if (getTaskFragment() != null) {
6003             getTaskFragment().onActivityStateChanged(this, state, reason);
6004         }
6005 
6006         // The WindowManager interprets the app stopping signal as
6007         // an indication that the Surface will eventually be destroyed.
6008         // This however isn't necessarily true if we are going to sleep.
6009         if (state == STOPPING && !isSleeping()) {
6010             if (getParent() == null) {
6011                 Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: "
6012                         + token);
6013                 return;
6014             }
6015         }
6016         updateVisibleForServiceConnection();
6017         if (app != null) {
6018             mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
6019         }
6020 
6021         switch (state) {
6022             case RESUMED:
6023                 mAtmService.updateBatteryStats(this, true);
6024                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED);
6025                 // Fall through.
6026             case STARTED:
6027                 // Update process info while making an activity from invisible to visible, to make
6028                 // sure the process state is updated to foreground.
6029                 if (app != null) {
6030                     app.updateProcessInfo(false /* updateServiceConnectionActivities */,
6031                             true /* activityChange */, true /* updateOomAdj */,
6032                             true /* addPendingTopUid */);
6033                 }
6034                 mAtmService.mH.post(this::notifyActivityStartedToContentCaptureService);
6035                 break;
6036             case PAUSED:
6037                 mAtmService.updateBatteryStats(this, false);
6038                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
6039                 break;
6040             case STOPPED:
6041                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED);
6042                 if (mDisplayContent != null) {
6043                     mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
6044                 }
6045                 break;
6046             case DESTROYED:
6047                 if (app != null && (mVisible || mVisibleRequested)) {
6048                     // The app may be died while visible (no PAUSED state).
6049                     mAtmService.updateBatteryStats(this, false);
6050                 }
6051                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED);
6052                 // Fall through.
6053             case DESTROYING:
6054                 if (app != null && !app.hasActivities()) {
6055                     // Update any services we are bound to that might care about whether
6056                     // their client may have activities.
6057                     // No longer have activities, so update LRU list and oom adj.
6058                     app.updateProcessInfo(true /* updateServiceConnectionActivities */,
6059                             false /* activityChange */, true /* updateOomAdj */,
6060                             false /* addPendingTopUid */);
6061                 }
6062                 break;
6063         }
6064     }
6065 
notifyActivityStartedToContentCaptureService()6066     private void notifyActivityStartedToContentCaptureService() {
6067         final ContentCaptureManagerInternal contentCaptureService =
6068                 LocalServices.getService(ContentCaptureManagerInternal.class);
6069         if (contentCaptureService != null) {
6070             // For ACTIVITY_STARTED content capture is directly invoked to avoid persisting
6071             // to UsageStats.
6072             contentCaptureService.notifyActivityEvent(mUserId, mActivityComponent,
6073                     ActivityEvent.TYPE_ACTIVITY_STARTED,
6074                     new ActivityId(getTask() != null ? getTask().mTaskId : INVALID_TASK_ID,
6075                             shareableActivityToken));
6076 
6077             contentCaptureService.sendActivityStartAssistData(mUserId,
6078                                 shareableActivityToken, intent);
6079         }
6080     }
6081 
getState()6082     State getState() {
6083         return mState;
6084     }
6085 
6086     /**
6087      * Returns {@code true} if the Activity is in the specified state.
6088      */
isState(State state)6089     boolean isState(State state) {
6090         return state == mState;
6091     }
6092 
6093     /**
6094      * Returns {@code true} if the Activity is in one of the specified states.
6095      */
isState(State state1, State state2)6096     boolean isState(State state1, State state2) {
6097         return state1 == mState || state2 == mState;
6098     }
6099 
6100     /**
6101      * Returns {@code true} if the Activity is in one of the specified states.
6102      */
isState(State state1, State state2, State state3)6103     boolean isState(State state1, State state2, State state3) {
6104         return state1 == mState || state2 == mState || state3 == mState;
6105     }
6106 
6107     /**
6108      * Returns {@code true} if the Activity is in one of the specified states.
6109      */
isState(State state1, State state2, State state3, State state4)6110     boolean isState(State state1, State state2, State state3, State state4) {
6111         return state1 == mState || state2 == mState || state3 == mState || state4 == mState;
6112     }
6113 
6114     /**
6115      * Returns {@code true} if the Activity is in one of the specified states.
6116      */
isState(State state1, State state2, State state3, State state4, State state5)6117     boolean isState(State state1, State state2, State state3, State state4, State state5) {
6118         return state1 == mState || state2 == mState || state3 == mState || state4 == mState
6119                 || state5 == mState;
6120     }
6121 
6122     /**
6123      * Returns {@code true} if the Activity is in one of the specified states.
6124      */
isState(State state1, State state2, State state3, State state4, State state5, State state6)6125     boolean isState(State state1, State state2, State state3, State state4, State state5,
6126             State state6) {
6127         return state1 == mState || state2 == mState || state3 == mState || state4 == mState
6128                 || state5 == mState || state6 == mState;
6129     }
6130 
destroySurfaces()6131     void destroySurfaces() {
6132         destroySurfaces(false /*cleanupOnResume*/);
6133     }
6134 
6135     /**
6136      * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure
6137      * the client has finished with them.
6138      *
6139      * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If
6140      * set to true, destroy only surfaces of removed windows, and clear relevant flags of the
6141      * others so that they are ready to be reused. If set to false (common case), destroy all
6142      * surfaces that's eligible, if the app is already stopped.
6143      */
destroySurfaces(boolean cleanupOnResume)6144     private void destroySurfaces(boolean cleanupOnResume) {
6145         boolean destroyedSomething = false;
6146 
6147         // Copying to a different list as multiple children can be removed.
6148         final ArrayList<WindowState> children = new ArrayList<>(mChildren);
6149         for (int i = children.size() - 1; i >= 0; i--) {
6150             final WindowState win = children.get(i);
6151             destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
6152         }
6153         if (destroyedSomething) {
6154             final DisplayContent dc = getDisplayContent();
6155             dc.assignWindowLayers(true /*setLayoutNeeded*/);
6156             updateLetterboxSurfaceIfNeeded(null);
6157         }
6158     }
6159 
notifyAppResumed()6160     void notifyAppResumed() {
6161         if (getParent() == null) {
6162             Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token);
6163             return;
6164         }
6165         final boolean wasStopped = mAppStopped;
6166         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppResumed: wasStopped=%b %s",
6167                 wasStopped, this);
6168         mAppStopped = false;
6169         // Allow the window to turn the screen on once the app is started and resumed.
6170         if (mAtmService.getActivityStartController().isInExecution()) {
6171             setCurrentLaunchCanTurnScreenOn(true);
6172         }
6173 
6174         if (!wasStopped) {
6175             destroySurfaces(true /*cleanupOnResume*/);
6176         }
6177     }
6178 
6179     /**
6180      * Suppress transition until the new activity becomes ready, otherwise the keyguard can appear
6181      * for a short amount of time before the new process with the new activity had the ability to
6182      * set its showWhenLocked flags.
6183      */
notifyUnknownVisibilityLaunchedForKeyguardTransition()6184     void notifyUnknownVisibilityLaunchedForKeyguardTransition() {
6185         // No display activities never add a window, so there is no point in waiting them for
6186         // relayout.
6187         if (noDisplay || !isKeyguardLocked()) {
6188             return;
6189         }
6190 
6191         mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(this);
6192     }
6193 
6194     /** @return {@code true} if this activity should be made visible. */
shouldBeVisible(boolean behindOccludedContainer, boolean ignoringKeyguard)6195     private boolean shouldBeVisible(boolean behindOccludedContainer, boolean ignoringKeyguard) {
6196         updateVisibilityIgnoringKeyguard(behindOccludedContainer);
6197 
6198         if (ignoringKeyguard) {
6199             return visibleIgnoringKeyguard;
6200         }
6201 
6202         return shouldBeVisibleUnchecked();
6203     }
6204 
shouldBeVisibleUnchecked()6205     boolean shouldBeVisibleUnchecked() {
6206         final Task rootTask = getRootTask();
6207         if (rootTask == null || !visibleIgnoringKeyguard) {
6208             return false;
6209         }
6210 
6211         // Activity in a root pinned task should not be visible if the root task is in force
6212         // hidden state.
6213         // Typically due to the FLAG_FORCE_HIDDEN_FOR_PINNED_TASK set on the root task, which is a
6214         // work around to send onStop before windowing mode change callbacks.
6215         // See also ActivityTaskSupervisor#removePinnedRootTaskInSurfaceTransaction
6216         // TODO: Should we ever be visible if the rootTask/task is invisible?
6217         if (inPinnedWindowingMode() && rootTask.isForceHidden()) {
6218             return false;
6219         }
6220 
6221         // Untrusted embedded activity can be visible only if there is no other overlay window.
6222         if (hasOverlayOverUntrustedModeEmbedded()) {
6223             return false;
6224         }
6225 
6226         // Check if the activity is on a sleeping display, canTurnScreenOn will also check
6227         // keyguard visibility
6228         if (mDisplayContent.isSleeping()) {
6229             return canTurnScreenOn();
6230         } else {
6231             return mTaskSupervisor.getKeyguardController().checkKeyguardVisibility(this);
6232         }
6233     }
6234 
6235     /**
6236      * Checks if there are any activities or other containers that belong to the same task on top of
6237      * this activity when embedded in untrusted mode.
6238      */
hasOverlayOverUntrustedModeEmbedded()6239     boolean hasOverlayOverUntrustedModeEmbedded() {
6240         if (!isEmbeddedInUntrustedMode() || getTask() == null) {
6241             // The activity is not embedded in untrusted mode.
6242             return false;
6243         }
6244 
6245         // Check if there are any activities with different UID over the activity that is embedded
6246         // in untrusted mode. Traverse bottom to top with boundary so that it will only check
6247         // activities above this activity.
6248         final ActivityRecord differentUidOverlayActivity = getTask().getActivity(
6249                 a -> !a.finishing && a.getUid() != getUid(), this /* boundary */,
6250                 false /* includeBoundary */, false /* traverseTopToBottom */);
6251         return differentUidOverlayActivity != null;
6252     }
6253 
updateVisibilityIgnoringKeyguard(boolean behindOccludedContainer)6254     void updateVisibilityIgnoringKeyguard(boolean behindOccludedContainer) {
6255         visibleIgnoringKeyguard = (!behindOccludedContainer || mLaunchTaskBehind)
6256                 && showToCurrentUser();
6257     }
6258 
shouldBeVisible()6259     boolean shouldBeVisible() {
6260         return shouldBeVisible(false /* ignoringKeyguard */);
6261     }
6262 
shouldBeVisible(boolean ignoringKeyguard)6263     boolean shouldBeVisible(boolean ignoringKeyguard) {
6264         final Task task = getTask();
6265         if (task == null) {
6266             return false;
6267         }
6268 
6269         final boolean behindOccludedContainer = !task.shouldBeVisible(null /* starting */)
6270                 || task.getOccludingActivityAbove(this) != null;
6271         return shouldBeVisible(behindOccludedContainer, ignoringKeyguard);
6272     }
6273 
makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient)6274     void makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient) {
6275         // This activity is not currently visible, but is running. Tell it to become visible.
6276         if ((mState == RESUMED && mVisibleRequested) || this == starting) {
6277             if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
6278                     "Not making visible, r=" + this + " state=" + mState + " starting=" + starting);
6279             return;
6280         }
6281 
6282         // If this activity is paused, tell it to now show its window.
6283         if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
6284                 "Making visible and scheduling visibility: " + this);
6285         final Task rootTask = getRootTask();
6286         try {
6287             if (rootTask.mTranslucentActivityWaiting != null) {
6288                 updateOptionsLocked(returningOptions);
6289                 rootTask.mUndrawnActivitiesBelowTopTranslucent.add(this);
6290             }
6291             setVisibility(true);
6292             app.postPendingUiCleanMsg(true);
6293             if (reportToClient) {
6294                 mClientVisibilityDeferred = false;
6295                 makeActiveIfNeeded(starting);
6296             } else {
6297                 mClientVisibilityDeferred = true;
6298             }
6299             // The activity may be waiting for stop, but that is no longer appropriate for it.
6300             mTaskSupervisor.mStoppingActivities.remove(this);
6301         } catch (Exception e) {
6302             // Just skip on any failure; we'll make it visible when it next restarts.
6303             Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e);
6304         }
6305         handleAlreadyVisible();
6306     }
6307 
makeInvisible()6308     void makeInvisible() {
6309         if (!mVisibleRequested) {
6310             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);
6311             return;
6312         }
6313         // Now for any activities that aren't visible to the user, make sure they no longer are
6314         // keeping the screen frozen.
6315         if (DEBUG_VISIBILITY) {
6316             Slog.v(TAG_VISIBILITY, "Making invisible: " + this + ", state=" + getState());
6317         }
6318         try {
6319             final boolean canEnterPictureInPicture = checkEnterPictureInPictureState(
6320                     "makeInvisible", true /* beforeStopping */);
6321             // Defer telling the client it is hidden if it can enter Pip and isn't current paused,
6322             // stopped or stopping. This gives it a chance to enter Pip in onPause().
6323             final boolean deferHidingClient = canEnterPictureInPicture
6324                     && !isState(STARTED, STOPPING, STOPPED, PAUSED);
6325             setDeferHidingClient(deferHidingClient);
6326             setVisibility(false);
6327 
6328             switch (getState()) {
6329                 case STOPPING:
6330                 case STOPPED:
6331                     // Reset the flag indicating that an app can enter picture-in-picture once the
6332                     // activity is hidden
6333                     supportsEnterPipOnTaskSwitch = false;
6334                     break;
6335                 case RESUMED:
6336                 case INITIALIZING:
6337                 case PAUSING:
6338                 case PAUSED:
6339                 case STARTED:
6340                     addToStopping(true /* scheduleIdle */,
6341                             canEnterPictureInPicture /* idleDelayed */, "makeInvisible");
6342                     break;
6343 
6344                 default:
6345                     break;
6346             }
6347         } catch (Exception e) {
6348             // Just skip on any failure; we'll make it visible when it next restarts.
6349             Slog.w(TAG, "Exception thrown making hidden: " + intent.getComponent(), e);
6350         }
6351     }
6352 
6353     /**
6354      * Make activity resumed or paused if needed.
6355      * @param activeActivity an activity that is resumed or just completed pause action.
6356      *                       We won't change the state of this activity.
6357      */
makeActiveIfNeeded(ActivityRecord activeActivity)6358     boolean makeActiveIfNeeded(ActivityRecord activeActivity) {
6359         if (shouldResumeActivity(activeActivity)) {
6360             if (DEBUG_VISIBILITY) {
6361                 Slog.v(TAG_VISIBILITY, "Resume visible activity, " + this);
6362             }
6363             return getRootTask().resumeTopActivityUncheckedLocked(activeActivity /* prev */,
6364                     null /* options */);
6365         } else if (shouldPauseActivity(activeActivity)) {
6366             if (DEBUG_VISIBILITY) {
6367                 Slog.v(TAG_VISIBILITY, "Pause visible activity, " + this);
6368             }
6369             // An activity must be in the {@link PAUSING} state for the system to validate
6370             // the move to {@link PAUSED}.
6371             setState(PAUSING, "makeActiveIfNeeded");
6372             EventLogTags.writeWmPauseActivity(mUserId, System.identityHashCode(this),
6373                     shortComponentName, "userLeaving=false", "make-active");
6374             try {
6375                 mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
6376                         PauseActivityItem.obtain(token, finishing, false /* userLeaving */,
6377                                 false /* dontReport */, mAutoEnteringPip));
6378             } catch (Exception e) {
6379                 Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
6380             }
6381         } else if (shouldStartActivity()) {
6382             if (DEBUG_VISIBILITY) {
6383                 Slog.v(TAG_VISIBILITY, "Start visible activity, " + this);
6384             }
6385             setState(STARTED, "makeActiveIfNeeded");
6386 
6387             try {
6388                 mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
6389                         StartActivityItem.obtain(token, takeSceneTransitionInfo()));
6390             } catch (Exception e) {
6391                 Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e);
6392             }
6393             // The activity may be waiting for stop, but that is no longer appropriate if we are
6394             // starting the activity again
6395             mTaskSupervisor.mStoppingActivities.remove(this);
6396         }
6397         return false;
6398     }
6399 
6400     /**
6401      * Check if activity should be moved to PAUSED state. The activity:
6402      * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
6403      * - should be non-focusable
6404      * - should not be currently pausing or paused
6405      * @param activeActivity the activity that is active or just completed pause action. We won't
6406      *                       resume if this activity is active.
6407      */
6408     @VisibleForTesting
shouldPauseActivity(ActivityRecord activeActivity)6409     boolean shouldPauseActivity(ActivityRecord activeActivity) {
6410         return shouldMakeActive(activeActivity) && !isFocusable() && !isState(PAUSING, PAUSED)
6411                 // We will only allow pausing if results is null, otherwise it will cause this
6412                 // activity to resume before getting result
6413                 && (results == null);
6414     }
6415 
6416     /**
6417      * Check if activity should be moved to RESUMED state.
6418      * See {@link #shouldBeResumed(ActivityRecord)}
6419      * @param activeActivity the activity that is active or just completed pause action. We won't
6420      *                       resume if this activity is active.
6421      */
6422     @VisibleForTesting
shouldResumeActivity(ActivityRecord activeActivity)6423     boolean shouldResumeActivity(ActivityRecord activeActivity) {
6424         return shouldBeResumed(activeActivity) && !isState(RESUMED);
6425     }
6426 
6427     /**
6428      * Check if activity should be RESUMED now. The activity:
6429      * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
6430      * - should be focusable
6431      */
shouldBeResumed(ActivityRecord activeActivity)6432     private boolean shouldBeResumed(ActivityRecord activeActivity) {
6433         return shouldMakeActive(activeActivity) && isFocusable()
6434                 && getTaskFragment().getVisibility(activeActivity)
6435                         == TASK_FRAGMENT_VISIBILITY_VISIBLE
6436                 && canResumeByCompat();
6437     }
6438 
6439     /**
6440      * Check if activity should be moved to STARTED state.
6441      * NOTE: This will not check if activity should be made paused or resumed first, so it must only
6442      * be called after checking with {@link #shouldResumeActivity(ActivityRecord)}
6443      * and {@link #shouldPauseActivity(ActivityRecord)}.
6444      */
shouldStartActivity()6445     private boolean shouldStartActivity() {
6446         return mVisibleRequested && (isState(STOPPED) || isState(STOPPING));
6447     }
6448 
6449     /**
6450      * Check if activity is eligible to be made active (resumed of paused). The activity:
6451      * - should be paused, stopped or stopping
6452      * - should not be the currently active one or launching behind other tasks
6453      * - should be either the topmost in task, or right below the top activity that is finishing
6454      * If all of these conditions are not met at the same time, the activity cannot be made active.
6455      */
6456     @VisibleForTesting
shouldMakeActive(ActivityRecord activeActivity)6457     boolean shouldMakeActive(ActivityRecord activeActivity) {
6458         // If the activity is stopped, stopping, cycle to an active state. We avoid doing
6459         // this when there is an activity waiting to become translucent as the extra binder
6460         // calls will lead to noticeable jank. A later call to
6461         // Task#ensureActivitiesVisible will bring the activity to a proper
6462         // active state.
6463         if (!isState(STARTED, RESUMED, PAUSED, STOPPED, STOPPING)
6464                 // TODO (b/185876784) Check could we remove the check condition
6465                 //  mTranslucentActivityWaiting != null here
6466                 || getRootTask().mTranslucentActivityWaiting != null) {
6467             return false;
6468         }
6469 
6470         if (this == activeActivity) {
6471             return false;
6472         }
6473 
6474         if (!mTaskSupervisor.readyToResume()) {
6475             // Making active is currently deferred (e.g. because an activity launch is in progress).
6476             return false;
6477         }
6478 
6479         if (this.mLaunchTaskBehind) {
6480             // This activity is being launched from behind, which means that it's not intended to be
6481             // presented to user right now, even if it's set to be visible.
6482             return false;
6483         }
6484 
6485         // Check if position in task allows to become paused
6486         if (!task.hasChild(this)) {
6487             throw new IllegalStateException("Activity not found in its task");
6488         }
6489         return getTaskFragment().topRunningActivity() == this;
6490     }
6491 
handleAlreadyVisible()6492     void handleAlreadyVisible() {
6493         try {
6494             if (returningOptions != null
6495                     && returningOptions.getAnimationType() == ANIM_SCENE_TRANSITION
6496                     && returningOptions.getSceneTransitionInfo() != null) {
6497                 app.getThread().scheduleOnNewSceneTransitionInfo(token,
6498                         returningOptions.getSceneTransitionInfo());
6499             }
6500         } catch(RemoteException e) {
6501         }
6502     }
6503 
activityResumedLocked(IBinder token, boolean handleSplashScreenExit)6504     static void activityResumedLocked(IBinder token, boolean handleSplashScreenExit) {
6505         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
6506         ProtoLog.i(WM_DEBUG_STATES, "Resumed activity; dropping state of: %s", r);
6507         if (r == null) {
6508             // If an app reports resumed after a long delay, the record on server side might have
6509             // been removed (e.g. destroy timeout), so the token could be null.
6510             return;
6511         }
6512         r.setCustomizeSplashScreenExitAnimation(handleSplashScreenExit);
6513         r.setSavedState(null /* savedState */);
6514 
6515         r.mDisplayContent.handleActivitySizeCompatModeIfNeeded(r);
6516         r.mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(r);
6517     }
6518 
activityRefreshedLocked(IBinder token)6519     static void activityRefreshedLocked(IBinder token) {
6520         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
6521         ProtoLog.i(WM_DEBUG_STATES, "Refreshed activity: %s", r);
6522         if (r == null) {
6523             // In case the record on server side has been removed (e.g. destroy timeout)
6524             // and the token could be null.
6525             return;
6526         }
6527         if (r.mDisplayContent.mActivityRefresher != null) {
6528             r.mDisplayContent.mActivityRefresher.onActivityRefreshed(r);
6529         }
6530     }
6531 
splashScreenAttachedLocked(IBinder token)6532     static void splashScreenAttachedLocked(IBinder token) {
6533         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
6534         if (r == null) {
6535             Slog.w(TAG, "splashScreenTransferredLocked cannot find activity");
6536             return;
6537         }
6538         r.onSplashScreenAttachComplete();
6539     }
6540 
6541     /**
6542      * Once we know that we have asked an application to put an activity in the resumed state
6543      * (either by launching it or explicitly telling it), this function updates the rest of our
6544      * state to match that fact.
6545      */
completeResumeLocked()6546     void completeResumeLocked() {
6547         idle = false;
6548         results = null;
6549         if (newIntents != null && newIntents.size() > 0) {
6550             mLastNewIntent = newIntents.get(newIntents.size() - 1);
6551         }
6552         newIntents = null;
6553 
6554         mTaskSupervisor.updateHomeProcessIfNeeded(this);
6555 
6556         if (nowVisible) {
6557             mTaskSupervisor.stopWaitingForActivityVisible(this);
6558         }
6559 
6560         // Schedule an idle timeout in case the app doesn't do it for us.
6561         mTaskSupervisor.scheduleIdleTimeout(this);
6562 
6563         mTaskSupervisor.reportResumedActivityLocked(this);
6564 
6565         resumeKeyDispatchingLocked();
6566         final Task rootTask = getRootTask();
6567         mTaskSupervisor.mNoAnimActivities.clear();
6568         returningOptions = null;
6569 
6570         if (canTurnScreenOn()) {
6571             mTaskSupervisor.wakeUp("turnScreenOnFlag");
6572         } else {
6573             // If the screen is going to turn on because the caller explicitly requested it and
6574             // the keyguard is not showing don't attempt to sleep. Otherwise the Activity will
6575             // pause and then resume again later, which will result in a double life-cycle event.
6576             rootTask.checkReadyForSleep();
6577         }
6578     }
6579 
activityPaused(boolean timeout)6580     void activityPaused(boolean timeout) {
6581         ProtoLog.v(WM_DEBUG_STATES, "Activity paused: token=%s, timeout=%b", token,
6582                 timeout);
6583 
6584         final TaskFragment taskFragment = getTaskFragment();
6585         if (taskFragment != null) {
6586             removePauseTimeout();
6587 
6588             final ActivityRecord pausingActivity = taskFragment.getPausingActivity();
6589             if (pausingActivity == this) {
6590                 ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s %s", this,
6591                         (timeout ? "(due to timeout)" : " (pause complete)"));
6592                 mAtmService.deferWindowLayout();
6593                 try {
6594                     taskFragment.completePause(true /* resumeNext */, null /* resumingActivity */);
6595                 } finally {
6596                     mAtmService.continueWindowLayout();
6597                 }
6598                 return;
6599             } else {
6600                 EventLogTags.writeWmFailedToPause(mUserId, System.identityHashCode(this),
6601                         shortComponentName, pausingActivity != null
6602                                 ? pausingActivity.shortComponentName : "(none)");
6603                 if (isState(PAUSING)) {
6604                     setState(PAUSED, "activityPausedLocked");
6605                     if (finishing) {
6606                         ProtoLog.v(WM_DEBUG_STATES,
6607                                 "Executing finish of failed to pause activity: %s", this);
6608                         completeFinishing("activityPausedLocked");
6609                     }
6610                 }
6611             }
6612         }
6613 
6614         mDisplayContent.handleActivitySizeCompatModeIfNeeded(this);
6615         mRootWindowContainer.ensureActivitiesVisible();
6616     }
6617 
6618     /**
6619      * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
6620      * this directly impacts the responsiveness seen by the user.
6621      */
schedulePauseTimeout()6622     void schedulePauseTimeout() {
6623         pauseTime = SystemClock.uptimeMillis();
6624         mAtmService.mH.postDelayed(mPauseTimeoutRunnable, PAUSE_TIMEOUT);
6625         ProtoLog.v(WM_DEBUG_STATES, "Waiting for pause to complete...");
6626     }
6627 
removePauseTimeout()6628     private void removePauseTimeout() {
6629         mAtmService.mH.removeCallbacks(mPauseTimeoutRunnable);
6630     }
6631 
removeDestroyTimeout()6632     private void removeDestroyTimeout() {
6633         mAtmService.mH.removeCallbacks(mDestroyTimeoutRunnable);
6634     }
6635 
removeStopTimeout()6636     private void removeStopTimeout() {
6637         mAtmService.mH.removeCallbacks(mStopTimeoutRunnable);
6638     }
6639 
removeTimeouts()6640     void removeTimeouts() {
6641         mTaskSupervisor.removeIdleTimeoutForActivity(this);
6642         removePauseTimeout();
6643         removeStopTimeout();
6644         removeDestroyTimeout();
6645         finishLaunchTickingLocked();
6646     }
6647 
stopIfPossible()6648     void stopIfPossible() {
6649         if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this);
6650         if (finishing) {
6651             Slog.e(TAG, "Request to stop a finishing activity: " + this);
6652             destroyIfPossible("stopIfPossible-finishing");
6653             return;
6654         }
6655         if (isNoHistory()) {
6656             if (!task.shouldSleepActivities()) {
6657                 ProtoLog.d(WM_DEBUG_STATES, "no-history finish of %s", this);
6658                 if (finishIfPossible("stop-no-history", false /* oomAdj */)
6659                         != FINISH_RESULT_CANCELLED) {
6660                     resumeKeyDispatchingLocked();
6661                     return;
6662                 }
6663             } else {
6664                 ProtoLog.d(WM_DEBUG_STATES, "Not finishing noHistory %s on stop "
6665                         + "because we're just sleeping", this);
6666             }
6667         }
6668 
6669         if (!attachedToProcess()) {
6670             return;
6671         }
6672         resumeKeyDispatchingLocked();
6673         try {
6674             ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPING: %s (stop requested)", this);
6675 
6676             setState(STOPPING, "stopIfPossible");
6677             if (DEBUG_VISIBILITY) {
6678                 Slog.v(TAG_VISIBILITY, "Stopping:" + this);
6679             }
6680             EventLogTags.writeWmStopActivity(
6681                     mUserId, System.identityHashCode(this), shortComponentName);
6682             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
6683                     StopActivityItem.obtain(token));
6684 
6685             mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);
6686         } catch (Exception e) {
6687             // Maybe just ignore exceptions here...  if the process has crashed, our death
6688             // notification will clean things up.
6689             Slog.w(TAG, "Exception thrown during pause", e);
6690             // Just in case, assume it to be stopped.
6691             mAppStopped = true;
6692             ProtoLog.v(WM_DEBUG_STATES, "Stop failed; moving to STOPPED: %s", this);
6693             setState(STOPPED, "stopIfPossible");
6694         }
6695     }
6696 
6697     /**
6698      * Notifies that the activity has stopped, and it is okay to destroy any surfaces which were
6699      * keeping alive in case they were still being used.
6700      */
activityStopped(Bundle newIcicle, PersistableBundle newPersistentState, CharSequence description)6701     void activityStopped(Bundle newIcicle, PersistableBundle newPersistentState,
6702             CharSequence description) {
6703         removeStopTimeout();
6704         final boolean isStopping = mState == STOPPING;
6705         if (!isStopping && mState != RESTARTING_PROCESS) {
6706             Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this + " " + mState);
6707             return;
6708         }
6709         if (newPersistentState != null) {
6710             mPersistentState = newPersistentState;
6711             mAtmService.notifyTaskPersisterLocked(task, false);
6712         }
6713 
6714         if (newIcicle != null) {
6715             // If icicle is null, this is happening due to a timeout, so we haven't really saved
6716             // the state.
6717             setSavedState(newIcicle);
6718             launchCount = 0;
6719             updateTaskDescription(description);
6720         }
6721         ProtoLog.i(WM_DEBUG_STATES, "Saving icicle of %s: %s", this, mIcicle);
6722 
6723         if (isStopping) {
6724             ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPED: %s (stop complete)", this);
6725             setState(STOPPED, "activityStopped");
6726         }
6727 
6728         mAppStopped = true;
6729         firstWindowDrawn = false;
6730         // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls
6731         // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787.
6732         // Clear any surface transactions and content overlay in this case.
6733         if (task.mLastRecentsAnimationTransaction != null) {
6734             task.clearLastRecentsAnimationTransaction(true /* forceRemoveOverlay */);
6735         }
6736         // Reset the last saved PiP snap fraction on app stop.
6737         mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
6738         if (isClientVisible()) {
6739             // Though this is usually unlikely to happen, still make sure the client is invisible.
6740             setClientVisible(false);
6741         }
6742         destroySurfaces();
6743         // Remove any starting window that was added for this app if they are still around.
6744         removeStartingWindow();
6745 
6746         if (finishing) {
6747             abortAndClearOptionsAnimation();
6748         } else {
6749             mAtmService.updatePreviousProcess(this);
6750         }
6751         mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
6752     }
6753 
addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason)6754     void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) {
6755         if (!mTaskSupervisor.mStoppingActivities.contains(this)) {
6756             EventLogTags.writeWmAddToStopping(mUserId, System.identityHashCode(this),
6757                     shortComponentName, reason);
6758             mTaskSupervisor.mStoppingActivities.add(this);
6759         }
6760 
6761         final Task rootTask = getRootTask();
6762         // If we already have a few activities waiting to stop, then give up on things going idle
6763         // and start clearing them out. Or if r is the last of activity of the last task the root
6764         // task will be empty and must be cleared immediately.
6765         boolean forceIdle = mTaskSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
6766                 || (isRootOfTask() && rootTask.getChildCount() <= 1);
6767         if (scheduleIdle || forceIdle) {
6768             ProtoLog.v(WM_DEBUG_STATES,
6769                     "Scheduling idle now: forceIdle=%b immediate=%b", forceIdle, !idleDelayed);
6770 
6771             if (!idleDelayed) {
6772                 mTaskSupervisor.scheduleIdle();
6773             } else {
6774                 mTaskSupervisor.scheduleIdleTimeout(this);
6775             }
6776         } else {
6777             rootTask.checkReadyForSleep();
6778         }
6779     }
6780 
startLaunchTickingLocked()6781     void startLaunchTickingLocked() {
6782         if (Build.IS_USER) {
6783             return;
6784         }
6785         if (launchTickTime == 0) {
6786             launchTickTime = SystemClock.uptimeMillis();
6787             continueLaunchTicking();
6788         }
6789     }
6790 
continueLaunchTicking()6791     private boolean continueLaunchTicking() {
6792         if (launchTickTime == 0) {
6793             return false;
6794         }
6795 
6796         final Task rootTask = getRootTask();
6797         if (rootTask == null) {
6798             return false;
6799         }
6800 
6801         rootTask.removeLaunchTickMessages();
6802         mAtmService.mH.postDelayed(mLaunchTickRunnable, LAUNCH_TICK);
6803         return true;
6804     }
6805 
removeLaunchTickRunnable()6806     void removeLaunchTickRunnable() {
6807         mAtmService.mH.removeCallbacks(mLaunchTickRunnable);
6808     }
6809 
finishLaunchTickingLocked()6810     void finishLaunchTickingLocked() {
6811         launchTickTime = 0;
6812         final Task rootTask = getRootTask();
6813         if (rootTask == null) {
6814             return;
6815         }
6816         rootTask.removeLaunchTickMessages();
6817     }
6818 
mayFreezeScreenLocked()6819     boolean mayFreezeScreenLocked() {
6820         return mayFreezeScreenLocked(app);
6821     }
6822 
mayFreezeScreenLocked(WindowProcessController app)6823     private boolean mayFreezeScreenLocked(WindowProcessController app) {
6824         // Only freeze the screen if this activity is currently attached to
6825         // an application, and that application is not blocked or unresponding.
6826         // In any other case, we can't count on getting the screen unfrozen,
6827         // so it is best to leave as-is.
6828         return hasProcess() && !app.isCrashing() && !app.isNotResponding();
6829     }
6830 
startFreezingScreenLocked(WindowProcessController app, int configChanges)6831     void startFreezingScreenLocked(WindowProcessController app, int configChanges) {
6832         if (mayFreezeScreenLocked(app)) {
6833             if (getParent() == null) {
6834                 Slog.w(TAG_WM,
6835                         "Attempted to freeze screen with non-existing app token: " + token);
6836                 return;
6837             }
6838 
6839             // Window configuration changes only effect windows, so don't require a screen freeze.
6840             int freezableConfigChanges = configChanges & ~(CONFIG_WINDOW_CONFIGURATION);
6841             if (freezableConfigChanges == 0 && okToDisplay()) {
6842                 ProtoLog.v(WM_DEBUG_ORIENTATION, "Skipping set freeze of %s", token);
6843                 return;
6844             }
6845 
6846             startFreezingScreen();
6847         }
6848     }
6849 
startFreezingScreen()6850     void startFreezingScreen() {
6851         startFreezingScreen(ROTATION_UNDEFINED /* overrideOriginalDisplayRotation */);
6852     }
6853 
startFreezingScreen(int overrideOriginalDisplayRotation)6854     void startFreezingScreen(int overrideOriginalDisplayRotation) {
6855         if (mTransitionController.isShellTransitionsEnabled()) {
6856             return;
6857         }
6858         ProtoLog.i(WM_DEBUG_ORIENTATION,
6859                 "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
6860                 token, isVisible(), mFreezingScreen, mVisibleRequested,
6861                 new RuntimeException().fillInStackTrace());
6862         if (!mVisibleRequested) {
6863             return;
6864         }
6865 
6866         // If the override is given, the rotation of display doesn't change but we still want to
6867         // cover the activity whose configuration is changing by freezing the display and running
6868         // the rotation animation.
6869         final boolean forceRotation = overrideOriginalDisplayRotation != ROTATION_UNDEFINED;
6870         if (!mFreezingScreen) {
6871             mFreezingScreen = true;
6872             mWmService.registerAppFreezeListener(this);
6873             mWmService.mAppsFreezingScreen++;
6874             if (mWmService.mAppsFreezingScreen == 1) {
6875                 if (forceRotation) {
6876                     // Make sure normal rotation animation will be applied.
6877                     mDisplayContent.getDisplayRotation().cancelSeamlessRotation();
6878                 }
6879                 mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */,
6880                         mDisplayContent, overrideOriginalDisplayRotation);
6881                 mWmService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
6882                 mWmService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
6883             }
6884         }
6885         if (forceRotation) {
6886             // The rotation of the real display won't change, so in order to unfreeze the screen
6887             // via {@link #checkAppWindowsReadyToShow}, the windows have to be able to call
6888             // {@link WindowState#reportResized} (it is skipped if the window is freezing) to update
6889             // the drawn state.
6890             return;
6891         }
6892         final int count = mChildren.size();
6893         for (int i = 0; i < count; i++) {
6894             final WindowState w = mChildren.get(i);
6895             w.onStartFreezingScreen();
6896         }
6897     }
6898 
isFreezingScreen()6899     boolean isFreezingScreen() {
6900         return mFreezingScreen;
6901     }
6902 
6903     @Override
onAppFreezeTimeout()6904     public void onAppFreezeTimeout() {
6905         Slog.w(TAG_WM, "Force clearing freeze: " + this);
6906         stopFreezingScreen(true, true);
6907     }
6908 
stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force)6909     void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) {
6910         if (!mFreezingScreen) {
6911             return;
6912         }
6913         ProtoLog.v(WM_DEBUG_ORIENTATION,
6914                 "Clear freezing of %s force=%b", this, force);
6915         final int count = mChildren.size();
6916         boolean unfrozeWindows = false;
6917         for (int i = 0; i < count; i++) {
6918             final WindowState w = mChildren.get(i);
6919             unfrozeWindows |= w.onStopFreezingScreen();
6920         }
6921         if (force || unfrozeWindows) {
6922             ProtoLog.v(WM_DEBUG_ORIENTATION, "No longer freezing: %s", this);
6923             mFreezingScreen = false;
6924             mWmService.unregisterAppFreezeListener(this);
6925             mWmService.mAppsFreezingScreen--;
6926             mWmService.mLastFinishedFreezeSource = this;
6927         }
6928         if (unfreezeSurfaceNow) {
6929             if (unfrozeWindows) {
6930                 mWmService.mWindowPlacerLocked.performSurfacePlacement();
6931             }
6932             mWmService.stopFreezingDisplayLocked();
6933         }
6934     }
6935 
onFirstWindowDrawn(WindowState win)6936     void onFirstWindowDrawn(WindowState win) {
6937         firstWindowDrawn = true;
6938         // stop tracking
6939         mSplashScreenStyleSolidColor = true;
6940 
6941         mAtmService.mBackNavigationController.removePredictiveSurfaceIfNeeded(this);
6942         if (mStartingWindow != null) {
6943             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s"
6944                     + ": first real window is shown, no animation", win.mToken);
6945             // If this initial window is animating, stop it -- we will do an animation to reveal
6946             // it from behind the starting window, so there is no need for it to also be doing its
6947             // own stuff.
6948             win.cancelAnimation();
6949         }
6950 
6951         // Remove starting window directly if is in a pure task. Otherwise if it is associated with
6952         // a task (e.g. nested task fragment), then remove only if all visible windows in the task
6953         // are drawn.
6954         final Task associatedTask = task.mSharedStartingData != null ? task : null;
6955         if (associatedTask == null) {
6956             removeStartingWindow();
6957         } else if (associatedTask.getActivity(
6958                 r -> r.isVisibleRequested() && !r.firstWindowDrawn) == null) {
6959             // The last drawn activity may not be the one that owns the starting window.
6960             final ActivityRecord r = associatedTask.topActivityContainsStartingWindow();
6961             if (r != null) {
6962                 r.removeStartingWindow();
6963             }
6964         }
6965         updateReportedVisibilityLocked();
6966     }
6967 
6968     /**
6969      * Sets whether something has been visible in the task and returns {@code true} if the state
6970      * is changed from invisible to visible.
6971      */
setTaskHasBeenVisible()6972     private boolean setTaskHasBeenVisible() {
6973         final boolean wasTaskVisible = task.getHasBeenVisible();
6974         if (wasTaskVisible) {
6975             return false;
6976         }
6977         if (inTransition()) {
6978             // The deferring will be canceled until transition is ready so it won't dispatch
6979             // intermediate states to organizer.
6980             task.setDeferTaskAppear(true);
6981         }
6982         task.setHasBeenVisible(true);
6983         return true;
6984     }
6985 
onStartingWindowDrawn()6986     void onStartingWindowDrawn() {
6987         boolean wasTaskVisible = false;
6988         if (task != null) {
6989             mSplashScreenStyleSolidColor = true;
6990             wasTaskVisible = !setTaskHasBeenVisible();
6991         }
6992 
6993         // The transition may not be executed if the starting process hasn't attached. But if the
6994         // starting window is drawn, the transition can start earlier. Exclude finishing and bubble
6995         // because it may be a trampoline.
6996         if (!wasTaskVisible && mStartingData != null && !finishing && !mLaunchedFromBubble
6997                 && mVisibleRequested && !mDisplayContent.mAppTransition.isReady()
6998                 && !mDisplayContent.mAppTransition.isRunning()
6999                 && mDisplayContent.isNextTransitionForward()) {
7000             // The pending transition state will be cleared after the transition is started, so
7001             // save the state for launching the client later (used by LaunchActivityItem).
7002             mStartingData.mIsTransitionForward = true;
7003             // Ensure that the transition can run with the latest orientation.
7004             if (this != mDisplayContent.getLastOrientationSource()) {
7005                 mDisplayContent.updateOrientation();
7006             }
7007             mDisplayContent.executeAppTransition();
7008         }
7009     }
7010 
7011     /** Called when the windows associated app window container are drawn. */
onWindowsDrawn()7012     private void onWindowsDrawn() {
7013         final TransitionInfoSnapshot info = mTaskSupervisor
7014                 .getActivityMetricsLogger().notifyWindowsDrawn(this);
7015         final boolean validInfo = info != null;
7016         final int windowsDrawnDelayMs = validInfo ? info.windowsDrawnDelayMs : INVALID_DELAY;
7017         final @WaitResult.LaunchState int launchState =
7018                 validInfo ? info.getLaunchState() : WaitResult.LAUNCH_STATE_UNKNOWN;
7019         // The activity may have been requested to be invisible (another activity has been launched)
7020         // so there is no valid info. But if it is the current top activity (e.g. sleeping), the
7021         // invalid state is still reported to make sure the waiting result is notified.
7022         if (validInfo || this == getDisplayArea().topRunningActivity()) {
7023             mTaskSupervisor.reportActivityLaunched(false /* timeout */, this,
7024                     windowsDrawnDelayMs, launchState);
7025         }
7026         finishLaunchTickingLocked();
7027         if (task != null) {
7028             setTaskHasBeenVisible();
7029         }
7030         // Clear indicated launch root task because there's no trampoline activity to expect after
7031         // the windows are drawn.
7032         mLaunchRootTask = null;
7033     }
7034 
7035     /** Called when the windows associated app window container are visible. */
onWindowsVisible()7036     void onWindowsVisible() {
7037         if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in " + token);
7038         mTaskSupervisor.stopWaitingForActivityVisible(this);
7039         if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
7040         if (!nowVisible) {
7041             nowVisible = true;
7042             lastVisibleTime = SystemClock.uptimeMillis();
7043             mAtmService.scheduleAppGcsLocked();
7044             // The nowVisible may be false in onAnimationFinished because the transition animation
7045             // was started by starting window but the main window hasn't drawn so the procedure
7046             // didn't schedule. Hence also check when nowVisible becomes true (drawn) to avoid the
7047             // closing activity having to wait until idle timeout to be stopped or destroyed if the
7048             // next activity won't report idle (e.g. repeated view animation).
7049             mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
7050 
7051             // If the activity is visible, but no windows are eligible to start input, unfreeze
7052             // to avoid permanently frozen IME insets.
7053             if (mImeInsetsFrozenUntilStartInput && getWindow(
7054                     win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags))
7055                     == null) {
7056                 mImeInsetsFrozenUntilStartInput = false;
7057             }
7058         }
7059     }
7060 
7061     /** Called when the windows associated app window container are no longer visible. */
onWindowsGone()7062     void onWindowsGone() {
7063         if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in " + token);
7064         if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
7065         nowVisible = false;
7066     }
7067 
7068     @Override
checkAppWindowsReadyToShow()7069     void checkAppWindowsReadyToShow() {
7070         if (allDrawn == mLastAllDrawn) {
7071             return;
7072         }
7073 
7074         mLastAllDrawn = allDrawn;
7075         if (!allDrawn) {
7076             return;
7077         }
7078 
7079         // The token has now changed state to having all windows shown...  what to do, what to do?
7080         if (mFreezingScreen) {
7081             showAllWindowsLocked();
7082             stopFreezingScreen(false, true);
7083             ProtoLog.i(WM_DEBUG_ORIENTATION,
7084                     "Setting mOrientationChangeComplete=true because wtoken %s "
7085                             + "numInteresting=%d numDrawn=%d",
7086                     this, mNumInterestingWindows, mNumDrawnWindows);
7087             // This will set mOrientationChangeComplete and cause a pass through layout.
7088             setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
7089                     "checkAppWindowsReadyToShow: freezingScreen");
7090         } else {
7091             setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
7092 
7093             // We can now show all of the drawn windows!
7094             if (!getDisplayContent().mOpeningApps.contains(this) && canShowWindows()) {
7095                 showAllWindowsLocked();
7096             }
7097         }
7098     }
7099 
7100     /**
7101      * This must be called while inside a transaction.
7102      */
showAllWindowsLocked()7103     void showAllWindowsLocked() {
7104         forAllWindows(windowState -> {
7105             if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState);
7106             windowState.performShowLocked();
7107         }, false /* traverseTopToBottom */);
7108     }
7109 
updateReportedVisibilityLocked()7110     void updateReportedVisibilityLocked() {
7111         if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
7112         final int count = mChildren.size();
7113 
7114         mReportedVisibilityResults.reset();
7115 
7116         for (int i = 0; i < count; i++) {
7117             final WindowState win = mChildren.get(i);
7118             win.updateReportedVisibility(mReportedVisibilityResults);
7119         }
7120 
7121         int numInteresting = mReportedVisibilityResults.numInteresting;
7122         int numVisible = mReportedVisibilityResults.numVisible;
7123         int numDrawn = mReportedVisibilityResults.numDrawn;
7124         boolean nowGone = mReportedVisibilityResults.nowGone;
7125 
7126         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
7127         boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && isVisible();
7128         if (!nowGone) {
7129             // If the app is not yet gone, then it can only become visible/drawn.
7130             if (!nowDrawn) {
7131                 nowDrawn = mReportedDrawn;
7132             }
7133             if (!nowVisible) {
7134                 nowVisible = reportedVisible;
7135             }
7136         }
7137         if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
7138                 + numInteresting + " visible=" + numVisible);
7139         if (nowDrawn != mReportedDrawn) {
7140             if (nowDrawn) {
7141                 onWindowsDrawn();
7142             }
7143             mReportedDrawn = nowDrawn;
7144         }
7145         if (nowVisible != reportedVisible) {
7146             if (DEBUG_VISIBILITY) Slog.v(TAG,
7147                     "Visibility changed in " + this + ": vis=" + nowVisible);
7148             reportedVisible = nowVisible;
7149             if (nowVisible) {
7150                 onWindowsVisible();
7151             } else {
7152                 onWindowsGone();
7153             }
7154         }
7155     }
7156 
isReportedDrawn()7157     boolean isReportedDrawn() {
7158         return mReportedDrawn;
7159     }
7160 
7161     @Override
setClientVisible(boolean clientVisible)7162     void setClientVisible(boolean clientVisible) {
7163         // TODO(shell-transitions): Remove mDeferHidingClient once everything is shell-transitions.
7164         //                          pip activities should just remain in clientVisible.
7165         if (!clientVisible && mDeferHidingClient) return;
7166         super.setClientVisible(clientVisible);
7167     }
7168 
7169     /**
7170      * Updated this app token tracking states for interesting and drawn windows based on the window.
7171      *
7172      * @return Returns true if the input window is considered interesting and drawn while all the
7173      *         windows in this app token where not considered drawn as of the last pass.
7174      */
updateDrawnWindowStates(WindowState w)7175     boolean updateDrawnWindowStates(WindowState w) {
7176         w.setDrawnStateEvaluated(true /*evaluated*/);
7177 
7178         if (DEBUG_STARTING_WINDOW_VERBOSE && w == mStartingWindow) {
7179             Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
7180                     + " allDrawn=" + allDrawn + " freezingScreen=" + mFreezingScreen);
7181         }
7182 
7183         if (allDrawn && !mFreezingScreen) {
7184             return false;
7185         }
7186 
7187         if (mLastTransactionSequence != mWmService.mTransactionSequence) {
7188             mLastTransactionSequence = mWmService.mTransactionSequence;
7189             mNumDrawnWindows = 0;
7190 
7191             // There is the main base application window, even if it is exiting, wait for it
7192             mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0;
7193         }
7194 
7195         final WindowStateAnimator winAnimator = w.mWinAnimator;
7196 
7197         boolean isInterestingAndDrawn = false;
7198 
7199         if (!allDrawn && w.mightAffectAllDrawn()) {
7200             if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
7201                 final boolean isAnimationSet = isAnimating(TRANSITION | PARENTS,
7202                         ANIMATION_TYPE_APP_TRANSITION);
7203                 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawn()
7204                         + ", isAnimationSet=" + isAnimationSet);
7205                 if (!w.isDrawn()) {
7206                     Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
7207                             + " pv=" + w.isVisibleByPolicy()
7208                             + " mDrawState=" + winAnimator.drawStateToString()
7209                             + " ph=" + w.isParentWindowHidden() + " th=" + mVisibleRequested
7210                             + " a=" + isAnimationSet);
7211                 }
7212             }
7213 
7214             if (w != mStartingWindow) {
7215                 if (w.isInteresting()) {
7216                     // Add non-main window as interesting since the main app has already been added
7217                     if (findMainWindow(false /* includeStartingApp */) != w) {
7218                         mNumInterestingWindows++;
7219                     }
7220                     if (w.isDrawn()) {
7221                         mNumDrawnWindows++;
7222 
7223                         if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
7224                             Slog.v(TAG, "tokenMayBeDrawn: "
7225                                     + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
7226                                     + " freezingScreen=" + mFreezingScreen
7227                                     + " mAppFreezing=" + w.mAppFreezing);
7228                         }
7229 
7230                         isInterestingAndDrawn = true;
7231                     }
7232                 }
7233             } else if (mStartingData != null && w.isDrawn()) {
7234                 // The starting window for this container is drawn.
7235                 mStartingData.mIsDisplayed = true;
7236             }
7237         }
7238 
7239         return isInterestingAndDrawn;
7240     }
7241 
7242     /**
7243      * Called when the input dispatching to a window associated with the app window container
7244      * timed-out.
7245      *
7246      * @param reason The reason for input dispatching time out.
7247      * @param windowPid The pid of the window input dispatching timed out on.
7248      * @return True if input dispatching should be aborted.
7249      */
inputDispatchingTimedOut(TimeoutRecord timeoutRecord, int windowPid)7250     public boolean inputDispatchingTimedOut(TimeoutRecord timeoutRecord, int windowPid) {
7251         try {
7252             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
7253                     "ActivityRecord#inputDispatchingTimedOut()");
7254             ActivityRecord anrActivity;
7255             WindowProcessController anrApp;
7256             boolean blameActivityProcess;
7257             timeoutRecord.mLatencyTracker.waitingOnGlobalLockStarted();
7258             synchronized (mAtmService.mGlobalLock) {
7259                 timeoutRecord.mLatencyTracker.waitingOnGlobalLockEnded();
7260                 anrActivity = getWaitingHistoryRecordLocked();
7261                 anrApp = app;
7262                 blameActivityProcess =  hasProcess()
7263                         && (app.getPid() == windowPid || windowPid == INVALID_PID);
7264             }
7265 
7266             if (blameActivityProcess) {
7267                 return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner,
7268                         anrActivity.shortComponentName, anrActivity.info.applicationInfo,
7269                         shortComponentName, app, false, timeoutRecord);
7270             } else {
7271                 // In this case another process added windows using this activity token.
7272                 // So, we call the generic service input dispatch timed out method so
7273                 // that the right process is blamed.
7274                 long timeoutMillis = mAtmService.mAmInternal.inputDispatchingTimedOut(
7275                         windowPid, false /* aboveSystem */, timeoutRecord);
7276                 return timeoutMillis <= 0;
7277             }
7278         } finally {
7279             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
7280         }
7281 
7282     }
7283 
getWaitingHistoryRecordLocked()7284     private ActivityRecord getWaitingHistoryRecordLocked() {
7285         // First find the real culprit...  if this activity has stopped, then the key dispatching
7286         // timeout should not be caused by this.
7287         if (mAppStopped) {
7288             final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
7289             if (rootTask == null) {
7290                 return this;
7291             }
7292             // Try to use the one which is closest to top.
7293             ActivityRecord r = rootTask.getTopResumedActivity();
7294             if (r == null) {
7295                 r = rootTask.getTopPausingActivity();
7296             }
7297             if (r != null) {
7298                 return r;
7299             }
7300         }
7301         return this;
7302     }
7303 
canBeTopRunning()7304     boolean canBeTopRunning() {
7305         return !finishing && showToCurrentUser();
7306     }
7307 
7308     /**
7309      * This method will return true if the activity is either visible, is becoming visible, is
7310      * currently pausing, or is resumed.
7311      */
isInterestingToUserLocked()7312     public boolean isInterestingToUserLocked() {
7313         return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED;
7314     }
7315 
7316     /**
7317      * Returns the task id of the activity token. If onlyRoot=true is specified, it will
7318      * return a valid id only if the activity is root or the activity is immediately above
7319      * the first non-relinquish-identity activity.
7320      * TODO(b/297476786): Clarify the use cases about when should get the bottom activity
7321      *                    or the first non-relinquish-identity activity from bottom.
7322      */
getTaskForActivityLocked(IBinder token, boolean onlyRoot)7323     static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7324         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
7325         if (r == null || r.getParent() == null) {
7326             return INVALID_TASK_ID;
7327         }
7328         final Task task = r.task;
7329         if (onlyRoot && r.compareTo(task.getRootActivity(
7330                 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)) > 0) {
7331             return INVALID_TASK_ID;
7332         }
7333         return task.mTaskId;
7334     }
7335 
isInRootTaskLocked(IBinder token)7336     static ActivityRecord isInRootTaskLocked(IBinder token) {
7337         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
7338         return (r != null) ? r.getRootTask().isInTask(r) : null;
7339     }
7340 
getRootTask(IBinder token)7341     static Task getRootTask(IBinder token) {
7342         final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
7343         if (r != null) {
7344             return r.getRootTask();
7345         }
7346         return null;
7347     }
7348 
7349     @Nullable
isInAnyTask(IBinder token)7350     static ActivityRecord isInAnyTask(IBinder token) {
7351         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
7352         return (r != null && r.isAttached()) ? r : null;
7353     }
7354 
7355     /**
7356      * @return display id to which this record is attached,
7357      *         {@link android.view.Display#INVALID_DISPLAY} if not attached.
7358      */
getDisplayId()7359     int getDisplayId() {
7360         return task != null && task.mDisplayContent != null
7361                  ? task.mDisplayContent.mDisplayId : INVALID_DISPLAY;
7362     }
7363 
isDestroyable()7364     final boolean isDestroyable() {
7365         if (finishing || !hasProcess()) {
7366             // This would be redundant.
7367             return false;
7368         }
7369         if (isState(RESUMED) || getRootTask() == null
7370                 || this == getTaskFragment().getPausingActivity()
7371                 || !mHaveState || !mAppStopped) {
7372             // We're not ready for this kind of thing.
7373             return false;
7374         }
7375         if (mVisibleRequested) {
7376             // The user would notice this!
7377             return false;
7378         }
7379         return true;
7380     }
7381 
createImageFilename(long createTime, int taskId)7382     private static String createImageFilename(long createTime, int taskId) {
7383         return String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + createTime +
7384                 IMAGE_EXTENSION;
7385     }
7386 
setTaskDescription(TaskDescription _taskDescription)7387     void setTaskDescription(TaskDescription _taskDescription) {
7388         Bitmap icon;
7389         if (_taskDescription.getIconFilename() == null &&
7390                 (icon = _taskDescription.getIcon()) != null) {
7391             final String iconFilename = createImageFilename(createTime, task.mTaskId);
7392             final File iconFile = new File(TaskPersister.getUserImagesDir(task.mUserId),
7393                     iconFilename);
7394             final String iconFilePath = iconFile.getAbsolutePath();
7395             mAtmService.getRecentTasks().saveImage(icon, iconFilePath);
7396             _taskDescription.setIconFilename(iconFilePath);
7397         }
7398         taskDescription = _taskDescription;
7399         getTask().updateTaskDescription();
7400     }
7401 
setLocusId(LocusId locusId)7402     void setLocusId(LocusId locusId) {
7403         if (Objects.equals(locusId, mLocusId)) return;
7404         mLocusId = locusId;
7405         final Task task = getTask();
7406         if (task != null) getTask().dispatchTaskInfoChangedIfNeeded(false /* force */);
7407     }
7408 
getLocusId()7409     LocusId getLocusId() {
7410         return mLocusId;
7411     }
7412 
reportScreenCaptured()7413     public void reportScreenCaptured() {
7414         if (mCaptureCallbacks != null) {
7415             final int n = mCaptureCallbacks.beginBroadcast();
7416             for (int i = 0; i < n; i++) {
7417                 IScreenCaptureObserver obs = mCaptureCallbacks.getBroadcastItem(i);
7418                 try {
7419                     obs.onScreenCaptured();
7420                 } catch (RemoteException e) {
7421                 }
7422             }
7423             mCaptureCallbacks.finishBroadcast();
7424         }
7425     }
7426 
registerCaptureObserver(IScreenCaptureObserver observer)7427     public void registerCaptureObserver(IScreenCaptureObserver observer) {
7428         synchronized (mWmService.mGlobalLock) {
7429             if (mCaptureCallbacks == null) {
7430                 mCaptureCallbacks = new RemoteCallbackList<IScreenCaptureObserver>();
7431             }
7432             mCaptureCallbacks.register(observer);
7433         }
7434     }
7435 
unregisterCaptureObserver(IScreenCaptureObserver observer)7436     public void unregisterCaptureObserver(IScreenCaptureObserver observer) {
7437         synchronized (mWmService.mGlobalLock) {
7438             if (mCaptureCallbacks != null) {
7439                 mCaptureCallbacks.unregister(observer);
7440             }
7441         }
7442     }
7443 
isRegisteredForScreenCaptureCallback()7444     boolean isRegisteredForScreenCaptureCallback() {
7445         return mCaptureCallbacks != null && mCaptureCallbacks.getRegisteredCallbackCount() > 0;
7446     }
7447 
setVoiceSessionLocked(IVoiceInteractionSession session)7448     void setVoiceSessionLocked(IVoiceInteractionSession session) {
7449         voiceSession = session;
7450         pendingVoiceInteractionStart = false;
7451     }
7452 
clearVoiceSessionLocked()7453     void clearVoiceSessionLocked() {
7454         voiceSession = null;
7455         pendingVoiceInteractionStart = false;
7456     }
7457 
showStartingWindow(boolean taskSwitch)7458     void showStartingWindow(boolean taskSwitch) {
7459         // Pass the activity which contains starting window already.
7460         final ActivityRecord prev = task.getActivity(
7461                 a -> a != this && a.mStartingData != null && a.showToCurrentUser());
7462         showStartingWindow(prev, false /* newTask */, taskSwitch, false /* startActivity */, null);
7463     }
7464 
7465     /**
7466      * Search for the candidate launching activity from currently visible activities.
7467      *
7468      * This activity could be launched from service, so we need to check whether there is existing a
7469      * foreground activity from the same process or same package.
7470      *
7471      */
searchCandidateLaunchingActivity()7472     private ActivityRecord searchCandidateLaunchingActivity() {
7473         // Get previous activity below self
7474         ActivityRecord below = task.getActivityBelow(this);
7475         if (below == null) {
7476             below = task.getParent().getActivityBelow(this);
7477         }
7478 
7479         if (below == null || below.isActivityTypeHome()) {
7480             return null;
7481         }
7482         final WindowProcessController myProcess = app != null
7483                 ? app : mAtmService.mProcessNames.get(processName, info.applicationInfo.uid);
7484         final WindowProcessController candidateProcess = below.app != null
7485                         ? below.app
7486                         : mAtmService.mProcessNames.get(below.processName,
7487                                 below.info.applicationInfo.uid);
7488         // same process or same package
7489         if (candidateProcess == myProcess
7490                 || mActivityComponent.getPackageName()
7491                 .equals(below.mActivityComponent.getPackageName())) {
7492             return below;
7493         }
7494         return null;
7495     }
7496 
isIconStylePreferred(int theme)7497     private boolean isIconStylePreferred(int theme) {
7498         if (theme == 0) {
7499             return false;
7500         }
7501         final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, theme,
7502                 R.styleable.Window, mWmService.mCurrentUserId);
7503         if (ent != null) {
7504             if (ent.array.hasValue(R.styleable.Window_windowSplashScreenBehavior)) {
7505                 return ent.array.getInt(R.styleable.Window_windowSplashScreenBehavior,
7506                         SPLASH_SCREEN_BEHAVIOR_DEFAULT)
7507                         == SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED;
7508             }
7509         }
7510         return false;
7511     }
7512 
7513     /**
7514      * @return true if a solid color splash screen must be used
7515      *         false when an icon splash screen can be used, but the final decision for whether to
7516      *               use an icon or solid color splash screen will be made by WmShell.
7517      */
shouldUseSolidColorSplashScreen(ActivityRecord sourceRecord, boolean startActivity, ActivityOptions options, int resolvedTheme)7518     private boolean shouldUseSolidColorSplashScreen(ActivityRecord sourceRecord,
7519             boolean startActivity, ActivityOptions options, int resolvedTheme) {
7520         if (sourceRecord == null && !startActivity) {
7521             // Use simple style if this activity is not top activity. This could happen when adding
7522             // a splash screen window to the warm start activity which is re-create because top is
7523             // finishing.
7524             final ActivityRecord above = task.getActivityAbove(this);
7525             if (above != null) {
7526                 return true;
7527             }
7528         }
7529 
7530         // setSplashScreenStyle decide in priority of windowSplashScreenBehavior.
7531         final int optionsStyle = options != null ? options.getSplashScreenStyle() :
7532                 SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
7533         if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR) {
7534             return true;
7535         } else if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_ICON
7536                     || isIconStylePreferred(resolvedTheme)) {
7537             return false;
7538         }
7539 
7540         // Choose the default behavior when neither the ActivityRecord nor the activity theme have
7541         // specified a splash screen style.
7542 
7543         if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME || launchedFromUid == Process.SHELL_UID) {
7544             return false;
7545         } else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) {
7546             return true;
7547         } else {
7548             // Need to check sourceRecord in case this activity is launched from a service.
7549             if (sourceRecord == null) {
7550                 sourceRecord = searchCandidateLaunchingActivity();
7551             }
7552 
7553             if (sourceRecord != null) {
7554                 return sourceRecord.mSplashScreenStyleSolidColor;
7555             }
7556 
7557             // Use an icon if the activity was launched from System for the first start.
7558             // Otherwise, must use solid color splash screen.
7559             return mLaunchSourceType != LAUNCH_SOURCE_TYPE_SYSTEM || !startActivity;
7560         }
7561     }
7562 
getSplashscreenTheme(ActivityOptions options)7563     private int getSplashscreenTheme(ActivityOptions options) {
7564         // Find the splash screen theme. User can override the persisted theme by
7565         // ActivityOptions.
7566         String splashScreenThemeResName = options != null
7567                 ? options.getSplashScreenThemeResName() : null;
7568         if (splashScreenThemeResName == null || splashScreenThemeResName.isEmpty()) {
7569             try {
7570                 splashScreenThemeResName = mAtmService.getPackageManager()
7571                         .getSplashScreenTheme(packageName, mUserId);
7572             } catch (RemoteException ignore) {
7573                 // Just use the default theme
7574             }
7575         }
7576         int splashScreenThemeResId = 0;
7577         if (splashScreenThemeResName != null && !splashScreenThemeResName.isEmpty()) {
7578             try {
7579                 final Context packageContext = mAtmService.mContext
7580                         .createPackageContext(packageName, 0);
7581                 splashScreenThemeResId = packageContext.getResources()
7582                         .getIdentifier(splashScreenThemeResName, null, null);
7583             } catch (PackageManager.NameNotFoundException
7584                     | Resources.NotFoundException ignore) {
7585                 // Just use the default theme
7586             }
7587         }
7588         return splashScreenThemeResId;
7589     }
7590 
showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, boolean startActivity, ActivityRecord sourceRecord)7591     void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
7592             boolean startActivity, ActivityRecord sourceRecord) {
7593         showStartingWindow(prev, newTask, taskSwitch, isProcessRunning(), startActivity,
7594                 sourceRecord, null /* candidateOptions */);
7595     }
7596 
7597     /**
7598      * @param prev Previous activity which contains a starting window.
7599      * @param processRunning Whether the client process is running.
7600      * @param startActivity Whether this activity is just created from starter.
7601      * @param sourceRecord The source activity which start this activity.
7602      * @param candidateOptions The options for the style of starting window.
7603      */
showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, boolean processRunning, boolean startActivity, ActivityRecord sourceRecord, ActivityOptions candidateOptions)7604     void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
7605             boolean processRunning, boolean startActivity, ActivityRecord sourceRecord,
7606             ActivityOptions candidateOptions) {
7607         if (mTaskOverlay) {
7608             // We don't show starting window for overlay activities.
7609             return;
7610         }
7611         final ActivityOptions startOptions = candidateOptions != null
7612                 ? candidateOptions : mPendingOptions;
7613         if (startOptions != null
7614                 && startOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
7615             // Don't show starting window when using shared element transition.
7616             return;
7617         }
7618 
7619         final int splashScreenTheme = startActivity ? getSplashscreenTheme(startOptions) : 0;
7620         final int resolvedTheme = evaluateStartingWindowTheme(prev, packageName, theme,
7621                 splashScreenTheme);
7622 
7623         mSplashScreenStyleSolidColor = shouldUseSolidColorSplashScreen(sourceRecord, startActivity,
7624                 startOptions, resolvedTheme);
7625 
7626         final boolean activityCreated =
7627                 mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal();
7628         // If this activity is just created and all activities below are finish, treat this
7629         // scenario as warm launch.
7630         final boolean newSingleActivity = !newTask && !activityCreated
7631                 && task.getActivity((r) -> !r.finishing && r != this) == null;
7632 
7633         final boolean scheduled = addStartingWindow(packageName, resolvedTheme,
7634                 prev, newTask || newSingleActivity, taskSwitch, processRunning,
7635                 allowTaskSnapshot(), activityCreated, mSplashScreenStyleSolidColor, allDrawn);
7636         if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) {
7637             Slog.d(TAG, "Scheduled starting window for " + this);
7638         }
7639     }
7640 
7641     /**
7642      * If any activities below the top running one are in the INITIALIZING state and they have a
7643      * starting window displayed then remove that starting window. It is possible that the activity
7644      * in this state will never resumed in which case that starting window will be orphaned.
7645      * <p>
7646      * It should only be called if this activity is behind other fullscreen activity.
7647      */
cancelInitializing()7648     void cancelInitializing() {
7649         if (mStartingData != null) {
7650             // Remove orphaned starting window.
7651             if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
7652             removeStartingWindowAnimation(false /* prepareAnimation */);
7653         }
7654         if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
7655             // Remove the unknown visibility record because an invisible activity shouldn't block
7656             // the keyguard transition.
7657             mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
7658         }
7659     }
7660 
postWindowRemoveStartingWindowCleanup(@onNull WindowState win)7661     void postWindowRemoveStartingWindowCleanup(@NonNull WindowState win) {
7662         if (mStartingWindow == win) {
7663             // This could only happen when the window is removed from hierarchy. So do not keep its
7664             // reference anymore.
7665             mStartingWindow = null;
7666             mStartingData = null;
7667             mStartingSurface = null;
7668         }
7669         if (mChildren.size() == 0 && mVisibleSetFromTransferredStartingWindow) {
7670             // We set the visible state to true for the token from a transferred starting
7671             // window. We now reset it back to false since the starting window was the last
7672             // window in the token.
7673             setVisible(false);
7674         }
7675     }
7676 
requestUpdateWallpaperIfNeeded()7677     void requestUpdateWallpaperIfNeeded() {
7678         for (int i = mChildren.size() - 1; i >= 0; i--) {
7679             final WindowState w = mChildren.get(i);
7680             w.requestUpdateWallpaperIfNeeded();
7681         }
7682     }
7683 
findMainWindow()7684     WindowState findMainWindow() {
7685         return findMainWindow(true);
7686     }
7687 
7688     /**
7689      * Finds the main window that either has type base application or application starting if
7690      * requested.
7691      *
7692      * @param includeStartingApp Allow to search application-starting windows to also be returned.
7693      * @return The main window of type base application or application starting if requested.
7694      */
findMainWindow(boolean includeStartingApp)7695     WindowState findMainWindow(boolean includeStartingApp) {
7696         WindowState candidate = null;
7697         for (int j = mChildren.size() - 1; j >= 0; --j) {
7698             final WindowState win = mChildren.get(j);
7699             final int type = win.mAttrs.type;
7700             // No need to loop through child window as base application and starting types can't be
7701             // child windows.
7702             if (type == TYPE_BASE_APPLICATION
7703                     || (includeStartingApp && type == TYPE_APPLICATION_STARTING)) {
7704                 // In cases where there are multiple windows, we prefer the non-exiting window. This
7705                 // happens for example when replacing windows during an activity relaunch. When
7706                 // constructing the animation, we want the new window, not the exiting one.
7707                 if (win.mAnimatingExit) {
7708                     candidate = win;
7709                 } else {
7710                     return win;
7711                 }
7712             }
7713         }
7714         return candidate;
7715     }
7716 
7717     @Override
needsZBoost()7718     boolean needsZBoost() {
7719         return mNeedsZBoost || super.needsZBoost();
7720     }
7721 
7722     @Override
getAnimationLeashParent()7723     public SurfaceControl getAnimationLeashParent() {
7724         // For transitions in the root pinned task (menu activity) we just let them occur as a child
7725         // of the root pinned task.
7726         // All normal app transitions take place in an animation layer which is below the root
7727         // pinned task but may be above the parent tasks of the given animating apps by default.
7728         // When a new hierarchical animation is enabled, we just let them occur as a child of the
7729         // parent task, i.e. the hierarchy of the surfaces is unchanged.
7730         if (inPinnedWindowingMode()) {
7731             return getRootTask().getSurfaceControl();
7732         } else {
7733             return super.getAnimationLeashParent();
7734         }
7735     }
7736 
7737     @VisibleForTesting
shouldAnimate()7738     boolean shouldAnimate() {
7739         return task == null || task.shouldAnimate();
7740     }
7741 
7742     /**
7743      * Creates a layer to apply crop to an animation.
7744      */
createAnimationBoundsLayer(Transaction t)7745     private SurfaceControl createAnimationBoundsLayer(Transaction t) {
7746         ProtoLog.i(WM_DEBUG_APP_TRANSITIONS_ANIM, "Creating animation bounds layer");
7747         final SurfaceControl.Builder builder = makeAnimationLeash()
7748                 .setParent(getAnimationLeashParent())
7749                 .setName(getSurfaceControl() + " - animation-bounds")
7750                 .setCallsite("ActivityRecord.createAnimationBoundsLayer");
7751         if (mNeedsLetterboxedAnimation) {
7752             // Needs to be an effect layer to support rounded corners
7753             builder.setEffectLayer();
7754         }
7755         final SurfaceControl boundsLayer = builder.build();
7756         t.show(boundsLayer);
7757         return boundsLayer;
7758     }
7759 
7760     @Override
shouldDeferAnimationFinish(Runnable endDeferFinishCallback)7761     public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
7762         return mAnimatingActivityRegistry != null
7763                 && mAnimatingActivityRegistry.notifyAboutToFinish(
7764                 this, endDeferFinishCallback);
7765     }
7766 
7767     @Override
isWaitingForTransitionStart()7768     boolean isWaitingForTransitionStart() {
7769         final DisplayContent dc = getDisplayContent();
7770         return dc != null && dc.mAppTransition.isTransitionSet()
7771                 && (dc.mOpeningApps.contains(this)
7772                 || dc.mClosingApps.contains(this)
7773                 || dc.mChangingContainers.contains(this));
7774     }
7775 
isTransitionForward()7776     boolean isTransitionForward() {
7777         return (mStartingData != null && mStartingData.mIsTransitionForward)
7778                 || mDisplayContent.isNextTransitionForward();
7779     }
7780 
7781     @Override
resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t)7782     void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) {
7783         // Noop as Activity may be offset for letterbox
7784     }
7785 
7786     @Override
onLeashAnimationStarting(Transaction t, SurfaceControl leash)7787     public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) {
7788         if (mAnimatingActivityRegistry != null) {
7789             mAnimatingActivityRegistry.notifyStarting(this);
7790         }
7791 
7792         if (mNeedsLetterboxedAnimation) {
7793             updateLetterboxSurfaceIfNeeded(findMainWindow(), t);
7794             mNeedsAnimationBoundsLayer = true;
7795         }
7796 
7797         // If the animation needs to be cropped then an animation bounds layer is created as a
7798         // child of the root pinned task or animation layer. The leash is then reparented to this
7799         // new layer.
7800         if (mNeedsAnimationBoundsLayer) {
7801             mTmpRect.setEmpty();
7802             if (getDisplayContent().mAppTransitionController.isTransitWithinTask(
7803                     getTransit(), task)) {
7804                 task.getBounds(mTmpRect);
7805             } else {
7806                 final Task rootTask = getRootTask();
7807                 if (rootTask == null) {
7808                     return;
7809                 }
7810                 // Set clip rect to root task bounds.
7811                 rootTask.getBounds(mTmpRect);
7812             }
7813             mAnimationBoundsLayer = createAnimationBoundsLayer(t);
7814 
7815             // Crop to root task bounds.
7816             t.setLayer(leash, 0);
7817             t.setLayer(mAnimationBoundsLayer, getLastLayer());
7818 
7819             if (mNeedsLetterboxedAnimation) {
7820                 final int cornerRadius = mLetterboxUiController
7821                         .getRoundedCornersRadius(findMainWindow());
7822 
7823                 final Rect letterboxInnerBounds = new Rect();
7824                 getLetterboxInnerBounds(letterboxInnerBounds);
7825 
7826                 t.setCornerRadius(mAnimationBoundsLayer, cornerRadius)
7827                         .setCrop(mAnimationBoundsLayer, letterboxInnerBounds);
7828             }
7829 
7830             // Reparent leash to animation bounds layer.
7831             t.reparent(leash, mAnimationBoundsLayer);
7832         }
7833     }
7834 
7835     @Override
showSurfaceOnCreation()7836     boolean showSurfaceOnCreation() {
7837         return false;
7838     }
7839 
7840     @Override
prepareSurfaces()7841     void prepareSurfaces() {
7842         final boolean isDecorSurfaceBoosted =
7843                 getTask() != null && getTask().isDecorSurfaceBoosted();
7844         final boolean show = (isVisible()
7845                 // Ensure that the activity content is hidden when the decor surface is boosted to
7846                 // prevent UI redressing attack.
7847                 && !isDecorSurfaceBoosted)
7848                 || isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS
7849                         | ANIMATION_TYPE_PREDICT_BACK);
7850 
7851         if (mSurfaceControl != null) {
7852             if (show && !mLastSurfaceShowing) {
7853                 getSyncTransaction().show(mSurfaceControl);
7854             } else if (!show && mLastSurfaceShowing) {
7855                 getSyncTransaction().hide(mSurfaceControl);
7856             }
7857             // Input sink surface is not a part of animation, so just apply in a steady state
7858             // (non-sync) with pending transaction.
7859             if (show && mSyncState == SYNC_STATE_NONE) {
7860                 mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getPendingTransaction());
7861             }
7862         }
7863         if (mThumbnail != null) {
7864             mThumbnail.setShowing(getPendingTransaction(), show);
7865         }
7866         mLastSurfaceShowing = show;
7867         super.prepareSurfaces();
7868     }
7869 
7870     /**
7871      * @return Whether our {@link #getSurfaceControl} is currently showing.
7872      */
isSurfaceShowing()7873     boolean isSurfaceShowing() {
7874         return mLastSurfaceShowing;
7875     }
7876 
attachThumbnailAnimation()7877     void attachThumbnailAnimation() {
7878         if (!isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
7879             return;
7880         }
7881         final HardwareBuffer thumbnailHeader =
7882                 getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(task);
7883         if (thumbnailHeader == null) {
7884             ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", task);
7885             return;
7886         }
7887         clearThumbnail();
7888         final Transaction transaction = getAnimatingContainer().getPendingTransaction();
7889         mThumbnail = new WindowContainerThumbnail(transaction, getAnimatingContainer(),
7890                 thumbnailHeader);
7891         mThumbnail.startAnimation(transaction, loadThumbnailAnimation(thumbnailHeader));
7892     }
7893 
7894     /**
7895      * Attaches a surface with a thumbnail for the
7896      * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation.
7897      */
attachCrossProfileAppsThumbnailAnimation()7898     void attachCrossProfileAppsThumbnailAnimation() {
7899         if (!isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
7900             return;
7901         }
7902         clearThumbnail();
7903 
7904         final WindowState win = findMainWindow();
7905         if (win == null) {
7906             return;
7907         }
7908         final Rect frame = win.getRelativeFrame();
7909         final Context context = mAtmService.getUiContext();
7910         final Drawable thumbnailDrawable;
7911         if (task.mUserId == mWmService.mCurrentUserId) {
7912             thumbnailDrawable = context.getDrawable(R.drawable.ic_account_circle);
7913         } else {
7914             final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
7915             thumbnailDrawable = dpm.getResources().getDrawable(
7916                     WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
7917                     () -> context.getDrawable(R.drawable.ic_corp_badge));
7918         }
7919         final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
7920                 .createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
7921         if (thumbnail == null) {
7922             return;
7923         }
7924         final Transaction transaction = getPendingTransaction();
7925         mThumbnail = new WindowContainerThumbnail(transaction, getTask(), thumbnail);
7926         final Animation animation =
7927                 getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(
7928                         frame);
7929         mThumbnail.startAnimation(transaction, animation, new Point(frame.left, frame.top));
7930     }
7931 
loadThumbnailAnimation(HardwareBuffer thumbnailHeader)7932     private Animation loadThumbnailAnimation(HardwareBuffer thumbnailHeader) {
7933         final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
7934 
7935         // If this is a multi-window scenario, we use the windows frame as
7936         // destination of the thumbnail header animation. If this is a full screen
7937         // window scenario, we use the whole display as the target.
7938         WindowState win = findMainWindow();
7939         Rect insets;
7940         Rect appRect;
7941         if (win != null) {
7942             insets = win.getInsetsStateWithVisibilityOverride().calculateInsets(
7943                     win.getFrame(), Type.systemBars(), false /* ignoreVisibility */).toRect();
7944             appRect = new Rect(win.getFrame());
7945             appRect.inset(insets);
7946         } else {
7947             insets = null;
7948             appRect = new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
7949         }
7950         final Configuration displayConfig = mDisplayContent.getConfiguration();
7951         return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
7952                 appRect, insets, thumbnailHeader, task, displayConfig.orientation);
7953     }
7954 
7955     @Override
onAnimationLeashLost(Transaction t)7956     public void onAnimationLeashLost(Transaction t) {
7957         super.onAnimationLeashLost(t);
7958         if (mAnimationBoundsLayer != null) {
7959             t.remove(mAnimationBoundsLayer);
7960             mAnimationBoundsLayer = null;
7961         }
7962 
7963         mNeedsAnimationBoundsLayer = false;
7964         if (mNeedsLetterboxedAnimation) {
7965             mNeedsLetterboxedAnimation = false;
7966             updateLetterboxSurfaceIfNeeded(findMainWindow(), t);
7967         }
7968 
7969         if (mAnimatingActivityRegistry != null) {
7970             mAnimatingActivityRegistry.notifyFinished(this);
7971         }
7972     }
7973 
7974     @Override
onAnimationFinished(@nimationType int type, AnimationAdapter anim)7975     protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
7976         super.onAnimationFinished(type, anim);
7977 
7978         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished");
7979         mTransit = TRANSIT_OLD_UNSET;
7980         mTransitFlags = 0;
7981 
7982         setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
7983                 "ActivityRecord");
7984 
7985         clearThumbnail();
7986         setClientVisible(isVisible() || mVisibleRequested);
7987 
7988         getDisplayContent().computeImeTargetIfNeeded(this);
7989 
7990         ProtoLog.v(WM_DEBUG_ANIM, "Animation done in %s"
7991                 + ": reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
7992                 this, reportedVisible, okToDisplay(), okToAnimate(),
7993                 isStartingWindowDisplayed());
7994 
7995         // clean up thumbnail window
7996         if (mThumbnail != null) {
7997             mThumbnail.destroy();
7998             mThumbnail = null;
7999         }
8000 
8001         // WindowState.onExitAnimationDone might modify the children list, so make a copy and then
8002         // traverse the copy.
8003         final ArrayList<WindowState> children = new ArrayList<>(mChildren);
8004         children.forEach(WindowState::onExitAnimationDone);
8005         // The starting window could transfer to another activity after app transition started, in
8006         // that case the latest top activity might not receive exit animation done callback if the
8007         // starting window didn't applied exit animation success. Notify animation finish to the
8008         // starting window if needed.
8009         if (task != null && startingMoved) {
8010             final WindowState transferredStarting = task.getWindow(w ->
8011                     w.mAttrs.type == TYPE_APPLICATION_STARTING);
8012             if (transferredStarting != null && transferredStarting.mAnimatingExit
8013                     && !transferredStarting.isSelfAnimating(0 /* flags */,
8014                     ANIMATION_TYPE_WINDOW_ANIMATION)) {
8015                 transferredStarting.onExitAnimationDone();
8016             }
8017         }
8018 
8019         getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
8020         scheduleAnimation();
8021 
8022         // Schedule to handle the stopping and finishing activities which the animation is done
8023         // because the activities which were animating have not been stopped yet.
8024         mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
8025         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
8026     }
8027 
clearAnimatingFlags()8028     void clearAnimatingFlags() {
8029         boolean wallpaperMightChange = false;
8030         for (int i = mChildren.size() - 1; i >= 0; i--) {
8031             final WindowState win = mChildren.get(i);
8032             wallpaperMightChange |= win.clearAnimatingFlags();
8033         }
8034         if (wallpaperMightChange) {
8035             requestUpdateWallpaperIfNeeded();
8036         }
8037     }
8038 
8039     @Override
cancelAnimation()8040     void cancelAnimation() {
8041         super.cancelAnimation();
8042         clearThumbnail();
8043     }
8044 
clearThumbnail()8045     private void clearThumbnail() {
8046         if (mThumbnail == null) {
8047             return;
8048         }
8049         mThumbnail.destroy();
8050         mThumbnail = null;
8051     }
8052 
getTransit()8053     public @TransitionOldType int getTransit() {
8054         return mTransit;
8055     }
8056 
8057 
registerRemoteAnimations(RemoteAnimationDefinition definition)8058     void registerRemoteAnimations(RemoteAnimationDefinition definition) {
8059         mRemoteAnimationDefinition = definition;
8060         if (definition != null) {
8061             definition.linkToDeath(this::unregisterRemoteAnimations);
8062         }
8063     }
8064 
unregisterRemoteAnimations()8065     void unregisterRemoteAnimations() {
8066         mRemoteAnimationDefinition = null;
8067     }
8068 
8069     @Override
getRemoteAnimationDefinition()8070     RemoteAnimationDefinition getRemoteAnimationDefinition() {
8071         return mRemoteAnimationDefinition;
8072     }
8073 
8074     @Override
applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, Configuration config)8075     void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames,
8076             Configuration config) {
8077         super.applyFixedRotationTransform(info, displayFrames, config);
8078         ensureActivityConfiguration();
8079     }
8080 
8081     /**
8082      * Returns the requested {@link Configuration.Orientation} for the current activity.
8083      */
8084     @Configuration.Orientation
8085     @Override
getRequestedConfigurationOrientation(boolean forDisplay)8086     int getRequestedConfigurationOrientation(boolean forDisplay) {
8087         return getRequestedConfigurationOrientation(forDisplay, getOverrideOrientation());
8088     }
8089 
8090     /**
8091      * Returns the requested {@link Configuration.Orientation} for the requested
8092      * {@link ActivityInfo.ScreenOrientation}.
8093      *
8094      * <p>When the current screen orientation is set to {@link SCREEN_ORIENTATION_BEHIND} it returns
8095      * the requested orientation for the activity below which is the first activity with an explicit
8096      * (different from {@link SCREEN_ORIENTATION_UNSET}) orientation which is not {@link
8097      * SCREEN_ORIENTATION_BEHIND}.
8098      */
8099     @Configuration.Orientation
getRequestedConfigurationOrientation(boolean forDisplay, @ActivityInfo.ScreenOrientation int requestedOrientation)8100     int getRequestedConfigurationOrientation(boolean forDisplay,
8101             @ActivityInfo.ScreenOrientation int requestedOrientation) {
8102         if (mTransparentPolicy.hasInheritedOrientation()) {
8103             final RootDisplayArea root = getRootDisplayArea();
8104             if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
8105                 return reverseConfigurationOrientation(
8106                         mTransparentPolicy.getInheritedOrientation());
8107             } else {
8108                 return mTransparentPolicy.getInheritedOrientation();
8109             }
8110         }
8111         if (task != null && requestedOrientation == SCREEN_ORIENTATION_BEHIND) {
8112             // We use Task here because we want to be consistent with what happens in
8113             // multi-window mode where other tasks orientations are ignored.
8114             final ActivityRecord belowCandidate = task.getActivity(
8115                     a -> a.canDefineOrientationForActivitiesAbove() /* callback */,
8116                     this /* boundary */, false /* includeBoundary */,
8117                     true /* traverseTopToBottom */);
8118             if (belowCandidate != null) {
8119                 return belowCandidate.getRequestedConfigurationOrientation(forDisplay);
8120             }
8121         }
8122         return super.getRequestedConfigurationOrientation(forDisplay, requestedOrientation);
8123     }
8124 
8125     /**
8126      * Returns the reversed configuration orientation.
8127      * @hide
8128      */
8129     @Configuration.Orientation
reverseConfigurationOrientation(@onfiguration.Orientation int orientation)8130     public static int reverseConfigurationOrientation(@Configuration.Orientation int orientation) {
8131         switch (orientation) {
8132             case ORIENTATION_LANDSCAPE:
8133                 return ORIENTATION_PORTRAIT;
8134             case ORIENTATION_PORTRAIT:
8135                 return ORIENTATION_LANDSCAPE;
8136             default:
8137                 return orientation;
8138         }
8139     }
8140 
8141     /**
8142      * Whether this activity can be used as an orientation source for activities above with
8143      * {@link SCREEN_ORIENTATION_BEHIND}.
8144      */
canDefineOrientationForActivitiesAbove()8145     boolean canDefineOrientationForActivitiesAbove() {
8146         if (finishing) {
8147             return false;
8148         }
8149         final int overrideOrientation = getOverrideOrientation();
8150         return overrideOrientation != SCREEN_ORIENTATION_UNSET
8151                 && overrideOrientation != SCREEN_ORIENTATION_BEHIND;
8152     }
8153 
8154     @Override
onCancelFixedRotationTransform(int originalDisplayRotation)8155     void onCancelFixedRotationTransform(int originalDisplayRotation) {
8156         if (this != mDisplayContent.getLastOrientationSource()) {
8157             // This activity doesn't affect display rotation.
8158             return;
8159         }
8160         final int requestedOrientation = getRequestedConfigurationOrientation();
8161         if (requestedOrientation != ORIENTATION_UNDEFINED
8162                 && requestedOrientation != mDisplayContent.getConfiguration().orientation) {
8163             // Only need to handle the activity that can be rotated with display or the activity
8164             // has requested the same orientation.
8165             return;
8166         }
8167 
8168         mDisplayContent.mPinnedTaskController.onCancelFixedRotationTransform();
8169         // Perform rotation animation according to the rotation of this activity.
8170         startFreezingScreen(originalDisplayRotation);
8171         // This activity may relaunch or perform configuration change so once it has reported drawn,
8172         // the screen can be unfrozen.
8173         ensureActivityConfiguration();
8174         if (mTransitionController.isCollecting(this)) {
8175             // In case the task was changed from PiP but still keeps old transform.
8176             task.resetSurfaceControlTransforms();
8177         }
8178     }
8179 
setRequestedOrientation(@ctivityInfo.ScreenOrientation int requestedOrientation)8180     void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
8181         if (mLetterboxUiController.shouldIgnoreRequestedOrientation(requestedOrientation)) {
8182             return;
8183         }
8184         final int originalRelaunchingCount = mPendingRelaunchCount;
8185         // This is necessary in order to avoid going into size compat mode when the orientation
8186         // change request comes from the app
8187         if (getRequestedConfigurationOrientation(false, requestedOrientation)
8188                     != getRequestedConfigurationOrientation(false /*forDisplay */)) {
8189             // Do not change the requested configuration now, because this will be done when setting
8190             // the orientation below with the new mCompatDisplayInsets
8191             clearSizeCompatModeAttributes();
8192         }
8193         ProtoLog.v(WM_DEBUG_ORIENTATION,
8194                 "Setting requested orientation %s for %s",
8195                 ActivityInfo.screenOrientationToString(requestedOrientation), this);
8196         setOrientation(requestedOrientation, this);
8197 
8198         // Push the new configuration to the requested app in case where it's not pushed, e.g. when
8199         // the request is handled at task level with letterbox.
8200         if (!getMergedOverrideConfiguration().equals(
8201                 mLastReportedConfiguration.getMergedConfiguration())) {
8202             ensureActivityConfiguration(false /* ignoreVisibility */);
8203             if (mPendingRelaunchCount > originalRelaunchingCount) {
8204                 mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(true);
8205             }
8206             if (mTransitionController.inPlayingTransition(this)) {
8207                 mTransitionController.mValidateActivityCompat.add(this);
8208             }
8209         }
8210 
8211         mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
8212                 task.mTaskId, requestedOrientation);
8213 
8214         mDisplayContent.getDisplayRotation().onSetRequestedOrientation();
8215     }
8216 
8217     /*
8218      * Called from {@link RootWindowContainer#ensureVisibilityAndConfig} to make sure the
8219      * orientation is updated before the app becomes visible.
8220      */
reportDescendantOrientationChangeIfNeeded()8221     void reportDescendantOrientationChangeIfNeeded() {
8222         // Orientation request is exposed only when we're visible. Therefore visibility change
8223         // will change requested orientation. Notify upward the hierarchy ladder to adjust
8224         // configuration. This is important to cases where activities with incompatible
8225         // orientations launch, or user goes back from an activity of bi-orientation to an
8226         // activity with specified orientation.
8227         if (onDescendantOrientationChanged(this)) {
8228             // WM Shell can show additional UI elements, e.g. a restart button for size compat mode
8229             // so ensure that WM Shell is called when an activity becomes visible.
8230             task.dispatchTaskInfoChangedIfNeeded(/* force= */ true);
8231         }
8232     }
8233 
8234     /**
8235      * Ignores the activity orientation request if the App is fixed-orientation portrait and has
8236      * ActivityEmbedding enabled and is currently running on large screen display. Or the display
8237      * could be rotated to portrait and not having large enough width for app to split.
8238      */
8239     @VisibleForTesting
shouldIgnoreOrientationRequests()8240     boolean shouldIgnoreOrientationRequests() {
8241         if (!mAppActivityEmbeddingSplitsEnabled
8242                 || !ActivityInfo.isFixedOrientationPortrait(getOverrideOrientation())
8243                 || task.inMultiWindowMode()) {
8244             return false;
8245         }
8246 
8247         return getTask().getConfiguration().smallestScreenWidthDp
8248                 >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
8249     }
8250 
8251     /**
8252      * We override because this class doesn't want its children affecting its reported orientation
8253      * in anyway.
8254      */
8255     @Override
getOrientation(int candidate)8256     int getOrientation(int candidate) {
8257         if (finishing || shouldIgnoreOrientationRequests()) {
8258             return SCREEN_ORIENTATION_UNSET;
8259         }
8260 
8261         if (candidate == SCREEN_ORIENTATION_BEHIND) {
8262             // Allow app to specify orientation regardless of its visibility state if the current
8263             // candidate want us to use orientation behind. I.e. the visible app on-top of this one
8264             // wants us to use the orientation of the app behind it.
8265             return getOverrideOrientation();
8266         }
8267 
8268         // The {@link ActivityRecord} should only specify an orientation when it is not closing.
8269         // Allowing closing {@link ActivityRecord} to participate can lead to an Activity in another
8270         // task being started in the wrong orientation during the transition.
8271         if (isVisibleRequested()) {
8272             return getOverrideOrientation();
8273         }
8274 
8275         return SCREEN_ORIENTATION_UNSET;
8276     }
8277 
8278     /**
8279      * Returns the app's preferred orientation regardless of its current visibility state taking
8280      * into account orientation per-app overrides applied by the device manufacturers.
8281      */
8282     @Override
getOverrideOrientation()8283     protected int getOverrideOrientation() {
8284         return mLetterboxUiController.overrideOrientationIfNeeded(super.getOverrideOrientation());
8285     }
8286 
8287     /**
8288      * Returns the app's preferred orientation regardless of its currently visibility state. This
8289      * is used to return a requested value to an app if they call {@link
8290      * android.app.Activity#getRequestedOrientation} since {@link #getOverrideOrientation} value
8291      * with override can confuse an app if it's different from what they requested with {@link
8292      * android.app.Activity#setRequestedOrientation}.
8293      */
8294     @ActivityInfo.ScreenOrientation
getRequestedOrientation()8295     int getRequestedOrientation() {
8296         return super.getOverrideOrientation();
8297     }
8298 
8299     /**
8300      * Set the last reported global configuration to the client. Should be called whenever a new
8301      * global configuration is sent to the client for this activity.
8302      */
setLastReportedGlobalConfiguration(@onNull Configuration config)8303     void setLastReportedGlobalConfiguration(@NonNull Configuration config) {
8304         mLastReportedConfiguration.setGlobalConfiguration(config);
8305     }
8306 
8307     /**
8308      * Set the last reported configuration to the client. Should be called whenever
8309      * a new merged configuration is sent to the client for this activity.
8310      */
setLastReportedConfiguration(@onNull Configuration global, @NonNull Configuration override)8311     void setLastReportedConfiguration(@NonNull Configuration global,
8312             @NonNull Configuration override) {
8313         mLastReportedConfiguration.setConfiguration(global, override);
8314     }
8315 
setLastReportedActivityWindowInfo(@onNull ActivityWindowInfo activityWindowInfo)8316     void setLastReportedActivityWindowInfo(@NonNull ActivityWindowInfo activityWindowInfo) {
8317         if (Flags.activityWindowInfoFlag()) {
8318             mLastReportedActivityWindowInfo.set(activityWindowInfo);
8319         }
8320     }
8321 
8322     @Nullable
getCompatDisplayInsets()8323     CompatDisplayInsets getCompatDisplayInsets() {
8324         if (mTransparentPolicy.isRunning()) {
8325             return mTransparentPolicy.getInheritedCompatDisplayInsets();
8326         }
8327         return mCompatDisplayInsets;
8328     }
8329 
8330     /**
8331      * @return The {@code true} if the current instance has {@link mCompatDisplayInsets} without
8332      * considering the inheritance implemented in {@link #getCompatDisplayInsets()}
8333      */
hasCompatDisplayInsetsWithoutInheritance()8334     boolean hasCompatDisplayInsetsWithoutInheritance() {
8335         return mCompatDisplayInsets != null;
8336     }
8337 
8338     /**
8339      * @return {@code true} if this activity is in size compatibility mode that uses the different
8340      *         density than its parent or its bounds don't fit in parent naturally.
8341      */
inSizeCompatMode()8342     boolean inSizeCompatMode() {
8343         if (mInSizeCompatModeForBounds) {
8344             return true;
8345         }
8346         if (getCompatDisplayInsets() == null || !shouldCreateCompatDisplayInsets()
8347                 // The orientation is different from parent when transforming.
8348                 || isFixedRotationTransforming()) {
8349             return false;
8350         }
8351         final Rect appBounds = getConfiguration().windowConfiguration.getAppBounds();
8352         if (appBounds == null) {
8353             // The app bounds hasn't been computed yet.
8354             return false;
8355         }
8356         final WindowContainer parent = getParent();
8357         if (parent == null) {
8358             // The parent of detached Activity can be null.
8359             return false;
8360         }
8361         final Configuration parentConfig = parent.getConfiguration();
8362         // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these
8363         // fields should be changed with density and bounds, so here only compares the most
8364         // significant field.
8365         return parentConfig.densityDpi != getConfiguration().densityDpi;
8366     }
8367 
8368     /**
8369      * Indicates the activity will keep the bounds and screen configuration when it was first
8370      * launched, no matter how its parent changes.
8371      *
8372      * <p>If {@true}, then {@link CompatDisplayInsets} will be created in {@link
8373      * #resolveOverrideConfiguration} to "freeze" activity bounds and insets.
8374      *
8375      * @return {@code true} if this activity is declared as non-resizable and fixed orientation or
8376      *         aspect ratio.
8377      */
shouldCreateCompatDisplayInsets()8378     boolean shouldCreateCompatDisplayInsets() {
8379         if (mLetterboxUiController.hasFullscreenOverride()) {
8380             // If the user has forced the applications aspect ratio to be fullscreen, don't use size
8381             // compatibility mode in any situation. The user has been warned and therefore accepts
8382             // the risk of the application misbehaving.
8383             return false;
8384         }
8385         switch (supportsSizeChanges()) {
8386             case SIZE_CHANGES_SUPPORTED_METADATA:
8387             case SIZE_CHANGES_SUPPORTED_OVERRIDE:
8388                 return false;
8389             case SIZE_CHANGES_UNSUPPORTED_OVERRIDE:
8390                 return true;
8391             default:
8392                 // Fall through
8393         }
8394         // Use root activity's info for tasks in multi-window mode, or fullscreen tasks in freeform
8395         // task display areas, to ensure visual consistency across activity launches and exits in
8396         // the same task.
8397         final TaskDisplayArea tda = getTaskDisplayArea();
8398         if (inMultiWindowMode() || (tda != null && tda.inFreeformWindowingMode())) {
8399             final ActivityRecord root = task != null ? task.getRootActivity() : null;
8400             if (root != null && root != this && !root.shouldCreateCompatDisplayInsets()) {
8401                 // If the root activity doesn't use size compatibility mode, the activities above
8402                 // are forced to be the same for consistent visual appearance.
8403                 return false;
8404             }
8405         }
8406         return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio())
8407                 // The configuration of non-standard type should be enforced by system.
8408                 // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is
8409                 // added to a task, but this function is called when resolving the launch params, at
8410                 // which point, the activity type is still undefined if it will be standard.
8411                 // For other non-standard types, the type is set in the constructor, so this should
8412                 // not be a problem.
8413                 && isActivityTypeStandardOrUndefined();
8414     }
8415 
8416     /**
8417      * Returns whether the activity supports size changes.
8418      */
8419     @ActivityInfo.SizeChangesSupportMode
supportsSizeChanges()8420     private int supportsSizeChanges() {
8421         if (mLetterboxUiController.shouldOverrideForceNonResizeApp()) {
8422             return SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
8423         }
8424 
8425         if (info.supportsSizeChanges) {
8426             return SIZE_CHANGES_SUPPORTED_METADATA;
8427         }
8428 
8429         if (mLetterboxUiController.shouldOverrideForceResizeApp()) {
8430             return SIZE_CHANGES_SUPPORTED_OVERRIDE;
8431         }
8432 
8433         return SIZE_CHANGES_UNSUPPORTED_METADATA;
8434     }
8435 
8436     @Override
hasSizeCompatBounds()8437     boolean hasSizeCompatBounds() {
8438         return mSizeCompatBounds != null;
8439     }
8440 
8441     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
updateCompatDisplayInsets()8442     private void updateCompatDisplayInsets() {
8443         if (getCompatDisplayInsets() != null || !shouldCreateCompatDisplayInsets()) {
8444             // The override configuration is set only once in size compatibility mode.
8445             return;
8446         }
8447 
8448         Configuration overrideConfig = getRequestedOverrideConfiguration();
8449         final Configuration fullConfig = getConfiguration();
8450 
8451         // Ensure the screen related fields are set. It is used to prevent activity relaunch
8452         // when moving between displays. For screenWidthDp and screenWidthDp, because they
8453         // are relative to bounds and density, they will be calculated in
8454         // {@link Task#computeConfigResourceOverrides} and the result will also be
8455         // relatively fixed.
8456         overrideConfig.colorMode = fullConfig.colorMode;
8457         overrideConfig.densityDpi = fullConfig.densityDpi;
8458         // The smallest screen width is the short side of screen bounds. Because the bounds
8459         // and density won't be changed, smallestScreenWidthDp is also fixed.
8460         overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
8461         if (ActivityInfo.isFixedOrientation(getOverrideOrientation())) {
8462             // lock rotation too. When in size-compat, onConfigurationChanged will watch for and
8463             // apply runtime rotation changes.
8464             overrideConfig.windowConfiguration.setRotation(
8465                     fullConfig.windowConfiguration.getRotation());
8466         }
8467 
8468         final Rect letterboxedContainerBounds =
8469                 mLetterboxBoundsForFixedOrientationAndAspectRatio != null
8470                         ? mLetterboxBoundsForFixedOrientationAndAspectRatio
8471                         : mLetterboxBoundsForAspectRatio;
8472         // The role of CompatDisplayInsets is like the override bounds.
8473         mCompatDisplayInsets =
8474                 new CompatDisplayInsets(
8475                         mDisplayContent, this, letterboxedContainerBounds,
8476                         mResolveConfigHint.mUseOverrideInsetsForConfig);
8477     }
8478 
clearSizeCompatModeAttributes()8479     private void clearSizeCompatModeAttributes() {
8480         mInSizeCompatModeForBounds = false;
8481         final float lastSizeCompatScale = mSizeCompatScale;
8482         mSizeCompatScale = 1f;
8483         if (mSizeCompatScale != lastSizeCompatScale) {
8484             forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */);
8485         }
8486         mSizeCompatBounds = null;
8487         mCompatDisplayInsets = null;
8488         mTransparentPolicy.clearInheritedCompatDisplayInsets();
8489     }
8490 
8491     @VisibleForTesting
clearSizeCompatMode()8492     void clearSizeCompatMode() {
8493         clearSizeCompatModeAttributes();
8494         // Clear config override in #updateCompatDisplayInsets().
8495         final int activityType = getActivityType();
8496         final Configuration overrideConfig = getRequestedOverrideConfiguration();
8497         overrideConfig.unset();
8498         // Keep the activity type which was set when attaching to a task to prevent leaving it
8499         // undefined.
8500         overrideConfig.windowConfiguration.setActivityType(activityType);
8501         onRequestedOverrideConfigurationChanged(overrideConfig);
8502     }
8503 
8504     @Override
matchParentBounds()8505     public boolean matchParentBounds() {
8506         final Rect overrideBounds = getResolvedOverrideBounds();
8507         if (overrideBounds.isEmpty()) {
8508             return true;
8509         }
8510         // An activity in size compatibility mode may have override bounds which equals to its
8511         // parent bounds, so the exact bounds should also be checked to allow IME window to attach
8512         // to the activity. See {@link DisplayContent#shouldImeAttachedToApp}.
8513         final WindowContainer parent = getParent();
8514         return parent == null || parent.getBounds().equals(overrideBounds);
8515     }
8516 
8517     @Override
getCompatScale()8518     float getCompatScale() {
8519         return hasSizeCompatBounds() ? mSizeCompatScale : super.getCompatScale();
8520     }
8521 
8522     @Override
resolveOverrideConfiguration(Configuration newParentConfiguration)8523     void resolveOverrideConfiguration(Configuration newParentConfiguration) {
8524         final Configuration requestedOverrideConfig = getRequestedOverrideConfiguration();
8525         if (requestedOverrideConfig.assetsSeq != ASSETS_SEQ_UNDEFINED
8526                 && newParentConfiguration.assetsSeq > requestedOverrideConfig.assetsSeq) {
8527             requestedOverrideConfig.assetsSeq = ASSETS_SEQ_UNDEFINED;
8528         }
8529         super.resolveOverrideConfiguration(newParentConfiguration);
8530         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
8531 
8532         applyLocaleOverrideIfNeeded(resolvedConfig);
8533 
8534         if (isFixedRotationTransforming()) {
8535             // The resolved configuration is applied with rotated display configuration. If this
8536             // activity matches its parent (the following resolving procedures are no-op), then it
8537             // can use the resolved configuration directly. Otherwise (e.g. fixed aspect ratio),
8538             // the rotated configuration is used as parent configuration to compute the actual
8539             // resolved configuration. It is like putting the activity in a rotated container.
8540             mTmpConfig.setTo(newParentConfiguration);
8541             mTmpConfig.updateFrom(resolvedConfig);
8542             newParentConfiguration = mTmpConfig;
8543         }
8544 
8545         mIsAspectRatioApplied = false;
8546         mIsEligibleForFixedOrientationLetterbox = false;
8547         mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
8548         mLetterboxBoundsForAspectRatio = null;
8549         mResolveConfigHint.resolveTmpOverrides(mDisplayContent, newParentConfiguration,
8550                 isFixedRotationTransforming());
8551 
8552         // Can't use resolvedConfig.windowConfiguration.getWindowingMode() because it can be
8553         // different from windowing mode of the task (PiP) during transition from fullscreen to PiP
8554         // and back which can cause visible issues (see b/184078928).
8555         final int parentWindowingMode =
8556                 newParentConfiguration.windowConfiguration.getWindowingMode();
8557         final boolean isInCameraCompatFreeform = parentWindowingMode == WINDOWING_MODE_FREEFORM
8558                 && mLetterboxUiController.getFreeformCameraCompatMode()
8559                         != CAMERA_COMPAT_FREEFORM_NONE;
8560 
8561         // Bubble activities should always fill their parent and should not be letterboxed.
8562         final boolean isFixedOrientationLetterboxAllowed = !getLaunchedFromBubble()
8563                 && (parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
8564                         || parentWindowingMode == WINDOWING_MODE_FULLSCREEN
8565                         || isInCameraCompatFreeform
8566                         // When starting to switch between PiP and fullscreen, the task is pinned
8567                         // and the activity is fullscreen. But only allow to apply letterbox if the
8568                         // activity is exiting PiP because an entered PiP should fill the task.
8569                         || (!mWaitForEnteringPinnedMode
8570                                 && parentWindowingMode == WINDOWING_MODE_PINNED
8571                                 && resolvedConfig.windowConfiguration.getWindowingMode()
8572                                         == WINDOWING_MODE_FULLSCREEN));
8573         // TODO(b/181207944): Consider removing the if condition and always run
8574         // resolveFixedOrientationConfiguration() since this should be applied for all cases.
8575         if (isFixedOrientationLetterboxAllowed) {
8576             resolveFixedOrientationConfiguration(newParentConfiguration);
8577         }
8578         // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
8579         // are already calculated in resolveFixedOrientationConfiguration.
8580         // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer.
8581         if (Flags.immersiveAppRepositioning() && !isLetterboxedForFixedOrientationAndAspectRatio()
8582                 && !mLetterboxUiController.hasFullscreenOverride()) {
8583             resolveAspectRatioRestriction(newParentConfiguration);
8584         }
8585         final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets();
8586         if (compatDisplayInsets != null) {
8587             resolveSizeCompatModeConfiguration(newParentConfiguration, compatDisplayInsets);
8588         } else if (inMultiWindowMode() && !isFixedOrientationLetterboxAllowed) {
8589             // We ignore activities' requested orientation in multi-window modes. They may be
8590             // taken into consideration in resolveFixedOrientationConfiguration call above.
8591             resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
8592             // If the activity has requested override bounds, the configuration needs to be
8593             // computed accordingly.
8594             if (!matchParentBounds()) {
8595                 computeConfigByResolveHint(resolvedConfig, newParentConfiguration);
8596             }
8597         }
8598         // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
8599         // are already calculated in resolveFixedOrientationConfiguration, or if in size compat
8600         // mode, it should already be calculated in resolveSizeCompatModeConfiguration.
8601         // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer.
8602         if (!Flags.immersiveAppRepositioning() && !isLetterboxedForFixedOrientationAndAspectRatio()
8603                 && !mInSizeCompatModeForBounds && !mLetterboxUiController.hasFullscreenOverride()) {
8604             resolveAspectRatioRestriction(newParentConfiguration);
8605         }
8606 
8607         if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null
8608                 // In fullscreen, can be letterboxed for aspect ratio.
8609                 || !inMultiWindowMode()) {
8610             updateResolvedBoundsPosition(newParentConfiguration);
8611         }
8612 
8613         boolean isIgnoreOrientationRequest = mDisplayContent != null
8614                 && mDisplayContent.getIgnoreOrientationRequest();
8615         if (compatDisplayInsets == null
8616                 // for size compat mode set in updateCompatDisplayInsets
8617                 // Fixed orientation letterboxing is possible on both large screen devices
8618                 // with ignoreOrientationRequest enabled and on phones in split screen even with
8619                 // ignoreOrientationRequest disabled.
8620                 && (mLetterboxBoundsForFixedOrientationAndAspectRatio != null
8621                         // Limiting check for aspect ratio letterboxing to devices with enabled
8622                         // ignoreOrientationRequest. This avoids affecting phones where apps may
8623                         // not expect the change of smallestScreenWidthDp after rotation which is
8624                         // possible with this logic. Not having smallestScreenWidthDp completely
8625                         // accurate on phones shouldn't make the big difference and is expected
8626                         // to be already well-tested by apps.
8627                         || (isIgnoreOrientationRequest && mIsAspectRatioApplied))) {
8628             // TODO(b/264034555): Use mDisplayContent to calculate smallestScreenWidthDp from all
8629             // rotations and only re-calculate if parent bounds have non-orientation size change.
8630             resolvedConfig.smallestScreenWidthDp =
8631                     Math.min(resolvedConfig.screenWidthDp, resolvedConfig.screenHeightDp);
8632         }
8633 
8634         // Assign configuration sequence number into hierarchy because there is a different way than
8635         // ensureActivityConfiguration() in this class that uses configuration in WindowState during
8636         // layout traversals.
8637         mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
8638         getResolvedOverrideConfiguration().seq = mConfigurationSeq;
8639 
8640         // Sandbox max bounds by setting it to the activity bounds, if activity is letterboxed, or
8641         // has or will have mCompatDisplayInsets for size compat. Also forces an activity to be
8642         // sandboxed or not depending upon the configuration settings.
8643         if (providesMaxBounds()) {
8644             mTmpBounds.set(resolvedConfig.windowConfiguration.getBounds());
8645             if (mTmpBounds.isEmpty()) {
8646                 // When there is no override bounds, the activity will inherit the bounds from
8647                 // parent.
8648                 mTmpBounds.set(newParentConfiguration.windowConfiguration.getBounds());
8649             }
8650             if (DEBUG_CONFIGURATION) {
8651                 ProtoLog.d(WM_DEBUG_CONFIGURATION, "Sandbox max bounds for uid %s to bounds %s. "
8652                                 + "config to never sandbox = %s, "
8653                                 + "config to always sandbox = %s, "
8654                                 + "letterboxing from mismatch with parent bounds = %s, "
8655                                 + "has mCompatDisplayInsets = %s, "
8656                                 + "should create compatDisplayInsets = %s",
8657                         getUid(),
8658                         mTmpBounds,
8659                         info.neverSandboxDisplayApis(sConstrainDisplayApisConfig),
8660                         info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig),
8661                         !matchParentBounds(),
8662                         compatDisplayInsets != null,
8663                         shouldCreateCompatDisplayInsets());
8664             }
8665             resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
8666         }
8667 
8668         applySizeOverrideIfNeeded(
8669                 mDisplayContent,
8670                 info.applicationInfo,
8671                 newParentConfiguration,
8672                 resolvedConfig,
8673                 mOptOutEdgeToEdge,
8674                 hasFixedRotationTransform(),
8675                 getCompatDisplayInsets() != null);
8676         mResolveConfigHint.resetTmpOverrides();
8677 
8678         logAppCompatState();
8679     }
8680 
getParentAppBoundsOverride()8681     @Nullable Rect getParentAppBoundsOverride() {
8682         return Rect.copyOrNull(mResolveConfigHint.mParentAppBoundsOverride);
8683     }
8684 
computeConfigByResolveHint(@onNull Configuration resolvedConfig, @NonNull Configuration parentConfig)8685     private void computeConfigByResolveHint(@NonNull Configuration resolvedConfig,
8686             @NonNull Configuration parentConfig) {
8687         task.computeConfigResourceOverrides(resolvedConfig, parentConfig, mResolveConfigHint);
8688         // Reset the temp info which should only take effect for the specified computation.
8689         mResolveConfigHint.mTmpCompatInsets = null;
8690         mResolveConfigHint.mTmpOverrideDisplayInfo = null;
8691     }
8692 
8693     /**
8694      * Returns whether activity bounds are letterboxed.
8695      *
8696      * <p>Note that letterbox UI may not be shown even when this returns {@code true}. See {@link
8697      * LetterboxUiController#shouldShowLetterboxUi} for more context.
8698      */
areBoundsLetterboxed()8699     boolean areBoundsLetterboxed() {
8700         return getAppCompatState(/* ignoreVisibility= */ true)
8701                 != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
8702     }
8703 
8704     /**
8705      * Logs the current App Compat state via {@link ActivityMetricsLogger#logAppCompatState}.
8706      */
logAppCompatState()8707     private void logAppCompatState() {
8708         mTaskSupervisor.getActivityMetricsLogger().logAppCompatState(this);
8709     }
8710 
8711     /**
8712      * Returns the current App Compat state of this activity.
8713      *
8714      * <p>The App Compat state indicates whether the activity is visible and letterboxed, and if so
8715      * what is the reason for letterboxing. The state is used for logging the time spent in
8716      * letterbox (sliced by the reason) vs non-letterbox per app.
8717      */
getAppCompatState()8718     int getAppCompatState() {
8719         return getAppCompatState(/* ignoreVisibility= */ false);
8720     }
8721 
8722     /**
8723      * Same as {@link #getAppCompatState()} except when {@code ignoreVisibility} the visibility
8724      * of the activity is ignored.
8725      *
8726      * @param ignoreVisibility whether to ignore the visibility of the activity and not return
8727      *                         NOT_VISIBLE if {@code mVisibleRequested} is false.
8728      */
getAppCompatState(boolean ignoreVisibility)8729     private int getAppCompatState(boolean ignoreVisibility) {
8730         if (!ignoreVisibility && !mVisibleRequested) {
8731             return APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
8732         }
8733         // TODO(b/256564921): Investigate if we need new metrics for translucent activities
8734         if (mTransparentPolicy.isRunning()) {
8735             return mTransparentPolicy.getInheritedAppCompatState();
8736         }
8737         if (mInSizeCompatModeForBounds) {
8738             return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
8739         }
8740         // Letterbox for fixed orientation. This check returns true only when an activity is
8741         // letterboxed for fixed orientation. Aspect ratio restrictions are also applied if
8742         // present. But this doesn't return true when the activity is letterboxed only because
8743         // of aspect ratio restrictions.
8744         if (isLetterboxedForFixedOrientationAndAspectRatio()) {
8745             return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
8746         }
8747         // Letterbox for limited aspect ratio.
8748         if (isLetterboxedForAspectRatioOnly()) {
8749             return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
8750         }
8751 
8752         return APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
8753     }
8754 
8755     /**
8756      * Adjusts position of resolved bounds if they don't fill the parent using gravity
8757      * requested in the config or via an ADB command. For more context see {@link
8758      * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)} and
8759      * {@link LetterboxUiController#getVerticalPositionMultiplier(Configuration)}
8760      * <p>
8761      * Note that this is the final step that can change the resolved bounds. After this method
8762      * is called, the position of the bounds will be moved to app space as sandboxing if the
8763      * activity has a size compat scale.
8764      */
updateResolvedBoundsPosition(Configuration newParentConfiguration)8765     private void updateResolvedBoundsPosition(Configuration newParentConfiguration) {
8766         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
8767         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
8768         if (resolvedBounds.isEmpty()) {
8769             return;
8770         }
8771         final Rect screenResolvedBounds =
8772                 mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
8773         final Rect parentAppBounds = mResolveConfigHint.mParentAppBoundsOverride;
8774         final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
8775         final float screenResolvedBoundsWidth = screenResolvedBounds.width();
8776         final float parentAppBoundsWidth = parentAppBounds.width();
8777         final boolean isImmersiveMode = isImmersiveMode(parentBounds);
8778         final Insets navBarInsets;
8779         if (isImmersiveMode) {
8780             navBarInsets = mDisplayContent.getInsetsStateController()
8781                     .getRawInsetsState().calculateInsets(
8782                             parentBounds,
8783                             WindowInsets.Type.navigationBars(),
8784                             true /* ignoreVisibility */);
8785         } else {
8786             navBarInsets = Insets.NONE;
8787         }
8788         // Horizontal position
8789         int offsetX = 0;
8790         if (parentBounds.width() != screenResolvedBoundsWidth) {
8791             if (screenResolvedBoundsWidth <= parentAppBoundsWidth) {
8792                 float positionMultiplier = mLetterboxUiController.getHorizontalPositionMultiplier(
8793                         newParentConfiguration);
8794                 // If in immersive mode, always align to right and overlap right insets (task bar)
8795                 // as they are transient and hidden. This removes awkward right spacing.
8796                 final int appWidth = (int) (parentAppBoundsWidth + navBarInsets.right);
8797                 offsetX = Math.max(0, (int) Math.ceil((appWidth
8798                         - screenResolvedBoundsWidth) * positionMultiplier)
8799                         // This is added to make sure that insets added inside
8800                         // CompatDisplayInsets#getContainerBounds() do not break the alignment
8801                         // provided by the positionMultiplier
8802                         - screenResolvedBounds.left + parentAppBounds.left);
8803             }
8804         }
8805 
8806         final float parentAppBoundsHeight = parentAppBounds.height();
8807         final float parentBoundsHeight = parentBounds.height();
8808         final float screenResolvedBoundsHeight = screenResolvedBounds.height();
8809         // Vertical position
8810         int offsetY = 0;
8811         if (parentBoundsHeight != screenResolvedBoundsHeight) {
8812             if (screenResolvedBoundsHeight <= parentAppBoundsHeight) {
8813                 float positionMultiplier = mLetterboxUiController.getVerticalPositionMultiplier(
8814                         newParentConfiguration);
8815                 // If in immersive mode, always align to bottom and overlap bottom insets (nav bar,
8816                 // task bar) as they are transient and hidden. This removes awkward bottom spacing.
8817                 final int appHeight = (int) (parentAppBoundsHeight + navBarInsets.bottom);
8818                 offsetY = Math.max(0, (int) Math.ceil((appHeight
8819                         - screenResolvedBoundsHeight) * positionMultiplier)
8820                         // This is added to make sure that insets added inside
8821                         // CompatDisplayInsets#getContainerBounds() do not break the alignment
8822                         // provided by the positionMultiplier
8823                         - screenResolvedBounds.top + parentAppBounds.top);
8824             }
8825         }
8826 
8827         if (mSizeCompatBounds != null) {
8828             mSizeCompatBounds.offset(offsetX , offsetY);
8829             final int dy = mSizeCompatBounds.top - resolvedBounds.top;
8830             final int dx = mSizeCompatBounds.left - resolvedBounds.left;
8831             offsetBounds(resolvedConfig, dx, dy);
8832         } else {
8833             offsetBounds(resolvedConfig, offsetX, offsetY);
8834         }
8835 
8836         // If the top is aligned with parentAppBounds add the vertical insets back so that the app
8837         // content aligns with the status bar
8838         if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top
8839                 && !isImmersiveMode) {
8840             resolvedConfig.windowConfiguration.getBounds().top = parentBounds.top;
8841             if (mSizeCompatBounds != null) {
8842                 mSizeCompatBounds.top = parentBounds.top;
8843             }
8844         }
8845 
8846         // Since bounds has changed, the configuration needs to be computed accordingly.
8847         computeConfigByResolveHint(resolvedConfig, newParentConfiguration);
8848 
8849         // The position of configuration bounds were calculated in screen space because that is
8850         // easier to resolve the relative position in parent container. However, if the activity is
8851         // scaled, the position should follow the scale because the configuration will be sent to
8852         // the client which is expected to be in a scaled environment.
8853         if (mSizeCompatScale != 1f) {
8854             final int screenPosX = resolvedBounds.left;
8855             final int screenPosY = resolvedBounds.top;
8856             final int dx = (int) (screenPosX / mSizeCompatScale + 0.5f) - screenPosX;
8857             final int dy = (int) (screenPosY / mSizeCompatScale + 0.5f) - screenPosY;
8858             offsetBounds(resolvedConfig, dx, dy);
8859         }
8860     }
8861 
isImmersiveMode(@onNull Rect parentBounds)8862     boolean isImmersiveMode(@NonNull Rect parentBounds) {
8863         if (!Flags.immersiveAppRepositioning()) {
8864             return false;
8865         }
8866         if (!mResolveConfigHint.mUseOverrideInsetsForConfig
8867                 && mWmService.mFlags.mInsetsDecoupledConfiguration) {
8868             return false;
8869         }
8870         final Insets navBarInsets = mDisplayContent.getInsetsStateController()
8871                 .getRawInsetsState().calculateInsets(
8872                         parentBounds,
8873                         WindowInsets.Type.navigationBars(),
8874                         false /* ignoreVisibility */);
8875         return Insets.NONE.equals(navBarInsets);
8876     }
8877 
getScreenResolvedBounds()8878     @NonNull Rect getScreenResolvedBounds() {
8879         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
8880         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
8881         return mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
8882     }
8883 
recomputeConfiguration()8884     void recomputeConfiguration() {
8885         // We check if the current activity is transparent. In that case we need to
8886         // recomputeConfiguration of the first opaque activity beneath, to allow a
8887         // proper computation of the new bounds.
8888         if (!mTransparentPolicy.applyOnOpaqueActivityBelow(
8889                 ActivityRecord::recomputeConfiguration)) {
8890             onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
8891         }
8892     }
8893 
isInTransition()8894     boolean isInTransition() {
8895         return inTransitionSelfOrParent();
8896     }
8897 
isDisplaySleepingAndSwapping()8898     boolean isDisplaySleepingAndSwapping() {
8899         for (int i = mDisplayContent.mAllSleepTokens.size() - 1; i >= 0; i--) {
8900             RootWindowContainer.SleepToken sleepToken = mDisplayContent.mAllSleepTokens.get(i);
8901             if (sleepToken.isDisplaySwapping()) {
8902                 return true;
8903             }
8904         }
8905         return false;
8906     }
8907 
8908     /**
8909      * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
8910      * orientation then aspect ratio restrictions are also already respected.
8911      *
8912      * <p>This happens when an activity has fixed orientation which doesn't match orientation of the
8913      * parent because a display setting 'ignoreOrientationRequest' is set to true. See {@link
8914      * WindowManagerService#getIgnoreOrientationRequest} for more context.
8915      */
isLetterboxedForFixedOrientationAndAspectRatio()8916     boolean isLetterboxedForFixedOrientationAndAspectRatio() {
8917         return mLetterboxBoundsForFixedOrientationAndAspectRatio != null;
8918     }
8919 
isLetterboxedForAspectRatioOnly()8920     boolean isLetterboxedForAspectRatioOnly() {
8921         return mLetterboxBoundsForAspectRatio != null;
8922     }
8923 
isAspectRatioApplied()8924     boolean isAspectRatioApplied() {
8925         return mIsAspectRatioApplied;
8926     }
8927 
8928     /**
8929      * Whether this activity is eligible for letterbox eduction.
8930      *
8931      * <p>Conditions that need to be met:
8932      *
8933      * <ul>
8934      *     <li>{@link LetterboxConfiguration#getIsEducationEnabled} is true.
8935      *     <li>The activity is eligible for fixed orientation letterbox.
8936      *     <li>The activity is in fullscreen.
8937      *     <li>The activity is portrait-only.
8938      *     <li>The activity doesn't have a starting window (education should only be displayed
8939      *     once the starting window is removed in {@link #removeStartingWindow}).
8940      * </ul>
8941      */
isEligibleForLetterboxEducation()8942     boolean isEligibleForLetterboxEducation() {
8943         return mWmService.mLetterboxConfiguration.getIsEducationEnabled()
8944                 && mIsEligibleForFixedOrientationLetterbox
8945                 && getWindowingMode() == WINDOWING_MODE_FULLSCREEN
8946                 && getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT
8947                 && mStartingWindow == null;
8948     }
8949 
8950     /**
8951      * In some cases, applying insets to bounds changes the orientation. For example, if a
8952      * close-to-square display rotates to portrait to respect a portrait orientation activity, after
8953      * insets such as the status and nav bars are applied, the activity may actually have a
8954      * landscape orientation. This method checks whether the orientations of the activity window
8955      * with and without insets match or if the orientation with insets already matches the
8956      * requested orientation. If not, it may be necessary to letterbox the window.
8957      * @param parentBounds are the new parent bounds passed down to the activity and should be used
8958      *                     to compute the stable bounds.
8959      * @param outStableBounds will store the stable bounds, which are the bounds with insets
8960      *                        applied, if orientation is not respected when insets are applied.
8961      *                        Stable bounds should be used to compute letterboxed bounds if
8962      *                        orientation is not respected when insets are applied.
8963      * @param outNonDecorBounds will store the non decor bounds, which are the bounds with non
8964      *                          decor insets applied, like display cutout and nav bar.
8965      */
orientationRespectedWithInsets(Rect parentBounds, Rect outStableBounds, Rect outNonDecorBounds)8966     private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outStableBounds,
8967             Rect outNonDecorBounds) {
8968         outStableBounds.setEmpty();
8969         if (mDisplayContent == null) {
8970             return true;
8971         }
8972         if (!mResolveConfigHint.mUseOverrideInsetsForConfig) {
8973             // No insets should be considered any more.
8974             return true;
8975         }
8976         // Only need to make changes if activity sets an orientation
8977         final int requestedOrientation = getRequestedConfigurationOrientation();
8978         if (requestedOrientation == ORIENTATION_UNDEFINED) {
8979             return true;
8980         }
8981         // Compute parent orientation from bounds
8982         final int orientation = parentBounds.height() >= parentBounds.width()
8983                 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
8984         // Compute orientation from stable parent bounds (= parent bounds with insets applied)
8985         final DisplayInfo di = isFixedRotationTransforming()
8986                 ? getFixedRotationTransformDisplayInfo()
8987                 : mDisplayContent.getDisplayInfo();
8988         final Task task = getTask();
8989         task.calculateInsetFrames(outNonDecorBounds /* outNonDecorBounds */,
8990                 outStableBounds /* outStableBounds */, parentBounds /* bounds */, di,
8991                 mResolveConfigHint.mUseOverrideInsetsForConfig);
8992         final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
8993                 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
8994         // If orientation does not match the orientation with insets applied, then a
8995         // display rotation will not be enough to respect orientation. However, even if they do
8996         // not match but the orientation with insets applied matches the requested orientation, then
8997         // there is no need to modify the bounds because when insets are applied, the activity will
8998         // have the desired orientation.
8999         final boolean orientationRespectedWithInsets = orientation == orientationWithInsets
9000                 || orientationWithInsets == requestedOrientation;
9001         return orientationRespectedWithInsets;
9002     }
9003 
9004     @Override
handlesOrientationChangeFromDescendant(int orientation)9005     boolean handlesOrientationChangeFromDescendant(int orientation) {
9006         if (shouldIgnoreOrientationRequests()) {
9007             return false;
9008         }
9009         return super.handlesOrientationChangeFromDescendant(orientation);
9010     }
9011 
9012     /**
9013      * Computes bounds (letterbox or pillarbox) when either:
9014      * 1. The parent doesn't handle the orientation change and the requested orientation is
9015      *    different from the parent (see {@link DisplayContent#setIgnoreOrientationRequest()}.
9016      * 2. The parent handling the orientation is not enough. This occurs when the display rotation
9017      *    may not be enough to respect orientation requests (see {@link
9018      *    ActivityRecord#orientationRespectedWithInsets}).
9019      *
9020      * <p>If letterboxed due to fixed orientation then aspect ratio restrictions are also applied
9021      * in this method.
9022      */
resolveFixedOrientationConfiguration(@onNull Configuration newParentConfig)9023     private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig) {
9024         final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
9025         final Rect stableBounds = new Rect();
9026         final Rect outNonDecorBounds = mTmpBounds;
9027         // If orientation is respected when insets are applied, then stableBounds will be empty.
9028         boolean orientationRespectedWithInsets =
9029                 orientationRespectedWithInsets(parentBounds, stableBounds, outNonDecorBounds);
9030         if (orientationRespectedWithInsets && handlesOrientationChangeFromDescendant(
9031                 getOverrideOrientation())) {
9032             // No need to letterbox because of fixed orientation. Display will handle
9033             // fixed-orientation requests and a display rotation is enough to respect requested
9034             // orientation with insets applied.
9035             return;
9036         }
9037         // TODO(b/232898850): always respect fixed-orientation request.
9038         // Ignore orientation request for activity in ActivityEmbedding split.
9039         final TaskFragment organizedTf = getOrganizedTaskFragment();
9040         if (organizedTf != null && !organizedTf.fillsParent()) {
9041             return;
9042         }
9043 
9044         final Rect resolvedBounds =
9045                 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
9046         final int stableBoundsOrientation = stableBounds.width() > stableBounds.height()
9047                 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
9048         final int parentOrientation = mResolveConfigHint.mUseOverrideInsetsForConfig
9049                 ? stableBoundsOrientation : newParentConfig.orientation;
9050 
9051         // If the activity requires a different orientation (either by override or activityInfo),
9052         // make it fit the available bounds by scaling down its bounds.
9053         final int forcedOrientation = getRequestedConfigurationOrientation();
9054 
9055         mIsEligibleForFixedOrientationLetterbox = forcedOrientation != ORIENTATION_UNDEFINED
9056                 && forcedOrientation != parentOrientation;
9057 
9058         if (!mIsEligibleForFixedOrientationLetterbox && (forcedOrientation == ORIENTATION_UNDEFINED
9059                 || orientationRespectedWithInsets)) {
9060             return;
9061         }
9062         final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets();
9063 
9064         if (compatDisplayInsets != null
9065                 && !compatDisplayInsets.mIsInFixedOrientationOrAspectRatioLetterbox) {
9066             // App prefers to keep its original size.
9067             // If the size compat is from previous fixed orientation letterboxing, we may want to
9068             // have fixed orientation letterbox again, otherwise it will show the size compat
9069             // restart button even if the restart bounds will be the same.
9070             return;
9071         }
9072 
9073         final Rect parentAppBounds = mResolveConfigHint.mUseOverrideInsetsForConfig
9074                 ? outNonDecorBounds : newParentConfig.windowConfiguration.getAppBounds();
9075         // TODO(b/182268157): Explore using only one type of parentBoundsWithInsets, either app
9076         // bounds or stable bounds to unify aspect ratio logic.
9077         final Rect parentBoundsWithInsets = orientationRespectedWithInsets
9078                 ? parentAppBounds : stableBounds;
9079         final Rect containingBounds = new Rect();
9080         final Rect containingBoundsWithInsets = new Rect();
9081         // Need to shrink the containing bounds into a square because the parent orientation
9082         // does not match the activity requested orientation.
9083         if (forcedOrientation == ORIENTATION_LANDSCAPE) {
9084             // Landscape is defined as width > height. Make the container respect landscape
9085             // orientation by shrinking height to one less than width. Landscape activity will be
9086             // vertically centered within parent bounds with insets, so position vertical bounds
9087             // within parent bounds with insets to prevent insets from unnecessarily trimming
9088             // vertical bounds.
9089             final int bottom = Math.min(parentBoundsWithInsets.top
9090                             + parentBoundsWithInsets.width() - 1, parentBoundsWithInsets.bottom);
9091             containingBounds.set(parentBounds.left, parentBoundsWithInsets.top, parentBounds.right,
9092                     bottom);
9093             containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
9094                     parentBoundsWithInsets.right, bottom);
9095         } else {
9096             // Portrait is defined as width <= height. Make the container respect portrait
9097             // orientation by shrinking width to match height. Portrait activity will be
9098             // horizontally centered within parent bounds with insets, so position horizontal bounds
9099             // within parent bounds with insets to prevent insets from unnecessarily trimming
9100             // horizontal bounds.
9101             final int right = Math.min(parentBoundsWithInsets.left
9102                             + parentBoundsWithInsets.height(), parentBoundsWithInsets.right);
9103             containingBounds.set(parentBoundsWithInsets.left, parentBounds.top, right,
9104                     parentBounds.bottom);
9105             containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
9106                     right, parentBoundsWithInsets.bottom);
9107         }
9108 
9109         // Store the current bounds to be able to revert to size compat mode values below if needed.
9110         final Rect prevResolvedBounds = new Rect(resolvedBounds);
9111         resolvedBounds.set(containingBounds);
9112 
9113         final float letterboxAspectRatioOverride =
9114                 mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig);
9115 
9116         // Aspect ratio as suggested by the system. Apps requested mix/max aspect ratio will
9117         // be respected in #applyAspectRatio.
9118         final float desiredAspectRatio;
9119         if (isDefaultMultiWindowLetterboxAspectRatioDesired(newParentConfig)) {
9120             desiredAspectRatio = DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
9121         } else if (letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
9122             desiredAspectRatio = letterboxAspectRatioOverride;
9123         } else {
9124             desiredAspectRatio = computeAspectRatio(parentBounds);
9125         }
9126 
9127         // Apply aspect ratio to resolved bounds
9128         mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
9129                 containingBounds, desiredAspectRatio);
9130 
9131         if (compatDisplayInsets != null) {
9132             compatDisplayInsets.getBoundsByRotation(mTmpBounds,
9133                     newParentConfig.windowConfiguration.getRotation());
9134             if (resolvedBounds.width() != mTmpBounds.width()
9135                     || resolvedBounds.height() != mTmpBounds.height()) {
9136                 // The app shouldn't be resized, we only do fixed orientation letterboxing if the
9137                 // compat bounds are also from the same fixed orientation letterbox. Otherwise,
9138                 // clear the fixed orientation bounds to show app in size compat mode.
9139                 resolvedBounds.set(prevResolvedBounds);
9140                 return;
9141             }
9142         }
9143 
9144         // Fixed orientation bounds are the same as its parent container, so clear the fixed
9145         // orientation bounds. This can happen in close to square displays where the orientation
9146         // is not respected with insets, but the display still matches or is less than the
9147         // activity aspect ratio.
9148         if (resolvedBounds.equals(parentBounds)) {
9149             resolvedBounds.set(prevResolvedBounds);
9150             return;
9151         }
9152 
9153         // Calculate app bounds using fixed orientation bounds because they will be needed later
9154         // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
9155         mResolveConfigHint.mTmpCompatInsets = compatDisplayInsets;
9156         computeConfigByResolveHint(getResolvedOverrideConfiguration(), newParentConfig);
9157         mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
9158     }
9159 
9160     /**
9161      * Returns {@code true} if the default aspect ratio for a letterboxed app in multi-window mode
9162      * should be used.
9163      */
isDefaultMultiWindowLetterboxAspectRatioDesired( @onNull Configuration parentConfig)9164     private boolean isDefaultMultiWindowLetterboxAspectRatioDesired(
9165             @NonNull Configuration parentConfig) {
9166         if (mDisplayContent == null) {
9167             return false;
9168         }
9169         final int windowingMode = parentConfig.windowConfiguration.getWindowingMode();
9170         return WindowConfiguration.inMultiWindowMode(windowingMode)
9171                 && !mDisplayContent.getIgnoreOrientationRequest();
9172     }
9173 
9174     /**
9175      * Resolves aspect ratio restrictions for an activity. If the bounds are restricted by
9176      * aspect ratio, the position will be adjusted later in {@link #updateResolvedBoundsPosition
9177      * within parent's app bounds to balance the visual appearance. The policy of aspect ratio has
9178      * higher priority than the requested override bounds.
9179      */
resolveAspectRatioRestriction(Configuration newParentConfiguration)9180     private void resolveAspectRatioRestriction(Configuration newParentConfiguration) {
9181         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
9182         final Rect parentAppBounds = mResolveConfigHint.mParentAppBoundsOverride;
9183         final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
9184         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
9185         // Use tmp bounds to calculate aspect ratio so we can know whether the activity should use
9186         // restricted size (resolved bounds may be the requested override bounds).
9187         mTmpBounds.setEmpty();
9188         mIsAspectRatioApplied = applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
9189         // If the out bounds is not empty, it means the activity cannot fill parent's app bounds,
9190         // then they should be aligned later in #updateResolvedBoundsPosition()
9191         if (!mTmpBounds.isEmpty()) {
9192             resolvedBounds.set(mTmpBounds);
9193         }
9194         if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
9195             // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
9196             // restrict, the bounds should be the requested override bounds.
9197             mResolveConfigHint.mTmpOverrideDisplayInfo = getFixedRotationTransformDisplayInfo();
9198             computeConfigByResolveHint(resolvedConfig, newParentConfiguration);
9199             mLetterboxBoundsForAspectRatio = new Rect(resolvedBounds);
9200         }
9201     }
9202 
9203     /**
9204      * Resolves consistent screen configuration for orientation and rotation changes without
9205      * inheriting the parent bounds.
9206      */
resolveSizeCompatModeConfiguration(Configuration newParentConfiguration, @NonNull CompatDisplayInsets compatDisplayInsets)9207     private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration,
9208             @NonNull CompatDisplayInsets compatDisplayInsets) {
9209         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
9210         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
9211 
9212         // When an activity needs to be letterboxed because of fixed orientation, use fixed
9213         // orientation bounds (stored in resolved bounds) instead of parent bounds since the
9214         // activity will be displayed within them even if it is in size compat mode. They should be
9215         // saved here before resolved bounds are overridden below.
9216         final boolean useResolvedBounds = Flags.immersiveAppRepositioning()
9217                 ? isAspectRatioApplied() : isLetterboxedForFixedOrientationAndAspectRatio();
9218         final Rect containerBounds = useResolvedBounds
9219                 ? new Rect(resolvedBounds)
9220                 : newParentConfiguration.windowConfiguration.getBounds();
9221         final Rect containerAppBounds = useResolvedBounds
9222                 ? new Rect(resolvedConfig.windowConfiguration.getAppBounds())
9223                 : mResolveConfigHint.mParentAppBoundsOverride;
9224 
9225         final int requestedOrientation = getRequestedConfigurationOrientation();
9226         final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED;
9227         final int parentOrientation = mResolveConfigHint.mUseOverrideInsetsForConfig
9228                 ? mResolveConfigHint.mTmpOverrideConfigOrientation
9229                 : newParentConfiguration.orientation;
9230         final int orientation = orientationRequested
9231                 ? requestedOrientation
9232                 // We should use the original orientation of the activity when possible to avoid
9233                 // forcing the activity in the opposite orientation.
9234                 : compatDisplayInsets.mOriginalRequestedOrientation != ORIENTATION_UNDEFINED
9235                         ? compatDisplayInsets.mOriginalRequestedOrientation
9236                         : parentOrientation;
9237         int rotation = newParentConfiguration.windowConfiguration.getRotation();
9238         final boolean isFixedToUserRotation = mDisplayContent == null
9239                 || mDisplayContent.getDisplayRotation().isFixedToUserRotation();
9240         if (!isFixedToUserRotation && !compatDisplayInsets.mIsFloating) {
9241             // Use parent rotation because the original display can be rotated.
9242             resolvedConfig.windowConfiguration.setRotation(rotation);
9243         } else {
9244             final int overrideRotation = resolvedConfig.windowConfiguration.getRotation();
9245             if (overrideRotation != ROTATION_UNDEFINED) {
9246                 rotation = overrideRotation;
9247             }
9248         }
9249 
9250         // Use compat insets to lock width and height. We should not use the parent width and height
9251         // because apps in compat mode should have a constant width and height. The compat insets
9252         // are locked when the app is first launched and are never changed after that, so we can
9253         // rely on them to contain the original and unchanging width and height of the app.
9254         final Rect containingAppBounds = new Rect();
9255         final Rect containingBounds = mTmpBounds;
9256         compatDisplayInsets.getContainerBounds(containingAppBounds, containingBounds, rotation,
9257                 orientation, orientationRequested, isFixedToUserRotation);
9258         resolvedBounds.set(containingBounds);
9259         // The size of floating task is fixed (only swap), so the aspect ratio is already correct.
9260         if (!compatDisplayInsets.mIsFloating) {
9261             mIsAspectRatioApplied =
9262                     applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
9263         }
9264 
9265         // Use resolvedBounds to compute other override configurations such as appBounds. The bounds
9266         // are calculated in compat container space. The actual position on screen will be applied
9267         // later, so the calculation is simpler that doesn't need to involve offset from parent.
9268         mResolveConfigHint.mTmpCompatInsets = compatDisplayInsets;
9269         computeConfigByResolveHint(resolvedConfig, newParentConfiguration);
9270         // Use current screen layout as source because the size of app is independent to parent.
9271         resolvedConfig.screenLayout = computeScreenLayout(
9272                 getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
9273                 resolvedConfig.screenHeightDp);
9274 
9275         // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside
9276         // the parent bounds appropriately.
9277         if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) {
9278             resolvedConfig.orientation = parentOrientation;
9279         }
9280 
9281         // Below figure is an example that puts an activity which was launched in a larger container
9282         // into a smaller container.
9283         //   The outermost rectangle is the real display bounds.
9284         //   "@" is the container app bounds (parent bounds or fixed orientation bounds)
9285         //   "#" is the {@code resolvedBounds} that applies to application.
9286         //   "*" is the {@code mSizeCompatBounds} that used to show on screen if scaled.
9287         // ------------------------------
9288         // |                            |
9289         // |    @@@@*********@@@@###    |
9290         // |    @   *       *   @  #    |
9291         // |    @   *       *   @  #    |
9292         // |    @   *       *   @  #    |
9293         // |    @@@@*********@@@@  #    |
9294         // ---------#--------------#-----
9295         //          #              #
9296         //          ################
9297         // The application is still layouted in "#" since it was launched, and it will be visually
9298         // scaled and positioned to "*".
9299 
9300         final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
9301 
9302         // Calculates the scale the size compatibility bounds into the region which is available
9303         // to application.
9304         final float lastSizeCompatScale = mSizeCompatScale;
9305         updateSizeCompatScale(resolvedAppBounds, containerAppBounds);
9306 
9307         final int containerTopInset = containerAppBounds.top - containerBounds.top;
9308         final boolean topNotAligned =
9309                 containerTopInset != resolvedAppBounds.top - resolvedBounds.top;
9310         if (mSizeCompatScale != 1f || topNotAligned) {
9311             if (mSizeCompatBounds == null) {
9312                 mSizeCompatBounds = new Rect();
9313             }
9314             mSizeCompatBounds.set(resolvedAppBounds);
9315             mSizeCompatBounds.offsetTo(0, 0);
9316             mSizeCompatBounds.scale(mSizeCompatScale);
9317             // The insets are included in height, e.g. the area of real cutout shouldn't be scaled.
9318             mSizeCompatBounds.bottom += containerTopInset;
9319         } else {
9320             mSizeCompatBounds = null;
9321         }
9322         if (mSizeCompatScale != lastSizeCompatScale) {
9323             forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */);
9324         }
9325 
9326         // The position will be later adjusted in updateResolvedBoundsPosition.
9327         // Above coordinates are in "@" space, now place "*" and "#" to screen space.
9328         final boolean fillContainer = resolvedBounds.equals(containingBounds);
9329         final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
9330         final int screenPosY = fillContainer ? containerBounds.top : containerAppBounds.top;
9331 
9332         if (screenPosX != 0 || screenPosY != 0) {
9333             if (mSizeCompatBounds != null) {
9334                 mSizeCompatBounds.offset(screenPosX, screenPosY);
9335             }
9336             // Add the global coordinates and remove the local coordinates.
9337             final int dx = screenPosX - resolvedBounds.left;
9338             final int dy = screenPosY - resolvedBounds.top;
9339             offsetBounds(resolvedConfig, dx, dy);
9340         }
9341 
9342         mInSizeCompatModeForBounds =
9343                 isInSizeCompatModeForBounds(resolvedAppBounds, containerAppBounds);
9344     }
9345 
updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds)9346     void updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds) {
9347         // Only allow to scale down.
9348         mSizeCompatScale = mTransparentPolicy.findOpaqueNotFinishingActivityBelow()
9349                 .map(activityRecord -> activityRecord.mSizeCompatScale)
9350                 .orElseGet(() -> {
9351                     final int contentW = resolvedAppBounds.width();
9352                     final int contentH = resolvedAppBounds.height();
9353                     final int viewportW = containerAppBounds.width();
9354                     final int viewportH = containerAppBounds.height();
9355                     return (contentW <= viewportW && contentH <= viewportH) ? 1f : Math.min(
9356                             (float) viewportW / contentW, (float) viewportH / contentH);
9357                 });
9358     }
9359 
isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds)9360     private boolean isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds) {
9361         if (mTransparentPolicy.isRunning()) {
9362             // To avoid wrong app behaviour, we decided to disable SCM when a translucent activity
9363             // is letterboxed.
9364             return false;
9365         }
9366         final int appWidth = appBounds.width();
9367         final int appHeight = appBounds.height();
9368         final int containerAppWidth = containerBounds.width();
9369         final int containerAppHeight = containerBounds.height();
9370 
9371         if (containerAppWidth == appWidth && containerAppHeight == appHeight) {
9372             // Matched the container bounds.
9373             return false;
9374         }
9375         if (containerAppWidth > appWidth && containerAppHeight > appHeight) {
9376             // Both sides are smaller than the container.
9377             return true;
9378         }
9379         if (containerAppWidth < appWidth || containerAppHeight < appHeight) {
9380             // One side is larger than the container.
9381             return true;
9382         }
9383 
9384         // The rest of the condition is that only one side is smaller than the container, but it
9385         // still needs to exclude the cases where the size is limited by the fixed aspect ratio.
9386         final float maxAspectRatio = getMaxAspectRatio();
9387         if (maxAspectRatio > 0) {
9388             final float aspectRatio = (0.5f + Math.max(appWidth, appHeight))
9389                     / Math.min(appWidth, appHeight);
9390             if (aspectRatio >= maxAspectRatio) {
9391                 // The current size has reached the max aspect ratio.
9392                 return false;
9393             }
9394         }
9395         final float minAspectRatio = getMinAspectRatio();
9396         if (minAspectRatio > 0) {
9397             // The activity should have at least the min aspect ratio, so this checks if the
9398             // container still has available space to provide larger aspect ratio.
9399             final float containerAspectRatio =
9400                     (0.5f + Math.max(containerAppWidth, containerAppHeight))
9401                             / Math.min(containerAppWidth, containerAppHeight);
9402             if (containerAspectRatio <= minAspectRatio) {
9403                 // The long side has reached the parent.
9404                 return false;
9405             }
9406         }
9407         return true;
9408     }
9409 
9410     /** @return The horizontal / vertical offset of putting the content in the center of viewport.*/
getCenterOffset(int viewportDim, int contentDim)9411     private static int getCenterOffset(int viewportDim, int contentDim) {
9412         return (int) ((viewportDim - contentDim + 1) * 0.5f);
9413     }
9414 
offsetBounds(Configuration inOutConfig, int offsetX, int offsetY)9415     private static void offsetBounds(Configuration inOutConfig, int offsetX, int offsetY) {
9416         inOutConfig.windowConfiguration.getBounds().offset(offsetX, offsetY);
9417         inOutConfig.windowConfiguration.getAppBounds().offset(offsetX, offsetY);
9418     }
9419 
9420     @Override
getBounds()9421     public Rect getBounds() {
9422         // TODO(b/268458693): Refactor configuration inheritance in case of translucent activities
9423         final Rect superBounds = super.getBounds();
9424         return mTransparentPolicy.findOpaqueNotFinishingActivityBelow()
9425                 .map(ActivityRecord::getBounds)
9426                 .orElseGet(() -> {
9427                     if (mSizeCompatBounds != null) {
9428                         return mSizeCompatBounds;
9429                     }
9430                     return superBounds;
9431                 });
9432     }
9433 
9434     @Override
9435     public boolean providesMaxBounds() {
9436         // System should always be able to access the DisplayArea bounds, so do not provide it with
9437         // compat max window bounds.
9438         if (getUid() == SYSTEM_UID) {
9439             return false;
9440         }
9441         // Do not sandbox to activity window bounds if the feature is disabled.
9442         if (mDisplayContent != null && !mDisplayContent.sandboxDisplayApis()) {
9443             return false;
9444         }
9445         // Never apply sandboxing to an app that should be explicitly excluded from the config.
9446         if (info.neverSandboxDisplayApis(sConstrainDisplayApisConfig)) {
9447             return false;
9448         }
9449         // Always apply sandboxing to an app that should be explicitly included from the config.
9450         if (info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig)) {
9451             return true;
9452         }
9453         // Max bounds should be sandboxed when an activity should have compatDisplayInsets, and it
9454         // will keep the same bounds and screen configuration when it was first launched regardless
9455         // how its parent window changes, so that the sandbox API will provide a consistent result.
9456         if (getCompatDisplayInsets() != null || shouldCreateCompatDisplayInsets()) {
9457             return true;
9458         }
9459 
9460         // No need to sandbox for resizable apps in (including in multi-window) because
9461         // resizableActivity=true indicates that they support multi-window. Likewise, do not sandbox
9462         // for activities in letterbox since the activity has declared it can handle resizing.
9463         return false;
9464     }
9465 
9466     @Override
9467     protected boolean setOverrideGender(Configuration requestsTmpConfig, int gender) {
9468         return WindowProcessController.applyConfigGenderOverride(
9469                 requestsTmpConfig, gender, mAtmService.mGrammaticalManagerInternal, getUid());
9470     }
9471 
9472     @VisibleForTesting
9473     @Override
9474     Rect getAnimationBounds(int appRootTaskClipMode) {
9475         // Use TaskFragment-bounds if available so that activity-level letterbox (maxAspectRatio) is
9476         // included in the animation.
9477         final TaskFragment taskFragment = getTaskFragment();
9478         return taskFragment != null ? taskFragment.getBounds() : getBounds();
9479     }
9480 
9481     @Override
9482     void getAnimationPosition(Point outPosition) {
9483         // Always animate from zero because if the activity doesn't fill the task, the letterbox
9484         // will fill the remaining area that should be included in the animation.
9485         outPosition.set(0, 0);
9486     }
9487 
9488     @Override
9489     public void onConfigurationChanged(Configuration newParentConfig) {
9490         // We want to collect the ActivityRecord if the windowing mode is changed, so that it will
9491         // dispatch app transition finished event correctly at the end.
9492         // Check #isVisible() because we don't want to animate for activity that stays invisible.
9493         // Activity with #isVisibleRequested() changed should be collected when that is requested.
9494         if (mTransitionController.isShellTransitionsEnabled() && isVisible()
9495                 && isVisibleRequested()) {
9496             final int projectedWindowingMode =
9497                     getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED
9498                             ? newParentConfig.windowConfiguration.getWindowingMode()
9499                             : getRequestedOverrideWindowingMode();
9500             if (getWindowingMode() != projectedWindowingMode
9501                     // Do not collect a pip activity about to enter pinned mode
9502                     // as a part of WindowOrganizerController#finishTransition().
9503                     // If not checked the activity might be collected for the wrong transition,
9504                     // such as a TRANSIT_OPEN transition requested right after TRANSIT_PIP.
9505                     && !(mWaitForEnteringPinnedMode
9506                     && mTransitionController.inFinishingTransition(this))) {
9507                 mTransitionController.collect(this);
9508             }
9509         }
9510         if (getCompatDisplayInsets() != null) {
9511             Configuration overrideConfig = getRequestedOverrideConfiguration();
9512             // Adapt to changes in orientation locking. The app is still non-resizable, but
9513             // it can change which orientation is fixed. If the fixed orientation changes,
9514             // update the rotation used on the "compat" display
9515             boolean wasFixedOrient =
9516                     overrideConfig.windowConfiguration.getRotation() != ROTATION_UNDEFINED;
9517             int requestedOrient = getRequestedConfigurationOrientation();
9518             if (requestedOrient != ORIENTATION_UNDEFINED
9519                     && requestedOrient != getConfiguration().orientation
9520                     // The task orientation depends on the top activity orientation, so it
9521                     // should match. If it doesn't, just wait until it does.
9522                     && requestedOrient == getParent().getConfiguration().orientation
9523                     && (overrideConfig.windowConfiguration.getRotation()
9524                             != getParent().getWindowConfiguration().getRotation())) {
9525                 overrideConfig.windowConfiguration.setRotation(
9526                         getParent().getWindowConfiguration().getRotation());
9527                 onRequestedOverrideConfigurationChanged(overrideConfig);
9528                 return;
9529             } else if (wasFixedOrient && requestedOrient == ORIENTATION_UNDEFINED
9530                     && (overrideConfig.windowConfiguration.getRotation()
9531                             != ROTATION_UNDEFINED)) {
9532                 overrideConfig.windowConfiguration.setRotation(ROTATION_UNDEFINED);
9533                 onRequestedOverrideConfigurationChanged(overrideConfig);
9534                 return;
9535             }
9536         }
9537 
9538         final boolean wasInPictureInPicture = inPinnedWindowingMode();
9539         final DisplayContent display = mDisplayContent;
9540         final int activityType = getActivityType();
9541         if (wasInPictureInPicture && attachedToProcess() && display != null) {
9542             // If the PIP activity is changing to fullscreen with display orientation change, the
9543             // fixed rotation will take effect that requires to send fixed rotation adjustments
9544             // before the process configuration (if the process is a configuration listener of the
9545             // activity). So when performing process configuration on client side, it can apply
9546             // the adjustments (see WindowToken#onFixedRotationStatePrepared).
9547             try {
9548                 app.pauseConfigurationDispatch();
9549                 super.onConfigurationChanged(newParentConfig);
9550                 if (mVisibleRequested && !inMultiWindowMode()) {
9551                     final int rotation = display.rotationForActivityInDifferentOrientation(this);
9552                     if (rotation != ROTATION_UNDEFINED) {
9553                         app.resumeConfigurationDispatch();
9554                         display.setFixedRotationLaunchingApp(this, rotation);
9555                     }
9556                 }
9557             } finally {
9558                 if (app.resumeConfigurationDispatch()) {
9559                     app.dispatchConfiguration(app.getConfiguration());
9560                 }
9561             }
9562         } else {
9563             super.onConfigurationChanged(newParentConfig);
9564         }
9565         if (activityType != ACTIVITY_TYPE_UNDEFINED
9566                 && activityType != getActivityType()) {
9567             final String errorMessage = "Can't change activity type once set: " + this
9568                     + " activityType=" + activityTypeToString(getActivityType()) + ", was "
9569                     + activityTypeToString(activityType);
9570             if (Build.IS_DEBUGGABLE) {
9571                 throw new IllegalStateException(errorMessage);
9572             }
9573             Slog.w(TAG, errorMessage);
9574         }
9575 
9576         // Before PiP animation is done, th windowing mode of the activity is still the previous
9577         // mode (see RootWindowContainer#moveActivityToPinnedRootTask). So once the windowing mode
9578         // of activity is changed, it is the signal of the last step to update the PiP states.
9579         if (!wasInPictureInPicture && inPinnedWindowingMode() && task != null) {
9580             mWaitForEnteringPinnedMode = false;
9581             mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, task.getBounds());
9582         }
9583 
9584         if (display == null) {
9585             return;
9586         }
9587         if (mVisibleRequested) {
9588             // It may toggle the UI for user to restart the size compatibility mode activity.
9589             display.handleActivitySizeCompatModeIfNeeded(this);
9590         } else if (getCompatDisplayInsets() != null && !visibleIgnoringKeyguard
9591                 && (app == null || !app.hasVisibleActivities())) {
9592             // visibleIgnoringKeyguard is checked to avoid clearing mCompatDisplayInsets during
9593             // displays change. Displays are turned off during the change so mVisibleRequested
9594             // can be false.
9595             // The override changes can only be obtained from display, because we don't have the
9596             // difference of full configuration in each hierarchy.
9597             final int displayChanges = display.getCurrentOverrideConfigurationChanges();
9598             final int orientationChanges = CONFIG_WINDOW_CONFIGURATION
9599                     | CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION;
9600             final boolean hasNonOrienSizeChanged = hasResizeChange(displayChanges)
9601                     // Filter out the case of simple orientation change.
9602                     && (displayChanges & orientationChanges) != orientationChanges;
9603             // For background activity that uses size compatibility mode, if the size or density of
9604             // the display is changed, then reset the override configuration and kill the activity's
9605             // process if its process state is not important to user.
9606             if (hasNonOrienSizeChanged || (displayChanges & ActivityInfo.CONFIG_DENSITY) != 0) {
9607                 restartProcessIfVisible();
9608             }
9609         }
9610     }
9611 
9612     @Override
9613     void dispatchConfigurationToChild(WindowState child, Configuration config) {
9614         if (isConfigurationDispatchPaused()) {
9615             return;
9616         }
9617         super.dispatchConfigurationToChild(child, config);
9618     }
9619 
9620     /**
9621      * Pauses dispatch of configuration changes to the client. This includes any
9622      * configuration-triggered lifecycle changes, WindowState configs, and surface changes. If
9623      * a lifecycle change comes from another source (eg. stop), it will still run but will use the
9624      * paused configuration.
9625      *
9626      * The main way this works is by blocking calls to {@link #updateReportedConfigurationAndSend}.
9627      * That method is responsible for evaluating whether the activity needs to be relaunched and
9628      * sending configurations.
9629      */
9630     void pauseConfigurationDispatch() {
9631         ++mPauseConfigurationDispatchCount;
9632         if (mPauseConfigurationDispatchCount == 1) {
9633             ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Pausing configuration dispatch for "
9634                     + " %s", this);
9635         }
9636     }
9637 
9638     /** @return `true` if configuration actually changed. */
9639     boolean resumeConfigurationDispatch() {
9640         --mPauseConfigurationDispatchCount;
9641         if (mPauseConfigurationDispatchCount > 0) {
9642             return false;
9643         }
9644         ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Resuming configuration dispatch for %s", this);
9645         if (mPauseConfigurationDispatchCount < 0) {
9646             Slog.wtf(TAG, "Trying to resume non-paused configuration dispatch");
9647             mPauseConfigurationDispatchCount = 0;
9648             return false;
9649         }
9650         if (mLastReportedDisplayId == getDisplayId()
9651                 && getConfiguration().equals(mLastReportedConfiguration.getMergedConfiguration())) {
9652             return false;
9653         }
9654         for (int i = getChildCount() - 1; i >= 0; --i) {
9655             dispatchConfigurationToChild(getChildAt(i), getConfiguration());
9656         }
9657         updateReportedConfigurationAndSend();
9658         return true;
9659     }
9660 
9661     boolean isConfigurationDispatchPaused() {
9662         return mPauseConfigurationDispatchCount > 0;
9663     }
9664 
9665     private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
9666             Rect containingBounds) {
9667         return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
9668                 0 /* desiredAspectRatio */);
9669     }
9670 
9671     /**
9672      * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
9673      * made to outBounds.
9674      *
9675      * @return {@code true} if aspect ratio restrictions were applied.
9676      */
9677     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
9678     private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
9679             Rect containingBounds, float desiredAspectRatio) {
9680         final float maxAspectRatio = getMaxAspectRatio();
9681         final Task rootTask = getRootTask();
9682         final float minAspectRatio = getMinAspectRatio();
9683         final TaskFragment organizedTf = getOrganizedTaskFragment();
9684         float aspectRatioToApply = desiredAspectRatio;
9685         if (task == null || rootTask == null
9686                 || (maxAspectRatio < 1 && minAspectRatio < 1 && aspectRatioToApply < 1)
9687                 // Don't set aspect ratio if we are in VR mode.
9688                 || isInVrUiMode(getConfiguration())
9689                 // TODO(b/232898850): Always respect aspect ratio requests.
9690                 // Don't set aspect ratio for activity in ActivityEmbedding split.
9691                 || (organizedTf != null && !organizedTf.fillsParent())) {
9692             return false;
9693         }
9694 
9695         final int containingAppWidth = containingAppBounds.width();
9696         final int containingAppHeight = containingAppBounds.height();
9697         final float containingRatio = computeAspectRatio(containingAppBounds);
9698 
9699         if (aspectRatioToApply < 1) {
9700             aspectRatioToApply = containingRatio;
9701         }
9702 
9703         if (maxAspectRatio >= 1 && aspectRatioToApply > maxAspectRatio) {
9704             aspectRatioToApply = maxAspectRatio;
9705         } else if (minAspectRatio >= 1 && aspectRatioToApply < minAspectRatio) {
9706             aspectRatioToApply = minAspectRatio;
9707         }
9708 
9709         int activityWidth = containingAppWidth;
9710         int activityHeight = containingAppHeight;
9711 
9712         if (containingRatio - aspectRatioToApply > ASPECT_RATIO_ROUNDING_TOLERANCE) {
9713             if (containingAppWidth < containingAppHeight) {
9714                 // Width is the shorter side, so we use that to figure-out what the max. height
9715                 // should be given the aspect ratio.
9716                 activityHeight = (int) ((activityWidth * aspectRatioToApply) + 0.5f);
9717             } else {
9718                 // Height is the shorter side, so we use that to figure-out what the max. width
9719                 // should be given the aspect ratio.
9720                 activityWidth = (int) ((activityHeight * aspectRatioToApply) + 0.5f);
9721             }
9722         } else if (aspectRatioToApply - containingRatio > ASPECT_RATIO_ROUNDING_TOLERANCE) {
9723             boolean adjustWidth;
9724             switch (getRequestedConfigurationOrientation()) {
9725                 case ORIENTATION_LANDSCAPE:
9726                     // Width should be the longer side for this landscape app, so we use the width
9727                     // to figure-out what the max. height should be given the aspect ratio.
9728                     adjustWidth = false;
9729                     break;
9730                 case ORIENTATION_PORTRAIT:
9731                     // Height should be the longer side for this portrait app, so we use the height
9732                     // to figure-out what the max. width should be given the aspect ratio.
9733                     adjustWidth = true;
9734                     break;
9735                 default:
9736                     // This app doesn't have a preferred orientation, so we keep the length of the
9737                     // longer side, and use it to figure-out the length of the shorter side.
9738                     if (containingAppWidth < containingAppHeight) {
9739                         // Width is the shorter side, so we use the height to figure-out what the
9740                         // max. width should be given the aspect ratio.
9741                         adjustWidth = true;
9742                     } else {
9743                         // Height is the shorter side, so we use the width to figure-out what the
9744                         // max. height should be given the aspect ratio.
9745                         adjustWidth = false;
9746                     }
9747                     break;
9748             }
9749             if (adjustWidth) {
9750                 activityWidth = (int) ((activityHeight / aspectRatioToApply) + 0.5f);
9751             } else {
9752                 activityHeight = (int) ((activityWidth / aspectRatioToApply) + 0.5f);
9753             }
9754         }
9755 
9756         if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) {
9757             // The display matches or is less than the activity aspect ratio, so nothing else to do.
9758             return false;
9759         }
9760 
9761         // Compute configuration based on max or min supported width and height.
9762         // Also account for the insets (e.g. display cutouts, navigation bar), which will be
9763         // clipped away later in {@link Task#computeConfigResourceOverrides()}, i.e., the out
9764         // bounds are the app bounds restricted by aspect ratio + clippable insets. Otherwise,
9765         // the app bounds would end up too small. To achieve this we will also add clippable insets
9766         // when the corresponding dimension fully fills the parent
9767 
9768         int right = activityWidth + containingAppBounds.left;
9769         int left = containingAppBounds.left;
9770         if (right >= containingAppBounds.right) {
9771             right = containingBounds.right;
9772             left = containingBounds.left;
9773         }
9774         int bottom = activityHeight + containingAppBounds.top;
9775         int top = containingAppBounds.top;
9776         if (bottom >= containingAppBounds.bottom) {
9777             bottom = containingBounds.bottom;
9778             top = containingBounds.top;
9779         }
9780         outBounds.set(left, top, right, bottom);
9781         return true;
9782     }
9783 
9784     /**
9785      * Returns the min aspect ratio of this activity.
9786      */
9787     float getMinAspectRatio() {
9788         if (mTransparentPolicy.isRunning()) {
9789             return mTransparentPolicy.getInheritedMinAspectRatio();
9790         }
9791         if (info.applicationInfo == null) {
9792             return info.getMinAspectRatio();
9793         }
9794         if (mLetterboxUiController.shouldApplyUserMinAspectRatioOverride()) {
9795             return mLetterboxUiController.getUserMinAspectRatio();
9796         }
9797         if (!mLetterboxUiController.shouldOverrideMinAspectRatio()
9798                 && !mLetterboxUiController.shouldOverrideMinAspectRatioForCamera()) {
9799             return info.getMinAspectRatio();
9800         }
9801         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
9802                 && !ActivityInfo.isFixedOrientationPortrait(
9803                         getOverrideOrientation())) {
9804             return info.getMinAspectRatio();
9805         }
9806 
9807         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN)
9808                 && isParentFullscreenPortrait()) {
9809             // We are using the parent configuration here as this is the most recent one that gets
9810             // passed to onConfigurationChanged when a relevant change takes place
9811             return info.getMinAspectRatio();
9812         }
9813 
9814         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN)) {
9815             return Math.max(mLetterboxUiController.getSplitScreenAspectRatio(),
9816                     info.getMinAspectRatio());
9817         }
9818 
9819         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) {
9820             return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
9821                     info.getMinAspectRatio());
9822         }
9823 
9824         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) {
9825             return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE,
9826                     info.getMinAspectRatio());
9827         }
9828         return info.getMinAspectRatio();
9829     }
9830 
9831     private boolean isParentFullscreenPortrait() {
9832         final WindowContainer parent = getParent();
9833         return parent != null
9834                 && parent.getConfiguration().orientation == ORIENTATION_PORTRAIT
9835                 && parent.getWindowConfiguration().getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
9836     }
9837 
9838     float getMaxAspectRatio() {
9839         if (mTransparentPolicy.isRunning()) {
9840             return mTransparentPolicy.getInheritedMaxAspectRatio();
9841         }
9842         return info.getMaxAspectRatio();
9843     }
9844 
9845     /**
9846      * Returns true if the activity has maximum or minimum aspect ratio.
9847      */
9848     private boolean hasFixedAspectRatio() {
9849         return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0;
9850     }
9851 
9852     /**
9853      * Returns the aspect ratio of the given {@code rect}.
9854      */
9855     static float computeAspectRatio(Rect rect) {
9856         final int width = rect.width();
9857         final int height = rect.height();
9858         if (width == 0 || height == 0) {
9859             return 0;
9860         }
9861         return Math.max(width, height) / (float) Math.min(width, height);
9862     }
9863 
9864     /**
9865      * @return {@code true} if this activity was reparented to another display but
9866      *         {@link #ensureActivityConfiguration} is not called.
9867      */
9868     boolean shouldUpdateConfigForDisplayChanged() {
9869         return mLastReportedDisplayId != getDisplayId();
9870     }
9871 
9872     boolean ensureActivityConfiguration() {
9873         return ensureActivityConfiguration(false /* ignoreVisibility */);
9874     }
9875 
9876     /**
9877      * Make sure the given activity matches the current configuration. Ensures the HistoryRecord
9878      * is updated with the correct configuration and all other bookkeeping is handled.
9879      *
9880      * @param ignoreVisibility If we should try to relaunch the activity even if it is invisible
9881      *                         (stopped state). This is useful for the case where we know the
9882      *                         activity will be visible soon and we want to ensure its configuration
9883      *                         before we make it visible.
9884      * @return False if the activity was relaunched and true if it wasn't relaunched because we
9885      *         can't or the app handles the specific configuration that is changing.
9886      */
9887     boolean ensureActivityConfiguration(boolean ignoreVisibility) {
9888         final Task rootTask = getRootTask();
9889         if (rootTask.mConfigWillChange) {
9890             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
9891                     + "(will change): %s", this);
9892             return true;
9893         }
9894 
9895         // We don't worry about activities that are finishing.
9896         if (finishing) {
9897             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter "
9898                     + "in finishing %s", this);
9899             return true;
9900         }
9901 
9902         if (isState(DESTROYED)) {
9903             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
9904                     + "in destroyed state %s", this);
9905             return true;
9906         }
9907 
9908         if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
9909             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
9910                     + "invisible: %s", this);
9911             return true;
9912         }
9913 
9914         if (isConfigurationDispatchPaused()) {
9915             return true;
9916         }
9917 
9918         return updateReportedConfigurationAndSend();
9919     }
9920 
9921     /**
9922      * @return {@code true} if the Camera is active for the current activity
9923      */
9924     boolean isCameraActive() {
9925         return mDisplayContent != null
9926                 && mDisplayContent.getDisplayRotationCompatPolicy() != null
9927                 && mDisplayContent.getDisplayRotationCompatPolicy()
9928                     .isCameraActive(this, /* mustBeFullscreen */ true);
9929     }
9930 
9931     boolean updateReportedConfigurationAndSend() {
9932         if (isConfigurationDispatchPaused()) {
9933             Slog.wtf(TAG, "trying to update reported(client) config while dispatch is paused");
9934         }
9935         ProtoLog.v(WM_DEBUG_CONFIGURATION, "Ensuring correct "
9936                 + "configuration: %s", this);
9937 
9938         final int newDisplayId = getDisplayId();
9939         final boolean displayChanged = mLastReportedDisplayId != newDisplayId;
9940         if (displayChanged) {
9941             mLastReportedDisplayId = newDisplayId;
9942         }
9943 
9944         // Calling from here rather than from onConfigurationChanged because it's possible that
9945         // onConfigurationChanged was called before mVisibleRequested became true and
9946         // mCompatDisplayInsets may not be called again when mVisibleRequested changes. And we
9947         // don't want to save mCompatDisplayInsets in onConfigurationChanged without visibility
9948         // check to avoid remembering obsolete configuration which can lead to unnecessary
9949         // size-compat mode.
9950         if (mVisibleRequested) {
9951             // Calling from here rather than resolveOverrideConfiguration to ensure that this is
9952             // called after full config is updated in ConfigurationContainer#onConfigurationChanged.
9953             updateCompatDisplayInsets();
9954         }
9955 
9956         // Short circuit: if the two full configurations are equal (the common case), then there is
9957         // nothing to do.  We test the full configuration instead of the global and merged override
9958         // configurations because there are cases (like moving a task to the root pinned task) where
9959         // the combine configurations are equal, but would otherwise differ in the override config
9960         mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration());
9961         final ActivityWindowInfo newActivityWindowInfo = getActivityWindowInfo();
9962         final boolean isActivityWindowInfoChanged = Flags.activityWindowInfoFlag()
9963                 && !mLastReportedActivityWindowInfo.equals(newActivityWindowInfo);
9964         if (!displayChanged && !isActivityWindowInfoChanged
9965                 && getConfiguration().equals(mTmpConfig)) {
9966             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display "
9967                     + "unchanged in %s", this);
9968             return true;
9969         }
9970 
9971         // Okay we now are going to make this activity have the new config.
9972         // But then we need to figure out how it needs to deal with that.
9973 
9974         // Find changes between last reported merged configuration and the current one. This is used
9975         // to decide whether to relaunch an activity or just report a configuration change.
9976         final int changes = getConfigurationChanges(mTmpConfig);
9977 
9978         // Update last reported values.
9979         final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
9980 
9981         setLastReportedConfiguration(getProcessGlobalConfiguration(), newMergedOverrideConfig);
9982         setLastReportedActivityWindowInfo(newActivityWindowInfo);
9983 
9984         if (mState == INITIALIZING) {
9985             // No need to relaunch or schedule new config for activity that hasn't been launched
9986             // yet. We do, however, return after applying the config to activity record, so that
9987             // it will use it for launch transaction.
9988             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check for "
9989                     + "initializing activity: %s", this);
9990             return true;
9991         }
9992 
9993         if (changes == 0) {
9994             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration no differences in %s",
9995                     this);
9996             // There are no significant differences, so we won't relaunch but should still deliver
9997             // the new configuration to the client process.
9998             if (displayChanged) {
9999                 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig,
10000                         newActivityWindowInfo);
10001             } else {
10002                 scheduleConfigurationChanged(newMergedOverrideConfig, newActivityWindowInfo);
10003             }
10004             notifyActivityRefresherAboutConfigurationChange(
10005                     mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig);
10006             return true;
10007         }
10008 
10009         ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration changes for %s, "
10010                 + "allChanges=%s", this, Configuration.configurationDiffToString(changes));
10011 
10012         // If the activity isn't currently running, just leave the new configuration and it will
10013         // pick that up next time it starts.
10014         if (!attachedToProcess()) {
10015             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter not running %s", this);
10016             return true;
10017         }
10018 
10019         // Figure out how to handle the changes between the configurations.
10020         ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=0x%s, "
10021                 + "handles=0x%s, mLastReportedConfiguration=%s", info.name,
10022                 Integer.toHexString(changes), Integer.toHexString(info.getRealConfigChanged()),
10023                 mLastReportedConfiguration);
10024 
10025         if (shouldRelaunchLocked(changes, mTmpConfig)) {
10026             // Aha, the activity isn't handling the change, so DIE DIE DIE.
10027             if (mVisible && mAtmService.mTmpUpdateConfigurationResult.mIsUpdating
10028                     && !mTransitionController.isShellTransitionsEnabled()) {
10029                 startFreezingScreenLocked(app, mAtmService.mTmpUpdateConfigurationResult.changes);
10030             }
10031             final boolean displayMayChange = mTmpConfig.windowConfiguration.getDisplayRotation()
10032                     != getWindowConfiguration().getDisplayRotation()
10033                     || !mTmpConfig.windowConfiguration.getMaxBounds().equals(
10034                             getWindowConfiguration().getMaxBounds());
10035             final boolean isAppResizeOnly = !displayMayChange
10036                     && (changes & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE
10037                             | CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)) == 0;
10038             // Do not preserve window if it is freezing screen because the original window won't be
10039             // able to update drawn state that causes freeze timeout.
10040             // TODO(b/258618073): Always preserve if possible.
10041             final boolean preserveWindow = isAppResizeOnly && !mFreezingScreen;
10042             final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
10043             if (hasResizeChange) {
10044                 final boolean isDragResizing = task.isDragResizing();
10045                 mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE
10046                         : RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
10047             } else {
10048                 mRelaunchReason = RELAUNCH_REASON_NONE;
10049             }
10050             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s", this);
10051             if (!mVisibleRequested) {
10052                 ProtoLog.v(WM_DEBUG_STATES, "Config is relaunching invisible "
10053                         + "activity %s called by %s", this, Debug.getCallers(4));
10054             }
10055             relaunchActivityLocked(preserveWindow, changes);
10056 
10057             // All done...  tell the caller we weren't able to keep this activity around.
10058             return false;
10059         }
10060 
10061         // Default case: the activity can handle this new configuration, so hand it over.
10062         // NOTE: We only forward the override configuration as the system level configuration
10063         // changes is always sent to all processes when they happen so it can just use whatever
10064         // system level configuration it last got.
10065         if (displayChanged) {
10066             scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig,
10067                     newActivityWindowInfo);
10068         } else {
10069             scheduleConfigurationChanged(newMergedOverrideConfig, newActivityWindowInfo);
10070         }
10071         notifyActivityRefresherAboutConfigurationChange(
10072                 mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig);
10073         return true;
10074     }
10075 
10076     private void notifyActivityRefresherAboutConfigurationChange(
10077             Configuration newConfig, Configuration lastReportedConfig) {
10078         if (mDisplayContent.mActivityRefresher == null
10079                 || !shouldBeResumed(/* activeActivity */ null)) {
10080             return;
10081         }
10082         mDisplayContent.mActivityRefresher.onActivityConfigurationChanging(
10083                 this, newConfig, lastReportedConfig);
10084     }
10085 
10086     /** Get process configuration, or global config if the process is not set. */
10087     private Configuration getProcessGlobalConfiguration() {
10088         return app != null ? app.getConfiguration() : mAtmService.getGlobalConfiguration();
10089     }
10090 
10091     /**
10092      * When assessing a configuration change, decide if the changes flags and the new configurations
10093      * should cause the Activity to relaunch.
10094      *
10095      * @param changes the changes due to the given configuration.
10096      * @param changesConfig the configuration that was used to calculate the given changes via a
10097      *        call to getConfigurationChanges.
10098      */
10099     private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {
10100         int configChanged = info.getRealConfigChanged();
10101         boolean onlyVrUiModeChanged = onlyVrUiModeChanged(changes, changesConfig);
10102 
10103         // Override for apps targeting pre-O sdks
10104         // If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode
10105         // to the config change.
10106         // For O and later, apps will be required to add configChanges="uimode" to their manifest.
10107         if (info.applicationInfo.targetSdkVersion < O
10108                 && requestedVrComponent != null
10109                 && onlyVrUiModeChanged) {
10110             configChanged |= CONFIG_UI_MODE;
10111         }
10112 
10113         // TODO(b/274944389): remove workaround after long-term solution is implemented
10114         // Don't restart due to desk mode change if the app does not have desk resources.
10115         if (mWmService.mSkipActivityRelaunchWhenDocking && onlyDeskInUiModeChanged(changesConfig)
10116                 && !hasDeskResources()) {
10117             configChanged |= CONFIG_UI_MODE;
10118         }
10119 
10120         return (changes & (~configChanged)) != 0;
10121     }
10122 
10123     /**
10124      * Returns true if the configuration change is solely due to the UI mode switching into or out
10125      * of UI_MODE_TYPE_VR_HEADSET.
10126      */
10127     private boolean onlyVrUiModeChanged(int changes, Configuration lastReportedConfig) {
10128         final Configuration currentConfig = getConfiguration();
10129         return changes == CONFIG_UI_MODE && (isInVrUiMode(currentConfig)
10130             != isInVrUiMode(lastReportedConfig));
10131     }
10132 
10133     /**
10134      * Returns true if the uiMode configuration changed, and desk mode
10135      * ({@link android.content.res.Configuration#UI_MODE_TYPE_DESK}) was the only change to uiMode.
10136      */
10137     private boolean onlyDeskInUiModeChanged(Configuration lastReportedConfig) {
10138         final Configuration currentConfig = getConfiguration();
10139 
10140         boolean deskModeChanged = isInDeskUiMode(currentConfig) != isInDeskUiMode(
10141                 lastReportedConfig);
10142         // UI mode contains fields other than the UI mode type, so determine if any other fields
10143         // changed.
10144         boolean uiModeOtherFieldsChanged =
10145                 (currentConfig.uiMode & ~UI_MODE_TYPE_MASK) != (lastReportedConfig.uiMode
10146                         & ~UI_MODE_TYPE_MASK);
10147 
10148         return deskModeChanged && !uiModeOtherFieldsChanged;
10149     }
10150 
10151     /**
10152      * Determines whether or not the application has desk mode resources.
10153      */
10154     boolean hasDeskResources() {
10155         if (mHasDeskResources != null) {
10156             // We already determined this, return the cached value.
10157             return mHasDeskResources;
10158         }
10159 
10160         mHasDeskResources = false;
10161         try {
10162             Resources packageResources = mAtmService.mContext.createPackageContextAsUser(
10163                     packageName, 0, UserHandle.of(mUserId)).getResources();
10164             for (Configuration sizeConfiguration :
10165                     packageResources.getSizeAndUiModeConfigurations()) {
10166                 if (isInDeskUiMode(sizeConfiguration)) {
10167                     mHasDeskResources = true;
10168                     break;
10169                 }
10170             }
10171         } catch (PackageManager.NameNotFoundException e) {
10172             Slog.w(TAG, "Exception thrown during checking for desk resources " + this, e);
10173         }
10174         return mHasDeskResources;
10175     }
10176 
10177     private int getConfigurationChanges(Configuration lastReportedConfig) {
10178         // Determine what has changed.  May be nothing, if this is a config that has come back from
10179         // the app after going idle.  In that case we just want to leave the official config object
10180         // now in the activity and do nothing else.
10181         int changes = lastReportedConfig.diff(getConfiguration());
10182         changes = SizeConfigurationBuckets.filterDiff(
10183                     changes, lastReportedConfig, getConfiguration(), mSizeConfigurations);
10184         // We don't want window configuration to cause relaunches.
10185         if ((changes & CONFIG_WINDOW_CONFIGURATION) != 0) {
10186             changes &= ~CONFIG_WINDOW_CONFIGURATION;
10187         }
10188 
10189         return changes;
10190     }
10191 
10192     private static boolean hasResizeChange(int change) {
10193         return (change & (CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
10194                 | CONFIG_SCREEN_LAYOUT)) != 0;
10195     }
10196 
10197     void relaunchActivityLocked(boolean preserveWindow, int configChangeFlags) {
10198         if (mAtmService.mSuppressResizeConfigChanges && preserveWindow) {
10199             return;
10200         }
10201         if (!preserveWindow) {
10202             // If the activity is the IME input target, ensure storing the last IME shown state
10203             // before relaunching it for restoring the IME visibility once its new window focused.
10204             final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget();
10205             mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null
10206                     && imeInputTarget.getWindowState().mActivityRecord == this
10207                     && mDisplayContent.mInputMethodWindow != null
10208                     && mDisplayContent.mInputMethodWindow.isVisible();
10209         }
10210         // Do not waiting for translucent activity if it is going to relaunch.
10211         final Task rootTask = getRootTask();
10212         if (rootTask != null && rootTask.mTranslucentActivityWaiting == this) {
10213             rootTask.checkTranslucentActivityWaiting(null);
10214         }
10215         final boolean andResume = shouldBeResumed(null /*activeActivity*/);
10216         List<ResultInfo> pendingResults = null;
10217         List<ReferrerIntent> pendingNewIntents = null;
10218         if (andResume) {
10219             pendingResults = results;
10220             pendingNewIntents = newIntents;
10221         }
10222         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
10223                 "Relaunching: " + this + " with results=" + pendingResults
10224                         + " newIntents=" + pendingNewIntents + " andResume=" + andResume
10225                         + " preserveWindow=" + preserveWindow);
10226         if (andResume) {
10227             EventLogTags.writeWmRelaunchResumeActivity(mUserId, System.identityHashCode(this),
10228                     task.mTaskId, shortComponentName, Integer.toHexString(configChangeFlags));
10229         } else {
10230             EventLogTags.writeWmRelaunchActivity(mUserId, System.identityHashCode(this),
10231                     task.mTaskId, shortComponentName, Integer.toHexString(configChangeFlags));
10232         }
10233 
10234         try {
10235             ProtoLog.i(WM_DEBUG_STATES, "Moving to %s Relaunching %s callers=%s" ,
10236                     (andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6));
10237             final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(token,
10238                     pendingResults, pendingNewIntents, configChangeFlags,
10239                     new MergedConfiguration(getProcessGlobalConfiguration(),
10240                             getMergedOverrideConfiguration()),
10241                     preserveWindow, getActivityWindowInfo());
10242             final ActivityLifecycleItem lifecycleItem;
10243             if (andResume) {
10244                 lifecycleItem = ResumeActivityItem.obtain(token, isTransitionForward(),
10245                         shouldSendCompatFakeFocus());
10246             } else {
10247                 lifecycleItem = PauseActivityItem.obtain(token);
10248             }
10249             mAtmService.getLifecycleManager().scheduleTransactionAndLifecycleItems(
10250                     app.getThread(), callbackItem, lifecycleItem);
10251             startRelaunching();
10252             // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
10253             // request resume if this activity is currently resumed, which implies we aren't
10254             // sleeping.
10255         } catch (RemoteException e) {
10256             Slog.w(TAG, "Failed to relaunch " + this + ": " + e);
10257         }
10258 
10259         if (andResume) {
10260             ProtoLog.d(WM_DEBUG_STATES, "Resumed after relaunch %s", this);
10261             results = null;
10262             newIntents = null;
10263             mAtmService.getAppWarningsLocked().onResumeActivity(this);
10264         } else {
10265             removePauseTimeout();
10266             setState(PAUSED, "relaunchActivityLocked");
10267         }
10268 
10269         // The activity may be waiting for stop, but that is no longer appropriate for it.
10270         mTaskSupervisor.mStoppingActivities.remove(this);
10271     }
10272 
10273     /**
10274      * Request the process of the activity to restart with its saved state (from
10275      * {@link android.app.Activity#onSaveInstanceState}) if possible. It also forces to recompute
10276      * the override configuration. Note if the activity is in background, the process will be killed
10277      * directly with keeping its record.
10278      */
10279     void restartProcessIfVisible() {
10280         if (finishing) return;
10281         Slog.i(TAG, "Request to restart process of " + this);
10282 
10283         // Reset the existing override configuration so it can be updated according to the latest
10284         // configuration.
10285         clearSizeCompatMode();
10286 
10287         if (!attachedToProcess()) {
10288             return;
10289         }
10290 
10291         // The restarting state avoids removing this record when process is died.
10292         setState(RESTARTING_PROCESS, "restartActivityProcess");
10293 
10294         if (!mVisibleRequested || mHaveState) {
10295             // Kill its process immediately because the activity should be in background.
10296             // The activity state will be update to {@link #DESTROYED} in
10297             // {@link ActivityStack#cleanUp} when handling process died.
10298             mAtmService.mH.post(() -> {
10299                 final WindowProcessController wpc;
10300                 synchronized (mAtmService.mGlobalLock) {
10301                     if (!hasProcess()
10302                             || app.getReportedProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND) {
10303                         return;
10304                     }
10305                     wpc = app;
10306                 }
10307                 mAtmService.mAmInternal.killProcess(wpc.mName, wpc.mUid, "resetConfig");
10308             });
10309             return;
10310         }
10311 
10312         if (mTransitionController.isShellTransitionsEnabled()) {
10313             final Transition transition = new Transition(TRANSIT_RELAUNCH, 0 /* flags */,
10314                     mTransitionController, mWmService.mSyncEngine);
10315             mTransitionController.startCollectOrQueue(transition, (deferred) -> {
10316                 if (mState != RESTARTING_PROCESS || !attachedToProcess()) {
10317                     transition.abort();
10318                     return;
10319                 }
10320                 // Request invisible so there will be a change after the activity is restarted
10321                 // to be visible.
10322                 setVisibleRequested(false);
10323                 transition.collect(this);
10324                 mTransitionController.requestStartTransition(transition, task,
10325                         null /* remoteTransition */, null /* displayChange */);
10326                 scheduleStopForRestartProcess();
10327             });
10328         } else {
10329             startFreezingScreen();
10330             scheduleStopForRestartProcess();
10331         }
10332     }
10333 
10334     private void scheduleStopForRestartProcess() {
10335         // The process will be killed until the activity reports stopped with saved state (see
10336         // {@link ActivityTaskManagerService.activityStopped}).
10337         try {
10338             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
10339                     StopActivityItem.obtain(token));
10340         } catch (RemoteException e) {
10341             Slog.w(TAG, "Exception thrown during restart " + this, e);
10342         }
10343         mTaskSupervisor.scheduleRestartTimeout(this);
10344     }
10345 
10346     boolean isProcessRunning() {
10347         WindowProcessController proc = app;
10348         if (proc == null) {
10349             proc = mAtmService.mProcessNames.get(processName, info.applicationInfo.uid);
10350         }
10351         return proc != null && proc.hasThread();
10352     }
10353 
10354     /**
10355      * @return Whether a task snapshot starting window may be shown.
10356      */
10357     private boolean allowTaskSnapshot() {
10358         if (newIntents == null) {
10359             return true;
10360         }
10361 
10362         // Restrict task snapshot starting window to launcher start, or is same as the last
10363         // delivered intent, or there is no intent at all (eg. task being brought to front). If
10364         // the intent is something else, likely the app is going to show some specific page or
10365         // view, instead of what's left last time.
10366         for (int i = newIntents.size() - 1; i >= 0; i--) {
10367             final Intent intent = newIntents.get(i);
10368             if (intent == null || ActivityRecord.isMainIntent(intent)) {
10369                 continue;
10370             }
10371 
10372             final boolean sameIntent = mLastNewIntent != null ? mLastNewIntent.filterEquals(intent)
10373                     : this.intent.filterEquals(intent);
10374             if (!sameIntent || intent.getExtras() != null) {
10375                 return false;
10376             }
10377         }
10378         return true;
10379     }
10380 
10381     /**
10382      * Returns {@code true} if the associated activity has the no history flag set on it.
10383      * {@code false} otherwise.
10384      */
10385     boolean isNoHistory() {
10386         return (intent.getFlags() & FLAG_ACTIVITY_NO_HISTORY) != 0
10387                 || (info.flags & FLAG_NO_HISTORY) != 0;
10388     }
10389 
10390     void saveToXml(TypedXmlSerializer out) throws IOException, XmlPullParserException {
10391         out.attributeLong(null, ATTR_ID, createTime);
10392         out.attributeInt(null, ATTR_LAUNCHEDFROMUID, launchedFromUid);
10393         if (launchedFromPackage != null) {
10394             out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
10395         }
10396         if (launchedFromFeatureId != null) {
10397             out.attribute(null, ATTR_LAUNCHEDFROMFEATURE, launchedFromFeatureId);
10398         }
10399         if (resolvedType != null) {
10400             out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
10401         }
10402         out.attributeBoolean(null, ATTR_COMPONENTSPECIFIED, componentSpecified);
10403         out.attributeInt(null, ATTR_USERID, mUserId);
10404 
10405         if (taskDescription != null) {
10406             taskDescription.saveToXml(out);
10407         }
10408 
10409         out.startTag(null, TAG_INTENT);
10410         intent.saveToXml(out);
10411         out.endTag(null, TAG_INTENT);
10412 
10413         if (isPersistable() && mPersistentState != null) {
10414             out.startTag(null, TAG_PERSISTABLEBUNDLE);
10415             mPersistentState.saveToXml(out);
10416             out.endTag(null, TAG_PERSISTABLEBUNDLE);
10417         }
10418 
10419         if (android.security.Flags.contentUriPermissionApis()) {
10420             ActivityCallerState.CallerInfo initialCallerInfo = mCallerState.getCallerInfoOrNull(
10421                     initialCallerInfoAccessToken);
10422             if (initialCallerInfo != null) {
10423                 out.startTag(null, TAG_INITIAL_CALLER_INFO);
10424                 initialCallerInfo.saveToXml(out);
10425                 out.endTag(null, TAG_INITIAL_CALLER_INFO);
10426             }
10427         }
10428     }
10429 
10430     static ActivityRecord restoreFromXml(TypedXmlPullParser in,
10431             ActivityTaskSupervisor taskSupervisor) throws IOException, XmlPullParserException {
10432         Intent intent = null;
10433         PersistableBundle persistentState = null;
10434         int launchedFromUid = in.getAttributeInt(null, ATTR_LAUNCHEDFROMUID, 0);
10435         String launchedFromPackage = in.getAttributeValue(null, ATTR_LAUNCHEDFROMPACKAGE);
10436         String launchedFromFeature = in.getAttributeValue(null, ATTR_LAUNCHEDFROMFEATURE);
10437         String resolvedType = in.getAttributeValue(null, ATTR_RESOLVEDTYPE);
10438         boolean componentSpecified = in.getAttributeBoolean(null, ATTR_COMPONENTSPECIFIED, false);
10439         int userId = in.getAttributeInt(null, ATTR_USERID, 0);
10440         long createTime = in.getAttributeLong(null, ATTR_ID, -1);
10441         final int outerDepth = in.getDepth();
10442         ActivityCallerState.CallerInfo initialCallerInfo = null;
10443 
10444         TaskDescription taskDescription = new TaskDescription();
10445         taskDescription.restoreFromXml(in);
10446 
10447         int event;
10448         while (((event = in.next()) != END_DOCUMENT) &&
10449                 (event != END_TAG || in.getDepth() >= outerDepth)) {
10450             if (event == START_TAG) {
10451                 final String name = in.getName();
10452                 if (DEBUG)
10453                         Slog.d(TaskPersister.TAG, "ActivityRecord: START_TAG name=" + name);
10454                 if (TAG_INTENT.equals(name)) {
10455                     intent = Intent.restoreFromXml(in);
10456                     if (DEBUG)
10457                             Slog.d(TaskPersister.TAG, "ActivityRecord: intent=" + intent);
10458                 } else if (TAG_PERSISTABLEBUNDLE.equals(name)) {
10459                     persistentState = PersistableBundle.restoreFromXml(in);
10460                     if (DEBUG) Slog.d(TaskPersister.TAG,
10461                             "ActivityRecord: persistentState=" + persistentState);
10462                 } else if (android.security.Flags.contentUriPermissionApis()
10463                         && TAG_INITIAL_CALLER_INFO.equals(name)) {
10464                     initialCallerInfo = ActivityCallerState.CallerInfo.restoreFromXml(in);
10465                 } else {
10466                     Slog.w(TAG, "restoreActivity: unexpected name=" + name);
10467                     XmlUtils.skipCurrentTag(in);
10468                 }
10469             }
10470         }
10471 
10472         if (intent == null) {
10473             throw new XmlPullParserException("restoreActivity error intent=" + intent);
10474         }
10475 
10476         final ActivityTaskManagerService service = taskSupervisor.mService;
10477         final ActivityInfo aInfo = taskSupervisor.resolveActivity(intent, resolvedType, 0, null,
10478                 userId, Binder.getCallingUid(), 0);
10479         if (aInfo == null) {
10480             throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent +
10481                     " resolvedType=" + resolvedType);
10482         }
10483         final ActivityRecord r = new ActivityRecord.Builder(service)
10484                 .setLaunchedFromUid(launchedFromUid)
10485                 .setLaunchedFromPackage(launchedFromPackage)
10486                 .setLaunchedFromFeature(launchedFromFeature)
10487                 .setIntent(intent)
10488                 .setResolvedType(resolvedType)
10489                 .setActivityInfo(aInfo)
10490                 .setComponentSpecified(componentSpecified)
10491                 .setPersistentState(persistentState)
10492                 .setTaskDescription(taskDescription)
10493                 .setCreateTime(createTime)
10494                 .build();
10495 
10496         if (android.security.Flags.contentUriPermissionApis() && initialCallerInfo != null) {
10497             r.mCallerState.add(r.initialCallerInfoAccessToken, initialCallerInfo);
10498         }
10499         return r;
10500     }
10501 
10502     private static boolean isInVrUiMode(Configuration config) {
10503         return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
10504     }
10505 
10506     private static boolean isInDeskUiMode(Configuration config) {
10507         return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_DESK;
10508     }
10509 
10510     String getProcessName() {
10511         return info.applicationInfo.processName;
10512     }
10513 
10514     int getUid() {
10515         return info.applicationInfo.uid;
10516     }
10517 
10518     boolean isUid(int uid) {
10519         return info.applicationInfo.uid == uid;
10520     }
10521 
10522     int getPid() {
10523         return app != null ? app.getPid() : 0;
10524     }
10525 
10526     int getLaunchedFromPid() {
10527         return launchedFromPid;
10528     }
10529 
10530     int getLaunchedFromUid() {
10531         return launchedFromUid;
10532     }
10533 
10534     /**
10535      * Gets the referrer package name with respect to package visibility. This method returns null
10536      * if the given package is not visible to this activity.
10537      */
10538     String getFilteredReferrer(String referrerPackage) {
10539         if (referrerPackage == null || (!referrerPackage.equals(packageName)
10540                 && mWmService.mPmInternal.filterAppAccess(
10541                         referrerPackage, info.applicationInfo.uid, mUserId))) {
10542             return null;
10543         }
10544         return referrerPackage;
10545     }
10546 
10547     /**
10548      * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag
10549      * {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord
10550      * should be visible depending on Keyguard state.
10551      *
10552      * @return true if the screen can be turned on, false otherwise.
10553      */
10554     boolean canTurnScreenOn() {
10555         if (!getTurnScreenOnFlag()) {
10556             return false;
10557         }
10558         return mCurrentLaunchCanTurnScreenOn
10559                 && mTaskSupervisor.getKeyguardController().checkKeyguardVisibility(this);
10560     }
10561 
10562     void setTurnScreenOn(boolean turnScreenOn) {
10563         mTurnScreenOn = turnScreenOn;
10564     }
10565 
10566     void setAllowCrossUidActivitySwitchFromBelow(boolean allowed) {
10567         mAllowCrossUidActivitySwitchFromBelow = allowed;
10568     }
10569 
10570     boolean getTurnScreenOnFlag() {
10571         return mTurnScreenOn || containsTurnScreenOnWindow();
10572     }
10573 
10574     private boolean containsTurnScreenOnWindow() {
10575         // When we are relaunching, it is possible for us to be unfrozen before our previous
10576         // windows have been added back. Using the cached value ensures that our previous
10577         // showWhenLocked preference is honored until relaunching is complete.
10578         if (isRelaunching()) {
10579             return mLastContainsTurnScreenOnWindow;
10580         }
10581         for (int i = mChildren.size() - 1; i >= 0; i--) {
10582             if ((mChildren.get(i).mAttrs.flags & LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
10583                 return true;
10584             }
10585         }
10586         return false;
10587     }
10588 
10589     /**
10590      * Check if this activity is able to resume. For pre-Q apps, only the topmost activities of each
10591      * process are allowed to be resumed.
10592      *
10593      * @return true if this activity can be resumed.
10594      */
10595     boolean canResumeByCompat() {
10596         return app == null || app.updateTopResumingActivityInProcessIfNeeded(this);
10597     }
10598 
10599     boolean isTopRunningActivity() {
10600         return mRootWindowContainer.topRunningActivity() == this;
10601     }
10602 
10603     /**
10604      * @return {@code true} if this is the focused activity on its current display, {@code false}
10605      * otherwise.
10606      */
10607     boolean isFocusedActivityOnDisplay() {
10608         return mDisplayContent.forAllTaskDisplayAreas(taskDisplayArea ->
10609                 taskDisplayArea.getFocusedActivity() == this);
10610     }
10611 
10612 
10613     /**
10614      * Check if this is the root of the task - first activity that is not finishing, starting from
10615      * the bottom of the task. If all activities are finishing - then this method will return
10616      * {@code true} if the activity is at the bottom.
10617      *
10618      * NOTE: This is different from 'effective root' - an activity that defines the task identity.
10619      */
10620     boolean isRootOfTask() {
10621         if (task == null) {
10622             return false;
10623         }
10624         final ActivityRecord rootActivity = task.getRootActivity(true);
10625         return this == rootActivity;
10626     }
10627 
10628     void setTaskOverlay(boolean taskOverlay) {
10629         mTaskOverlay = taskOverlay;
10630         setAlwaysOnTop(mTaskOverlay);
10631     }
10632 
10633     boolean isTaskOverlay() {
10634         return mTaskOverlay;
10635     }
10636 
10637     @Override
10638     public boolean isAlwaysOnTop() {
10639         return mTaskOverlay || super.isAlwaysOnTop();
10640     }
10641 
10642     @Override
10643     boolean showToCurrentUser() {
10644         return mShowForAllUsers || mWmService.isUserVisible(mUserId);
10645     }
10646 
10647     @Override
10648     boolean canCustomizeAppTransition() {
10649         return true;
10650     }
10651 
10652     @Override
10653     public String toString() {
10654         if (stringName != null) {
10655             return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) +
10656                     (finishing ? " f}" : "") + (mIsExiting ? " isExiting" : "") + "}";
10657         }
10658         StringBuilder sb = new StringBuilder(128);
10659         sb.append("ActivityRecord{");
10660         sb.append(Integer.toHexString(System.identityHashCode(this)));
10661         sb.append(" u");
10662         sb.append(mUserId);
10663         sb.append(' ');
10664         sb.append(intent.getComponent().flattenToShortString());
10665         stringName = sb.toString();
10666         return stringName;
10667     }
10668 
10669     /**
10670      * Write all fields to an {@code ActivityRecordProto}. This assumes the
10671      * {@code ActivityRecordProto} is the outer-most proto data.
10672      */
10673     void dumpDebug(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) {
10674         writeNameToProto(proto, NAME);
10675         super.dumpDebug(proto, WINDOW_TOKEN, logLevel);
10676         proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
10677         proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
10678         proto.write(IS_ANIMATING, isAnimating(TRANSITION | PARENTS | CHILDREN,
10679                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION));
10680         if (mThumbnail != null){
10681             mThumbnail.dumpDebug(proto, THUMBNAIL);
10682         }
10683         proto.write(FILLS_PARENT, fillsParent());
10684         proto.write(APP_STOPPED, mAppStopped);
10685         proto.write(TRANSLUCENT, !occludesParent());
10686         proto.write(VISIBLE, mVisible);
10687         proto.write(VISIBLE_REQUESTED, mVisibleRequested);
10688         proto.write(CLIENT_VISIBLE, isClientVisible());
10689         proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
10690         proto.write(REPORTED_DRAWN, mReportedDrawn);
10691         proto.write(REPORTED_VISIBLE, reportedVisible);
10692         proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows);
10693         proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows);
10694         proto.write(ALL_DRAWN, allDrawn);
10695         proto.write(LAST_ALL_DRAWN, mLastAllDrawn);
10696         if (mStartingWindow != null) {
10697             mStartingWindow.writeIdentifierToProto(proto, STARTING_WINDOW);
10698         }
10699         proto.write(STARTING_DISPLAYED, isStartingWindowDisplayed());
10700         proto.write(STARTING_MOVED, startingMoved);
10701         proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW,
10702                 mVisibleSetFromTransferredStartingWindow);
10703 
10704         proto.write(STATE, mState.toString());
10705         proto.write(FRONT_OF_TASK, isRootOfTask());
10706         if (hasProcess()) {
10707             proto.write(PROC_ID, app.getPid());
10708         }
10709         proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled());
10710         proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
10711         proto.write(MIN_ASPECT_RATIO, getMinAspectRatio());
10712         // Only record if max bounds sandboxing is applied, if the caller has the necessary
10713         // permission to access the device configs.
10714         proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds());
10715         proto.write(ENABLE_RECENTS_SCREENSHOT, mEnableRecentsScreenshot);
10716         proto.write(LAST_DROP_INPUT_MODE, mLastDropInputMode);
10717         proto.write(OVERRIDE_ORIENTATION, getOverrideOrientation());
10718         proto.write(SHOULD_SEND_COMPAT_FAKE_FOCUS, shouldSendCompatFakeFocus());
10719         proto.write(SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT,
10720                 mLetterboxUiController.shouldForceRotateForCameraCompat());
10721         proto.write(SHOULD_REFRESH_ACTIVITY_FOR_CAMERA_COMPAT,
10722                 mLetterboxUiController.shouldRefreshActivityForCameraCompat());
10723         proto.write(SHOULD_REFRESH_ACTIVITY_VIA_PAUSE_FOR_CAMERA_COMPAT,
10724                 mLetterboxUiController.shouldRefreshActivityViaPauseForCameraCompat());
10725         proto.write(SHOULD_OVERRIDE_MIN_ASPECT_RATIO,
10726                 mLetterboxUiController.shouldOverrideMinAspectRatio());
10727         proto.write(SHOULD_IGNORE_ORIENTATION_REQUEST_LOOP,
10728                 mLetterboxUiController.shouldIgnoreOrientationRequestLoop());
10729         proto.write(SHOULD_OVERRIDE_FORCE_RESIZE_APP,
10730                 mLetterboxUiController.shouldOverrideForceResizeApp());
10731         proto.write(SHOULD_ENABLE_USER_ASPECT_RATIO_SETTINGS,
10732                 mLetterboxUiController.shouldEnableUserAspectRatioSettings());
10733         proto.write(IS_USER_FULLSCREEN_OVERRIDE_ENABLED,
10734                 mLetterboxUiController.isUserFullscreenOverrideEnabled());
10735     }
10736 
10737     @Override
10738     long getProtoFieldId() {
10739         return ACTIVITY;
10740     }
10741 
10742     @Override
10743     public void dumpDebug(ProtoOutputStream proto, long fieldId,
10744             @WindowTraceLogLevel int logLevel) {
10745         // Critical log level logs only visible elements to mitigate performance overheard
10746         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
10747             return;
10748         }
10749 
10750         final long token = proto.start(fieldId);
10751         dumpDebug(proto, logLevel);
10752         proto.end(token);
10753     }
10754 
10755     void writeNameToProto(ProtoOutputStream proto, long fieldId) {
10756         proto.write(fieldId, shortComponentName);
10757     }
10758 
10759     @Override
10760     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
10761         final long token = proto.start(fieldId);
10762         proto.write(HASH_CODE, System.identityHashCode(this));
10763         proto.write(USER_ID, mUserId);
10764         proto.write(TITLE, intent.getComponent().flattenToShortString());
10765         proto.end(token);
10766     }
10767 
10768     /**
10769      * The precomputed insets of the display in each rotation. This is used to make the size
10770      * compatibility mode activity compute the configuration without relying on its current display.
10771      */
10772     static class CompatDisplayInsets {
10773         /** The original rotation the compat insets were computed in. */
10774         final @Rotation int mOriginalRotation;
10775         /** The original requested orientation for the activity. */
10776         final @Configuration.Orientation int mOriginalRequestedOrientation;
10777         /** The container width on rotation 0. */
10778         private final int mWidth;
10779         /** The container height on rotation 0. */
10780         private final int mHeight;
10781         /** Whether the {@link Task} windowingMode represents a floating window*/
10782         final boolean mIsFloating;
10783         /**
10784          * Whether is letterboxed because of fixed orientation or aspect ratio when
10785          * the unresizable activity is first shown.
10786          */
10787         final boolean mIsInFixedOrientationOrAspectRatioLetterbox;
10788         /**
10789          * The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
10790          * is used to compute the appBounds.
10791          */
10792         final Rect[] mNonDecorInsets = new Rect[4];
10793         /**
10794          * The stableInsets for each rotation. Includes the status bar inset and the
10795          * nonDecorInsets. It is used to compute {@link Configuration#screenWidthDp} and
10796          * {@link Configuration#screenHeightDp}.
10797          */
10798         final Rect[] mStableInsets = new Rect[4];
10799 
10800         /** Constructs the environment to simulate the bounds behavior of the given container. */
10801         CompatDisplayInsets(DisplayContent display, ActivityRecord container,
10802                 @Nullable Rect letterboxedContainerBounds, boolean useOverrideInsets) {
10803             mOriginalRotation = display.getRotation();
10804             mIsFloating = container.getWindowConfiguration().tasksAreFloating();
10805             mOriginalRequestedOrientation = container.getRequestedConfigurationOrientation();
10806             if (mIsFloating) {
10807                 final Rect containerBounds = container.getWindowConfiguration().getBounds();
10808                 mWidth = containerBounds.width();
10809                 mHeight = containerBounds.height();
10810                 // For apps in freeform, the task bounds are the parent bounds from the app's
10811                 // perspective. No insets because within a window.
10812                 final Rect emptyRect = new Rect();
10813                 for (int rotation = 0; rotation < 4; rotation++) {
10814                     mNonDecorInsets[rotation] = emptyRect;
10815                     mStableInsets[rotation] = emptyRect;
10816                 }
10817                 mIsInFixedOrientationOrAspectRatioLetterbox = false;
10818                 return;
10819             }
10820 
10821             final Task task = container.getTask();
10822 
10823             mIsInFixedOrientationOrAspectRatioLetterbox = letterboxedContainerBounds != null;
10824 
10825             // Store the bounds of the Task for the non-resizable activity to use in size compat
10826             // mode so that the activity will not be resized regardless the windowing mode it is
10827             // currently in.
10828             // When an activity needs to be letterboxed because of fixed orientation or aspect
10829             // ratio, use resolved bounds instead of task bounds since the activity will be
10830             // displayed within these even if it is in size compat mode.
10831             final Rect filledContainerBounds = mIsInFixedOrientationOrAspectRatioLetterbox
10832                     ? letterboxedContainerBounds
10833                     : task != null ? task.getBounds() : display.getBounds();
10834             final boolean useActivityRotation = container.hasFixedRotationTransform()
10835                     && mIsInFixedOrientationOrAspectRatioLetterbox;
10836             final int filledContainerRotation = useActivityRotation
10837                     ? container.getWindowConfiguration().getRotation()
10838                     : display.getConfiguration().windowConfiguration.getRotation();
10839             final Point dimensions = getRotationZeroDimensions(
10840                     filledContainerBounds, filledContainerRotation);
10841             mWidth = dimensions.x;
10842             mHeight = dimensions.y;
10843 
10844             // Bounds of the filled container if it doesn't fill the display.
10845             final Rect unfilledContainerBounds =
10846                     filledContainerBounds.equals(display.getBounds()) ? null : new Rect();
10847             final DisplayPolicy policy = display.getDisplayPolicy();
10848             for (int rotation = 0; rotation < 4; rotation++) {
10849                 mNonDecorInsets[rotation] = new Rect();
10850                 mStableInsets[rotation] = new Rect();
10851                 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
10852                 final int dw = rotated ? display.mBaseDisplayHeight : display.mBaseDisplayWidth;
10853                 final int dh = rotated ? display.mBaseDisplayWidth : display.mBaseDisplayHeight;
10854                 final DisplayPolicy.DecorInsets.Info decorInfo =
10855                         policy.getDecorInsetsInfo(rotation, dw, dh);
10856                 if (useOverrideInsets) {
10857                     mStableInsets[rotation].set(decorInfo.mOverrideConfigInsets);
10858                     mNonDecorInsets[rotation].set(decorInfo.mOverrideNonDecorInsets);
10859                 } else {
10860                     mStableInsets[rotation].set(decorInfo.mConfigInsets);
10861                     mNonDecorInsets[rotation].set(decorInfo.mNonDecorInsets);
10862                 }
10863 
10864                 if (unfilledContainerBounds == null) {
10865                     continue;
10866                 }
10867                 // The insets is based on the display, but the container may be smaller than the
10868                 // display, so update the insets to exclude parts that are not intersected with the
10869                 // container.
10870                 unfilledContainerBounds.set(filledContainerBounds);
10871                 display.rotateBounds(
10872                         filledContainerRotation,
10873                         rotation,
10874                         unfilledContainerBounds);
10875                 updateInsetsForBounds(unfilledContainerBounds, dw, dh, mNonDecorInsets[rotation]);
10876                 updateInsetsForBounds(unfilledContainerBounds, dw, dh, mStableInsets[rotation]);
10877             }
10878         }
10879 
10880         /**
10881          * Gets the width and height of the {@code container} when it is not rotated, so that after
10882          * the display is rotated, we can calculate the bounds by rotating the dimensions.
10883          * @see #getBoundsByRotation
10884          */
10885         private static Point getRotationZeroDimensions(final Rect bounds, int rotation) {
10886             final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
10887             final int width = bounds.width();
10888             final int height = bounds.height();
10889             return rotated ? new Point(height, width) : new Point(width, height);
10890         }
10891 
10892         /**
10893          * Updates the display insets to exclude the parts that are not intersected with the given
10894          * bounds.
10895          */
10896         private static void updateInsetsForBounds(Rect bounds, int displayWidth, int displayHeight,
10897                 Rect inset) {
10898             inset.left = Math.max(0, inset.left - bounds.left);
10899             inset.top = Math.max(0, inset.top - bounds.top);
10900             inset.right = Math.max(0, bounds.right - displayWidth + inset.right);
10901             inset.bottom = Math.max(0, bounds.bottom - displayHeight + inset.bottom);
10902         }
10903 
10904         void getBoundsByRotation(Rect outBounds, int rotation) {
10905             final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
10906             final int dw = rotated ? mHeight : mWidth;
10907             final int dh = rotated ? mWidth : mHeight;
10908             outBounds.set(0, 0, dw, dh);
10909         }
10910 
10911         void getFrameByOrientation(Rect outBounds, int orientation) {
10912             final int longSide = Math.max(mWidth, mHeight);
10913             final int shortSide = Math.min(mWidth, mHeight);
10914             final boolean isLandscape = orientation == ORIENTATION_LANDSCAPE;
10915             outBounds.set(0, 0, isLandscape ? longSide : shortSide,
10916                     isLandscape ? shortSide : longSide);
10917         }
10918 
10919         // TODO(b/267151420): Explore removing getContainerBounds() from CompatDisplayInsets.
10920         /** Gets the horizontal centered container bounds for size compatibility mode. */
10921         void getContainerBounds(Rect outAppBounds, Rect outBounds, int rotation, int orientation,
10922                 boolean orientationRequested, boolean isFixedToUserRotation) {
10923             getFrameByOrientation(outBounds, orientation);
10924             if (mIsFloating) {
10925                 outAppBounds.set(outBounds);
10926                 return;
10927             }
10928 
10929             getBoundsByRotation(outAppBounds, rotation);
10930             final int dW = outAppBounds.width();
10931             final int dH = outAppBounds.height();
10932             final boolean isOrientationMismatched =
10933                     ((outBounds.width() > outBounds.height()) != (dW > dH));
10934 
10935             if (isOrientationMismatched && isFixedToUserRotation && orientationRequested) {
10936                 // The orientation is mismatched but the display cannot rotate. The bounds will fit
10937                 // to the short side of container.
10938                 if (orientation == ORIENTATION_LANDSCAPE) {
10939                     outBounds.bottom = (int) ((float) dW * dW / dH);
10940                     outBounds.right = dW;
10941                 } else {
10942                     outBounds.bottom = dH;
10943                     outBounds.right = (int) ((float) dH * dH / dW);
10944                 }
10945                 outBounds.offset(getCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
10946             }
10947             outAppBounds.set(outBounds);
10948 
10949             if (isOrientationMismatched) {
10950                 // One side of container is smaller than the requested size, then it will be scaled
10951                 // and the final position will be calculated according to the parent container and
10952                 // scale, so the original size shouldn't be shrunk by insets.
10953                 final Rect insets = mNonDecorInsets[rotation];
10954                 outBounds.offset(insets.left, insets.top);
10955                 outAppBounds.offset(insets.left, insets.top);
10956             } else if (rotation != ROTATION_UNDEFINED) {
10957                 // Ensure the app bounds won't overlap with insets.
10958                 TaskFragment.intersectWithInsetsIfFits(outAppBounds, outBounds,
10959                         mNonDecorInsets[rotation]);
10960             }
10961         }
10962     }
10963 
10964     private static class AppSaturationInfo {
10965         float[] mMatrix = new float[9];
10966         float[] mTranslation = new float[3];
10967 
10968         void setSaturation(@Size(9) float[] matrix, @Size(3) float[] translation) {
10969             System.arraycopy(matrix, 0, mMatrix, 0, mMatrix.length);
10970             System.arraycopy(translation, 0, mTranslation, 0, mTranslation.length);
10971         }
10972     }
10973 
10974     @Override
10975     RemoteAnimationTarget createRemoteAnimationTarget(
10976             RemoteAnimationController.RemoteAnimationRecord record) {
10977         final WindowState mainWindow = findMainWindow();
10978         if (task == null || mainWindow == null) {
10979             return null;
10980         }
10981         final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
10982                 task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect();
10983         InsetUtils.addInsets(insets, getLetterboxInsets());
10984 
10985         final RemoteAnimationTarget target = new RemoteAnimationTarget(task.mTaskId,
10986                 record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(),
10987                 new Rect(), insets,
10988                 getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
10989                 record.mAdapter.mEndBounds, task.getWindowConfiguration(),
10990                 false /*isNotInRecents*/,
10991                 record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
10992                 record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
10993         target.setShowBackdrop(record.mShowBackdrop);
10994         target.setWillShowImeOnTarget(mStartingData != null && mStartingData.hasImeSurface());
10995         target.hasAnimatingParent = record.hasAnimatingParent();
10996         return target;
10997     }
10998 
10999     @Override
11000     boolean canCreateRemoteAnimationTarget() {
11001         return true;
11002     }
11003 
11004     @Override
11005     void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
11006             Rect outSurfaceInsets) {
11007         final WindowState win = findMainWindow();
11008         if (win == null) {
11009             return;
11010         }
11011         win.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
11012     }
11013 
11014     void setPictureInPictureParams(PictureInPictureParams p) {
11015         pictureInPictureArgs.copyOnlySet(p);
11016         adjustPictureInPictureParamsIfNeeded(getBounds());
11017         getTask().getRootTask().onPictureInPictureParamsChanged();
11018     }
11019 
11020     void setShouldDockBigOverlays(boolean shouldDockBigOverlays) {
11021         this.shouldDockBigOverlays = shouldDockBigOverlays;
11022         getTask().getRootTask().onShouldDockBigOverlaysChanged();
11023     }
11024 
11025     @Override
11026     boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
11027         if (task != null && task.mSharedStartingData != null) {
11028             final WindowState startingWin = task.topStartingWindow();
11029             if (startingWin != null && startingWin.mSyncState == SYNC_STATE_READY
11030                     && mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
11031                 // The sync is ready if a drawn starting window covered the task.
11032                 return true;
11033             }
11034         }
11035         if (!super.isSyncFinished(group)) return false;
11036         if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController
11037                 .isVisibilityUnknown(this)) {
11038             return false;
11039         }
11040         if (!isVisibleRequested()) return true;
11041         if (mPendingRelaunchCount > 0) return false;
11042         // Wait for attach. That is the earliest time where we know if there will be an associated
11043         // display rotation. If we don't wait, the starting-window can finishDrawing first and
11044         // cause the display rotation to end-up in a following transition.
11045         if (!isAttached()) return false;
11046         // If visibleRequested, wait for at-least one visible child.
11047         for (int i = mChildren.size() - 1; i >= 0; --i) {
11048             if (mChildren.get(i).isVisibleRequested()) {
11049                 return true;
11050             }
11051         }
11052         return false;
11053     }
11054 
11055     @Override
11056     void finishSync(Transaction outMergedTransaction, BLASTSyncEngine.SyncGroup group,
11057             boolean cancel) {
11058         // This override is just for getting metrics. allFinished needs to be checked before
11059         // finish because finish resets all the states.
11060         final BLASTSyncEngine.SyncGroup syncGroup = getSyncGroup();
11061         if (syncGroup != null && group != getSyncGroup()) return;
11062         mLastAllReadyAtSync = allSyncFinished();
11063         super.finishSync(outMergedTransaction, group, cancel);
11064     }
11065 
11066     @Nullable
11067     Point getMinDimensions() {
11068         final ActivityInfo.WindowLayout windowLayout = info.windowLayout;
11069         if (windowLayout == null) {
11070             return null;
11071         }
11072         return new Point(windowLayout.minWidth, windowLayout.minHeight);
11073     }
11074 
11075     /**
11076      * Returns the {@link #createTime} if the top window is the `base` window. Note that do not
11077      * use the window creation time because the window could be re-created when the activity
11078      * relaunched if configuration changed.
11079      * <p>
11080      * Otherwise, return the creation time of the top window.
11081      */
11082     long getLastWindowCreateTime() {
11083         final WindowState window = getWindow(alwaysTruePredicate());
11084         return window != null && window.mAttrs.type != TYPE_BASE_APPLICATION
11085                 ? window.getCreateTime()
11086                 : createTime;
11087     }
11088 
11089     /**
11090      * Adjust the source rect hint in {@link #pictureInPictureArgs} by window bounds since
11091      * it is relative to its root view (see also b/235599028).
11092      * It is caller's responsibility to make sure this is called exactly once when we update
11093      * {@link #pictureInPictureArgs} to avoid double offset.
11094      */
11095     private void adjustPictureInPictureParamsIfNeeded(Rect windowBounds) {
11096         if (pictureInPictureArgs != null && pictureInPictureArgs.hasSourceBoundsHint()) {
11097             pictureInPictureArgs.getSourceRectHint().offset(windowBounds.left, windowBounds.top);
11098         }
11099     }
11100 
11101     private void applyLocaleOverrideIfNeeded(Configuration resolvedConfig) {
11102         // We always align the locale for ActivityEmbedding apps. System apps or some apps which
11103         // has set known cert apps can embed across different uid activity.
11104         boolean shouldAlignLocale = isEmbedded()
11105                 || (task != null && task.mAlignActivityLocaleWithTask);
11106         if (!shouldAlignLocale) {
11107             return;
11108         }
11109 
11110         boolean differentPackage = task != null
11111                 && task.realActivity != null
11112                 && !task.realActivity.getPackageName().equals(packageName);
11113         if (!differentPackage) {
11114             return;
11115         }
11116 
11117         final ActivityTaskManagerInternal.PackageConfig appConfig =
11118                 mAtmService.mPackageConfigPersister.findPackageConfiguration(
11119                         task.realActivity.getPackageName(), mUserId);
11120         // If package lookup yields locales, set the target activity's locales to match,
11121         // otherwise leave target activity as-is.
11122         if (appConfig != null && appConfig.mLocales != null && !appConfig.mLocales.isEmpty()) {
11123             resolvedConfig.setLocales(appConfig.mLocales);
11124         }
11125     }
11126 
11127     /**
11128      * Whether we should send fake focus when the activity is resumed. This is done because some
11129      * game engines wait to get focus before drawing the content of the app.
11130      */
11131     // TODO(b/263593361): Explore enabling compat fake focus for freeform.
11132     // TODO(b/263592337): Explore enabling compat fake focus for fullscreen, e.g. for when
11133     // covered with bubbles.
11134     boolean shouldSendCompatFakeFocus() {
11135         return mLetterboxUiController.shouldSendFakeFocus() && inMultiWindowMode()
11136                 && !inPinnedWindowingMode() && !inFreeformWindowingMode();
11137     }
11138 
11139     boolean canCaptureSnapshot() {
11140         if (!isSurfaceShowing() || findMainWindow() == null) {
11141             return false;
11142         }
11143         return forAllWindows(
11144                 // Ensure at least one window for the top app is visible before attempting to
11145                 // take a screenshot. Visible here means that the WSA surface is shown and has
11146                 // an alpha greater than 0.
11147                 ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown()
11148                         && ws.mWinAnimator.mLastAlpha > 0f, true  /* traverseTopToBottom */);
11149     }
11150 
11151     void overrideCustomTransition(boolean open, int enterAnim, int exitAnim, int backgroundColor) {
11152         CustomAppTransition transition = getCustomAnimation(open);
11153         if (transition == null) {
11154             transition = new CustomAppTransition();
11155             if (open) {
11156                 mCustomOpenTransition = transition;
11157             } else {
11158                 mCustomCloseTransition = transition;
11159             }
11160         }
11161 
11162         transition.mEnterAnim = enterAnim;
11163         transition.mExitAnim = exitAnim;
11164         transition.mBackgroundColor = backgroundColor;
11165     }
11166 
11167     void clearCustomTransition(boolean open) {
11168         if (open) {
11169             mCustomOpenTransition = null;
11170         } else {
11171             mCustomCloseTransition = null;
11172         }
11173     }
11174 
11175     CustomAppTransition getCustomAnimation(boolean open) {
11176         return open ? mCustomOpenTransition : mCustomCloseTransition;
11177     }
11178 
11179     // Override the WindowAnimation_(Open/Close)(Enter/Exit)Animation
11180     static class CustomAppTransition {
11181         int mEnterAnim;
11182         int mExitAnim;
11183         int mBackgroundColor;
11184     }
11185 
11186     static class Builder {
11187         private final ActivityTaskManagerService mAtmService;
11188         private WindowProcessController mCallerApp;
11189         private int mLaunchedFromPid;
11190         private int mLaunchedFromUid;
11191         private String mLaunchedFromPackage;
11192         private String mLaunchedFromFeature;
11193         private Intent mIntent;
11194         private String mResolvedType;
11195         private ActivityInfo mActivityInfo;
11196         private Configuration mConfiguration;
11197         private ActivityRecord mResultTo;
11198         private String mResultWho;
11199         private int mRequestCode;
11200         private boolean mComponentSpecified;
11201         private boolean mRootVoiceInteraction;
11202         private ActivityOptions mOptions;
11203         private ActivityRecord mSourceRecord;
11204         private PersistableBundle mPersistentState;
11205         private TaskDescription mTaskDescription;
11206         private long mCreateTime;
11207 
11208         Builder(ActivityTaskManagerService service) {
11209             mAtmService = service;
11210         }
11211 
11212         Builder setCaller(@NonNull WindowProcessController caller) {
11213             mCallerApp = caller;
11214             return this;
11215         }
11216 
11217         Builder setLaunchedFromPid(int pid) {
11218             mLaunchedFromPid = pid;
11219             return this;
11220         }
11221 
11222         Builder setLaunchedFromUid(int uid) {
11223             mLaunchedFromUid = uid;
11224             return this;
11225         }
11226 
11227         Builder setLaunchedFromPackage(String fromPackage) {
11228             mLaunchedFromPackage = fromPackage;
11229             return this;
11230         }
11231 
11232         Builder setLaunchedFromFeature(String fromFeature) {
11233             mLaunchedFromFeature = fromFeature;
11234             return this;
11235         }
11236 
11237         Builder setIntent(Intent intent) {
11238             mIntent = intent;
11239             return this;
11240         }
11241 
11242         Builder setResolvedType(String resolvedType) {
11243             mResolvedType = resolvedType;
11244             return this;
11245         }
11246 
11247         Builder setActivityInfo(ActivityInfo activityInfo) {
11248             mActivityInfo = activityInfo;
11249             return this;
11250         }
11251 
11252         Builder setResultTo(ActivityRecord resultTo) {
11253             mResultTo = resultTo;
11254             return this;
11255         }
11256 
11257         Builder setResultWho(String resultWho) {
11258             mResultWho = resultWho;
11259             return this;
11260         }
11261 
11262         Builder setRequestCode(int reqCode) {
11263             mRequestCode = reqCode;
11264             return this;
11265         }
11266 
11267         Builder setComponentSpecified(boolean componentSpecified) {
11268             mComponentSpecified = componentSpecified;
11269             return this;
11270         }
11271 
11272         Builder setRootVoiceInteraction(boolean rootVoiceInteraction) {
11273             mRootVoiceInteraction = rootVoiceInteraction;
11274             return this;
11275         }
11276 
11277         Builder setActivityOptions(ActivityOptions options) {
11278             mOptions = options;
11279             return this;
11280         }
11281 
11282         Builder setConfiguration(Configuration config) {
11283             mConfiguration = config;
11284             return this;
11285         }
11286 
11287         Builder setSourceRecord(ActivityRecord source) {
11288             mSourceRecord = source;
11289             return this;
11290         }
11291 
11292         private Builder setPersistentState(PersistableBundle persistentState) {
11293             mPersistentState = persistentState;
11294             return this;
11295         }
11296 
11297         private Builder setTaskDescription(TaskDescription taskDescription) {
11298             mTaskDescription = taskDescription;
11299             return this;
11300         }
11301 
11302         private Builder setCreateTime(long createTime) {
11303             mCreateTime = createTime;
11304             return this;
11305         }
11306 
11307         ActivityRecord build() {
11308             if (mConfiguration == null) {
11309                 mConfiguration = mAtmService.getConfiguration();
11310             }
11311             return new ActivityRecord(mAtmService, mCallerApp, mLaunchedFromPid,
11312                     mLaunchedFromUid, mLaunchedFromPackage, mLaunchedFromFeature, mIntent,
11313                     mResolvedType, mActivityInfo, mConfiguration, mResultTo, mResultWho,
11314                     mRequestCode, mComponentSpecified, mRootVoiceInteraction,
11315                     mAtmService.mTaskSupervisor, mOptions, mSourceRecord, mPersistentState,
11316                     mTaskDescription, mCreateTime);
11317         }
11318     }
11319 }
11320