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