• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     private 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 && (visible || !mDisplayContent.isSleeping())) {
5349                     Slog.e(TAG, "setVisibility=" + visible
5350                             + " while transition is not collecting or finishing "
5351                             + this + " caller=" + Debug.getCallers(8));
5352                     // Force showing the parents because they may be hidden by previous transition.
5353                     if (visible) {
5354                         final Transaction t = getSyncTransaction();
5355                         for (WindowContainer<?> p = getParent(); p != null && p != mDisplayContent;
5356                                 p = p.getParent()) {
5357                             if (p.mSurfaceControl != null) {
5358                                 t.show(p.mSurfaceControl);
5359                             }
5360                         }
5361                     }
5362                 }
5363             }
5364         }
5365 
5366         onChildVisibilityRequested(visible);
5367 
5368         final DisplayContent displayContent = getDisplayContent();
5369         displayContent.mOpeningApps.remove(this);
5370         displayContent.mClosingApps.remove(this);
5371         waitingToShow = false;
5372         setVisibleRequested(visible);
5373         mLastDeferHidingClient = deferHidingClient;
5374 
5375         if (!visible) {
5376             // If this activity is about to finish/stopped and now becomes invisible, remove it
5377             // from the unknownApp list in case the activity does not want to draw anything, which
5378             // keep the user waiting for the next transition to start.
5379             if (finishing || isState(STOPPED)) {
5380                 displayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
5381             }
5382             // Because starting window was transferred, this activity may be a trampoline which has
5383             // been occluded by next activity. If it has added windows, set client visibility
5384             // immediately to avoid the client getting RELAYOUT_RES_FIRST_TIME from relayout and
5385             // drawing an unnecessary frame.
5386             if (startingMoved && !firstWindowDrawn && hasChild()) {
5387                 setClientVisible(false);
5388             }
5389         } else {
5390             if (!appTransition.isTransitionSet()
5391                     && appTransition.isReady()) {
5392                 // Add the app mOpeningApps if transition is unset but ready. This means
5393                 // we're doing a screen freeze, and the unfreeze will wait for all opening
5394                 // apps to be ready.
5395                 displayContent.mOpeningApps.add(this);
5396             }
5397             startingMoved = false;
5398             // If the token is currently hidden (should be the common case), or has been
5399             // stopped, then we need to set up to wait for its windows to be ready.
5400             if (!isVisible() || mAppStopped) {
5401                 clearAllDrawn();
5402 
5403                 // If the app was already visible, don't reset the waitingToShow state.
5404                 if (!isVisible()) {
5405                     waitingToShow = true;
5406 
5407                     // If the client isn't hidden, we don't need to reset the drawing state.
5408                     if (!isClientVisible()) {
5409                         // Let's reset the draw state in order to prevent the starting window to be
5410                         // immediately dismissed when the app still has the surface.
5411                         forAllWindows(w -> {
5412                             if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
5413                                 w.mWinAnimator.resetDrawState();
5414 
5415                                 // Force add to mResizingWindows, so that we are guaranteed to get
5416                                 // another reportDrawn callback.
5417                                 w.forceReportingResized();
5418                             }
5419                         }, true /* traverseTopToBottom */);
5420                     }
5421                 }
5422             }
5423 
5424             // In the case where we are making an app visible but holding off for a transition,
5425             // we still need to tell the client to make its windows visible so they get drawn.
5426             // Otherwise, we will wait on performing the transition until all windows have been
5427             // drawn, they never will be, and we are sad.
5428             setClientVisible(true);
5429 
5430             requestUpdateWallpaperIfNeeded();
5431 
5432             ProtoLog.v(WM_DEBUG_ADD_REMOVE, "No longer Stopped: %s", this);
5433             mAppStopped = false;
5434 
5435             transferStartingWindowFromHiddenAboveTokenIfNeeded();
5436         }
5437 
5438         // Defer committing visibility until transition starts.
5439         if (isCollecting) {
5440             // It may be occluded by the activity above that calls convertFromTranslucent().
5441             if (!visible && mTransitionController.inPlayingTransition(this)) {
5442                 mTransitionChangeFlags |= FLAG_IS_OCCLUDED;
5443             }
5444             return;
5445         }
5446         if (inFinishingTransition) {
5447             // Let the finishing transition commit the visibility, but let the controller know
5448             // about it so that we can recover from degenerate cases.
5449             mTransitionController.mValidateCommitVis.add(this);
5450             return;
5451         }
5452         // If we are preparing an app transition, then delay changing
5453         // the visibility of this token until we execute that transition.
5454         if (deferCommitVisibilityChange(visible)) {
5455             return;
5456         }
5457 
5458         commitVisibility(visible, true /* performLayout */);
5459         updateReportedVisibilityLocked();
5460     }
5461 
5462     /**
5463      * Returns {@code true} if this activity is either added to opening-apps or closing-apps.
5464      * Then its visibility will be committed until the transition is ready.
5465      */
deferCommitVisibilityChange(boolean visible)5466     private boolean deferCommitVisibilityChange(boolean visible) {
5467         if (mTransitionController.isShellTransitionsEnabled()) {
5468             // Shell transition doesn't use opening/closing sets.
5469             return false;
5470         }
5471         if (!mDisplayContent.mAppTransition.isTransitionSet()) {
5472             // Defer committing visibility for non-home app which is animating by recents.
5473             if (isActivityTypeHome() || !isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) {
5474                 return false;
5475             }
5476         }
5477         if (mWaitForEnteringPinnedMode && mVisible == visible) {
5478             // If the visibility is not changed during enter PIP, we don't want to include it in
5479             // app transition to affect the animation theme, because the Pip organizer will
5480             // animate the entering PIP instead.
5481             return false;
5482         }
5483 
5484         // The animation will be visible soon so do not skip by screen off.
5485         final boolean ignoreScreenOn = canTurnScreenOn() || mTaskSupervisor.getKeyguardController()
5486                 .isKeyguardGoingAway(mDisplayContent.mDisplayId);
5487         // Ignore display frozen so the opening / closing transition type can be updated correctly
5488         // even if the display is frozen. And it's safe since in applyAnimation will still check
5489         // DC#okToAnimate again if the transition animation is fine to apply.
5490         if (!okToAnimate(true /* ignoreFrozen */, ignoreScreenOn)) {
5491             return false;
5492         }
5493         if (visible) {
5494             mDisplayContent.mOpeningApps.add(this);
5495             mEnteringAnimation = true;
5496         } else if (mVisible) {
5497             mDisplayContent.mClosingApps.add(this);
5498             mEnteringAnimation = false;
5499         }
5500         if ((mDisplayContent.mAppTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0) {
5501             // Add the launching-behind activity to mOpeningApps.
5502             final WindowState win = mDisplayContent.findFocusedWindow();
5503             if (win != null) {
5504                 final ActivityRecord focusedActivity = win.mActivityRecord;
5505                 if (focusedActivity != null) {
5506                     ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
5507                             "TRANSIT_FLAG_OPEN_BEHIND,  adding %s to mOpeningApps",
5508                             focusedActivity);
5509                     // Force animation to be loaded.
5510                     mDisplayContent.mOpeningApps.add(focusedActivity);
5511                 }
5512             }
5513         }
5514         return true;
5515     }
5516 
5517     @Override
applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources)5518     boolean applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter,
5519             boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
5520         if ((mTransitionChangeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
5521             return false;
5522         }
5523         // If it was set to true, reset the last request to force the transition.
5524         mRequestForceTransition = false;
5525         return super.applyAnimation(lp, transit, enter, isVoiceInteraction, sources);
5526     }
5527 
5528     /**
5529      * Update visibility to this {@link ActivityRecord}.
5530      *
5531      * <p class="note"><strong>Note: </strong> Unlike {@link #setVisibility}, this immediately
5532      * updates the visibility without starting an app transition. Since this function may start
5533      * animation on {@link WindowState} depending on app transition animation status, an app
5534      * transition animation must be started before calling this function if necessary.</p>
5535      *
5536      * @param visible {@code true} if this {@link ActivityRecord} should become visible, otherwise
5537      *                this should become invisible.
5538      * @param performLayout if {@code true}, perform surface placement after committing visibility.
5539      * @param fromTransition {@code true} if this is part of finishing a transition.
5540      */
commitVisibility(boolean visible, boolean performLayout, boolean fromTransition)5541     void commitVisibility(boolean visible, boolean performLayout, boolean fromTransition) {
5542         // Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually
5543         // been set by the app now.
5544         mVisibleSetFromTransferredStartingWindow = false;
5545         if (visible == isVisible()) {
5546             return;
5547         }
5548 
5549         final int windowsCount = mChildren.size();
5550         // With Shell-Transition, the activity will running a transition when it is visible.
5551         // It won't be included when fromTransition is true means the call from finishTransition.
5552         final boolean runningAnimation = sEnableShellTransitions ? visible
5553                 : isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION);
5554         for (int i = 0; i < windowsCount; i++) {
5555             mChildren.get(i).onAppVisibilityChanged(visible, runningAnimation);
5556         }
5557         setVisible(visible);
5558         setVisibleRequested(visible);
5559         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "commitVisibility: %s: visible=%b"
5560                         + " visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s",
5561                 this, isVisible(), mVisibleRequested, isInTransition(), runningAnimation,
5562                 Debug.getCallers(5));
5563         if (!visible) {
5564             stopFreezingScreen(true, true);
5565         } else {
5566             // If we are being set visible, and the starting window is not yet displayed,
5567             // then make sure it doesn't get displayed.
5568             if (mStartingWindow != null && !mStartingWindow.isDrawn()
5569                     && (firstWindowDrawn || allDrawn)) {
5570                 mStartingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
5571                 mStartingWindow.mLegacyPolicyVisibilityAfterAnim = false;
5572             }
5573             // We are becoming visible, so better freeze the screen with the windows that are
5574             // getting visible so we also wait for them.
5575             forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true);
5576         }
5577         // dispatchTaskInfoChangedIfNeeded() right after ActivityRecord#setVisibility() can report
5578         // the stale visible state, because the state will be updated after the app transition.
5579         // So tries to report the actual visible state again where the state is changed.
5580         Task task = getOrganizedTask();
5581         while (task != null) {
5582             task.dispatchTaskInfoChangedIfNeeded(false /* force */);
5583             task = task.getParent().asTask();
5584         }
5585         final DisplayContent displayContent = getDisplayContent();
5586         displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
5587         if (performLayout) {
5588             mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
5589                     false /*updateInputWindows*/);
5590             mWmService.mWindowPlacerLocked.performSurfacePlacement();
5591         }
5592         displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
5593         mTransitionChangeFlags = 0;
5594 
5595         postApplyAnimation(visible, fromTransition);
5596     }
5597 
commitVisibility(boolean visible, boolean performLayout)5598     void commitVisibility(boolean visible, boolean performLayout) {
5599         commitVisibility(visible, performLayout, false /* fromTransition */);
5600     }
5601 
setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation)5602     void setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation) {
5603         mNeedsLetterboxedAnimation = needsLetterboxedAnimation;
5604     }
5605 
isNeedsLetterboxedAnimation()5606     boolean isNeedsLetterboxedAnimation() {
5607         return mNeedsLetterboxedAnimation;
5608     }
5609 
isInLetterboxAnimation()5610     boolean isInLetterboxAnimation() {
5611         return mNeedsLetterboxedAnimation && isAnimating();
5612     }
5613 
5614     /**
5615      * Post process after applying an app transition animation.
5616      *
5617      * <p class="note"><strong>Note: </strong> This function must be called after the animations
5618      * have been applied and {@link #commitVisibility}.</p>
5619      *
5620      * @param visible {@code true} if this {@link ActivityRecord} has become visible, otherwise
5621      *                this has become invisible.
5622      * @param fromTransition {@code true} if this call is part of finishing a transition. This is
5623      *                       needed because the shell transition is no-longer active by the time
5624      *                       commitVisibility is called.
5625      */
postApplyAnimation(boolean visible, boolean fromTransition)5626     private void postApplyAnimation(boolean visible, boolean fromTransition) {
5627         final boolean usingShellTransitions = mTransitionController.isShellTransitionsEnabled();
5628         final boolean delayed = !usingShellTransitions && isAnimating(PARENTS | CHILDREN,
5629                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION
5630                         | ANIMATION_TYPE_RECENTS);
5631         if (!delayed && !usingShellTransitions) {
5632             // We aren't delayed anything, but exiting windows rely on the animation finished
5633             // callback being called in case the ActivityRecord was pretending to be delayed,
5634             // which we might have done because we were in closing/opening apps list.
5635             onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, null /* AnimationAdapter */);
5636             if (visible) {
5637                 // The token was made immediately visible, there will be no entrance animation.
5638                 // We need to inform the client the enter animation was finished.
5639                 mEnteringAnimation = true;
5640                 mWmService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(
5641                         token);
5642             }
5643         }
5644 
5645         // If we're becoming visible, immediately change client visibility as well. there seem
5646         // to be some edge cases where we change our visibility but client visibility never gets
5647         // updated.
5648         // If we're becoming invisible, update the client visibility if we are not running an
5649         // animation and aren't in RESUMED state. Otherwise, we'll update client visibility in
5650         // onAnimationFinished or activityStopped.
5651         if (visible || (mState != RESUMED && (usingShellTransitions || !isAnimating(
5652                 PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)))) {
5653             setClientVisible(visible);
5654         }
5655 
5656         final DisplayContent displayContent = getDisplayContent();
5657         if (!visible) {
5658             mImeInsetsFrozenUntilStartInput = true;
5659         }
5660 
5661         if (!displayContent.mClosingApps.contains(this)
5662                 && !displayContent.mOpeningApps.contains(this)
5663                 && !fromTransition) {
5664             // Take the screenshot before possibly hiding the WSA, otherwise the screenshot
5665             // will not be taken.
5666             mWmService.mSnapshotController.notifyAppVisibilityChanged(this, visible);
5667         }
5668 
5669         // If we are hidden but there is no delay needed we immediately
5670         // apply the Surface transaction so that the ActivityManager
5671         // can have some guarantee on the Surface state following
5672         // setting the visibility. This captures cases like dismissing
5673         // the docked or root pinned task where there is no app transition.
5674         //
5675         // In the case of a "Null" animation, there will be
5676         // no animation but there will still be a transition set.
5677         // We still need to delay hiding the surface such that it
5678         // can be synchronized with showing the next surface in the transition.
5679         if (!usingShellTransitions && !isVisible() && !delayed
5680                 && !displayContent.mAppTransition.isTransitionSet()) {
5681             SurfaceControl.openTransaction();
5682             try {
5683                 forAllWindows(win -> {
5684                     win.mWinAnimator.hide(getGlobalTransaction(), "immediately hidden");
5685                 }, true);
5686             } finally {
5687                 SurfaceControl.closeTransaction();
5688             }
5689         }
5690     }
5691 
5692     /** Updates draw state and shows drawn windows. */
commitFinishDrawing(SurfaceControl.Transaction t)5693     void commitFinishDrawing(SurfaceControl.Transaction t) {
5694         boolean committed = false;
5695         for (int i = mChildren.size() - 1; i >= 0; i--) {
5696             committed |= mChildren.get(i).commitFinishDrawing(t);
5697         }
5698         if (committed) {
5699             requestUpdateWallpaperIfNeeded();
5700         }
5701     }
5702 
5703     /**
5704      * Check if visibility of this {@link ActivityRecord} should be updated as part of an app
5705      * transition.
5706      *
5707      * <p class="note><strong>Note:</strong> If the visibility of this {@link ActivityRecord} is
5708      * already set to {@link #mVisible}, we don't need to update the visibility. So {@code false} is
5709      * returned.</p>
5710      *
5711      * @param visible {@code true} if this {@link ActivityRecord} should become visible,
5712      *                {@code false} if this should become invisible.
5713      * @return {@code true} if visibility of this {@link ActivityRecord} should be updated, and
5714      *         an app transition animation should be run.
5715      */
shouldApplyAnimation(boolean visible)5716     boolean shouldApplyAnimation(boolean visible) {
5717         // Allow for state update and animation to be applied if:
5718         // * activity is transitioning visibility state
5719         // * or the activity was marked as hidden and is exiting before we had a chance to play the
5720         // transition animation
5721         return isVisible() != visible || mRequestForceTransition || (!isVisible() && mIsExiting);
5722     }
5723 
5724     /**
5725      * See {@link Activity#setRecentsScreenshotEnabled}.
5726      */
setRecentsScreenshotEnabled(boolean enabled)5727     void setRecentsScreenshotEnabled(boolean enabled) {
5728         mEnableRecentsScreenshot = enabled;
5729     }
5730 
5731     /**
5732      * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
5733      * the case when preview screenshots are disabled {@link #setRecentsScreenshotEnabled} or when
5734      * we can't take a snapshot for other reasons, for example, if we have a secure window.
5735      *
5736      * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
5737      *         screenshot.
5738      */
shouldUseAppThemeSnapshot()5739     boolean shouldUseAppThemeSnapshot() {
5740         return !mEnableRecentsScreenshot || forAllWindows(WindowState::isSecureLocked,
5741                 true /* topToBottom */);
5742     }
5743 
5744     /**
5745      * Sets whether the current launch can turn the screen on.
5746      * @see #currentLaunchCanTurnScreenOn()
5747      */
setCurrentLaunchCanTurnScreenOn(boolean currentLaunchCanTurnScreenOn)5748     void setCurrentLaunchCanTurnScreenOn(boolean currentLaunchCanTurnScreenOn) {
5749         mCurrentLaunchCanTurnScreenOn = currentLaunchCanTurnScreenOn;
5750     }
5751 
5752     /**
5753      * Indicates whether the current launch can turn the screen on. This is to prevent multiple
5754      * relayouts from turning the screen back on. The screen should only turn on at most
5755      * once per activity resume.
5756      * <p>
5757      * Note this flag is only meaningful when {@link WindowManager.LayoutParams#FLAG_TURN_SCREEN_ON}
5758      * or {@link ActivityRecord#canTurnScreenOn} is set.
5759      *
5760      * @return {@code true} if the activity is ready to turn on the screen.
5761      */
currentLaunchCanTurnScreenOn()5762     boolean currentLaunchCanTurnScreenOn() {
5763         return mCurrentLaunchCanTurnScreenOn;
5764     }
5765 
setState(State state, String reason)5766     void setState(State state, String reason) {
5767         ProtoLog.v(WM_DEBUG_STATES, "State movement: %s from:%s to:%s reason:%s",
5768                 this, getState(), state, reason);
5769 
5770         if (state == mState) {
5771             // No need to do anything if state doesn't change.
5772             ProtoLog.v(WM_DEBUG_STATES, "State unchanged from:%s", state);
5773             return;
5774         }
5775 
5776         mState = state;
5777 
5778         if (getTaskFragment() != null) {
5779             getTaskFragment().onActivityStateChanged(this, state, reason);
5780         }
5781 
5782         // The WindowManager interprets the app stopping signal as
5783         // an indication that the Surface will eventually be destroyed.
5784         // This however isn't necessarily true if we are going to sleep.
5785         if (state == STOPPING && !isSleeping()) {
5786             if (getParent() == null) {
5787                 Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: "
5788                         + token);
5789                 return;
5790             }
5791         }
5792         updateVisibleForServiceConnection();
5793         if (app != null) {
5794             mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
5795         }
5796 
5797         switch (state) {
5798             case RESUMED:
5799                 mAtmService.updateBatteryStats(this, true);
5800                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED);
5801                 // Fall through.
5802             case STARTED:
5803                 // Update process info while making an activity from invisible to visible, to make
5804                 // sure the process state is updated to foreground.
5805                 if (app != null) {
5806                     app.updateProcessInfo(false /* updateServiceConnectionActivities */,
5807                             true /* activityChange */, true /* updateOomAdj */,
5808                             true /* addPendingTopUid */);
5809                 }
5810                 final ContentCaptureManagerInternal contentCaptureService =
5811                         LocalServices.getService(ContentCaptureManagerInternal.class);
5812                 if (contentCaptureService != null) {
5813                     contentCaptureService.notifyActivityEvent(mUserId, mActivityComponent,
5814                             ActivityEvent.TYPE_ACTIVITY_STARTED,
5815                             new ActivityId(getTask() != null ? getTask().mTaskId : INVALID_TASK_ID,
5816                                     shareableActivityToken));
5817                 }
5818                 break;
5819             case PAUSED:
5820                 mAtmService.updateBatteryStats(this, false);
5821                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
5822                 break;
5823             case STOPPED:
5824                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED);
5825                 break;
5826             case DESTROYED:
5827                 if (app != null && (mVisible || mVisibleRequested)) {
5828                     // The app may be died while visible (no PAUSED state).
5829                     mAtmService.updateBatteryStats(this, false);
5830                 }
5831                 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED);
5832                 // Fall through.
5833             case DESTROYING:
5834                 if (app != null && !app.hasActivities()) {
5835                     // Update any services we are bound to that might care about whether
5836                     // their client may have activities.
5837                     // No longer have activities, so update LRU list and oom adj.
5838                     app.updateProcessInfo(true /* updateServiceConnectionActivities */,
5839                             false /* activityChange */, true /* updateOomAdj */,
5840                             false /* addPendingTopUid */);
5841                 }
5842                 break;
5843         }
5844     }
5845 
getState()5846     State getState() {
5847         return mState;
5848     }
5849 
5850     /**
5851      * Returns {@code true} if the Activity is in the specified state.
5852      */
isState(State state)5853     boolean isState(State state) {
5854         return state == mState;
5855     }
5856 
5857     /**
5858      * Returns {@code true} if the Activity is in one of the specified states.
5859      */
isState(State state1, State state2)5860     boolean isState(State state1, State state2) {
5861         return state1 == mState || state2 == mState;
5862     }
5863 
5864     /**
5865      * Returns {@code true} if the Activity is in one of the specified states.
5866      */
isState(State state1, State state2, State state3)5867     boolean isState(State state1, State state2, State state3) {
5868         return state1 == mState || state2 == mState || state3 == mState;
5869     }
5870 
5871     /**
5872      * Returns {@code true} if the Activity is in one of the specified states.
5873      */
isState(State state1, State state2, State state3, State state4)5874     boolean isState(State state1, State state2, State state3, State state4) {
5875         return state1 == mState || state2 == mState || state3 == mState || state4 == mState;
5876     }
5877 
5878     /**
5879      * Returns {@code true} if the Activity is in one of the specified states.
5880      */
isState(State state1, State state2, State state3, State state4, State state5)5881     boolean isState(State state1, State state2, State state3, State state4, State state5) {
5882         return state1 == mState || state2 == mState || state3 == mState || state4 == mState
5883                 || state5 == mState;
5884     }
5885 
5886     /**
5887      * Returns {@code true} if the Activity is in one of the specified states.
5888      */
isState(State state1, State state2, State state3, State state4, State state5, State state6)5889     boolean isState(State state1, State state2, State state3, State state4, State state5,
5890             State state6) {
5891         return state1 == mState || state2 == mState || state3 == mState || state4 == mState
5892                 || state5 == mState || state6 == mState;
5893     }
5894 
destroySurfaces()5895     void destroySurfaces() {
5896         destroySurfaces(false /*cleanupOnResume*/);
5897     }
5898 
5899     /**
5900      * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure
5901      * the client has finished with them.
5902      *
5903      * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If
5904      * set to true, destroy only surfaces of removed windows, and clear relevant flags of the
5905      * others so that they are ready to be reused. If set to false (common case), destroy all
5906      * surfaces that's eligible, if the app is already stopped.
5907      */
destroySurfaces(boolean cleanupOnResume)5908     private void destroySurfaces(boolean cleanupOnResume) {
5909         boolean destroyedSomething = false;
5910 
5911         // Copying to a different list as multiple children can be removed.
5912         final ArrayList<WindowState> children = new ArrayList<>(mChildren);
5913         for (int i = children.size() - 1; i >= 0; i--) {
5914             final WindowState win = children.get(i);
5915             destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
5916         }
5917         if (destroyedSomething) {
5918             final DisplayContent dc = getDisplayContent();
5919             dc.assignWindowLayers(true /*setLayoutNeeded*/);
5920             updateLetterboxSurface(null);
5921         }
5922     }
5923 
notifyAppResumed()5924     void notifyAppResumed() {
5925         if (getParent() == null) {
5926             Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token);
5927             return;
5928         }
5929         final boolean wasStopped = mAppStopped;
5930         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppResumed: wasStopped=%b %s",
5931                 wasStopped, this);
5932         mAppStopped = false;
5933         // Allow the window to turn the screen on once the app is started and resumed.
5934         if (mAtmService.getActivityStartController().isInExecution()) {
5935             setCurrentLaunchCanTurnScreenOn(true);
5936         }
5937 
5938         if (!wasStopped) {
5939             destroySurfaces(true /*cleanupOnResume*/);
5940         }
5941     }
5942 
5943     /**
5944      * Suppress transition until the new activity becomes ready, otherwise the keyguard can appear
5945      * for a short amount of time before the new process with the new activity had the ability to
5946      * set its showWhenLocked flags.
5947      */
notifyUnknownVisibilityLaunchedForKeyguardTransition()5948     void notifyUnknownVisibilityLaunchedForKeyguardTransition() {
5949         // No display activities never add a window, so there is no point in waiting them for
5950         // relayout.
5951         if (noDisplay || !isKeyguardLocked()) {
5952             return;
5953         }
5954 
5955         mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(this);
5956     }
5957 
5958     /** @return {@code true} if this activity should be made visible. */
shouldBeVisible(boolean behindOccludedContainer, boolean ignoringKeyguard)5959     private boolean shouldBeVisible(boolean behindOccludedContainer, boolean ignoringKeyguard) {
5960         updateVisibilityIgnoringKeyguard(behindOccludedContainer);
5961 
5962         if (ignoringKeyguard) {
5963             return visibleIgnoringKeyguard;
5964         }
5965 
5966         return shouldBeVisibleUnchecked();
5967     }
5968 
shouldBeVisibleUnchecked()5969     boolean shouldBeVisibleUnchecked() {
5970         final Task rootTask = getRootTask();
5971         if (rootTask == null || !visibleIgnoringKeyguard) {
5972             return false;
5973         }
5974 
5975         // Activity in a root pinned task should not be visible if the root task is in force
5976         // hidden state.
5977         // Typically due to the FLAG_FORCE_HIDDEN_FOR_PINNED_TASK set on the root task, which is a
5978         // work around to send onStop before windowing mode change callbacks.
5979         // See also ActivityTaskSupervisor#removePinnedRootTaskInSurfaceTransaction
5980         // TODO: Should we ever be visible if the rootTask/task is invisible?
5981         if (inPinnedWindowingMode() && rootTask.isForceHidden()) {
5982             return false;
5983         }
5984 
5985         // Untrusted embedded activity can be visible only if there is no other overlay window.
5986         if (hasOverlayOverUntrustedModeEmbedded()) {
5987             return false;
5988         }
5989 
5990         // Check if the activity is on a sleeping display, canTurnScreenOn will also check
5991         // keyguard visibility
5992         if (mDisplayContent.isSleeping()) {
5993             return canTurnScreenOn();
5994         } else {
5995             return mTaskSupervisor.getKeyguardController().checkKeyguardVisibility(this);
5996         }
5997     }
5998 
5999     /**
6000      * Checks if there are any activities or other containers that belong to the same task on top of
6001      * this activity when embedded in untrusted mode.
6002      */
hasOverlayOverUntrustedModeEmbedded()6003     boolean hasOverlayOverUntrustedModeEmbedded() {
6004         if (!isEmbeddedInUntrustedMode() || getTask() == null) {
6005             // The activity is not embedded in untrusted mode.
6006             return false;
6007         }
6008 
6009         // Check if there are any activities with different UID over the activity that is embedded
6010         // in untrusted mode. Traverse bottom to top with boundary so that it will only check
6011         // activities above this activity.
6012         final ActivityRecord differentUidOverlayActivity = getTask().getActivity(
6013                 a -> !a.finishing && a.getUid() != getUid(), this /* boundary */,
6014                 false /* includeBoundary */, false /* traverseTopToBottom */);
6015         return differentUidOverlayActivity != null;
6016     }
6017 
updateVisibilityIgnoringKeyguard(boolean behindOccludedContainer)6018     void updateVisibilityIgnoringKeyguard(boolean behindOccludedContainer) {
6019         visibleIgnoringKeyguard = (!behindOccludedContainer || mLaunchTaskBehind)
6020                 && showToCurrentUser();
6021     }
6022 
shouldBeVisible()6023     boolean shouldBeVisible() {
6024         final Task task = getTask();
6025         if (task == null) {
6026             return false;
6027         }
6028 
6029         final boolean behindOccludedContainer = !task.shouldBeVisible(null /* starting */)
6030                 || task.getOccludingActivityAbove(this) != null;
6031         return shouldBeVisible(behindOccludedContainer, false /* ignoringKeyguard */);
6032     }
6033 
makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient)6034     void makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient) {
6035         // This activity is not currently visible, but is running. Tell it to become visible.
6036         if ((mState == RESUMED && mVisibleRequested) || this == starting) {
6037             if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
6038                     "Not making visible, r=" + this + " state=" + mState + " starting=" + starting);
6039             return;
6040         }
6041 
6042         // If this activity is paused, tell it to now show its window.
6043         if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
6044                 "Making visible and scheduling visibility: " + this);
6045         final Task rootTask = getRootTask();
6046         try {
6047             if (rootTask.mTranslucentActivityWaiting != null) {
6048                 updateOptionsLocked(returningOptions);
6049                 rootTask.mUndrawnActivitiesBelowTopTranslucent.add(this);
6050             }
6051             setVisibility(true);
6052             app.postPendingUiCleanMsg(true);
6053             if (reportToClient) {
6054                 mClientVisibilityDeferred = false;
6055                 makeActiveIfNeeded(starting);
6056             } else {
6057                 mClientVisibilityDeferred = true;
6058             }
6059             // The activity may be waiting for stop, but that is no longer appropriate for it.
6060             mTaskSupervisor.mStoppingActivities.remove(this);
6061         } catch (Exception e) {
6062             // Just skip on any failure; we'll make it visible when it next restarts.
6063             Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e);
6064         }
6065         handleAlreadyVisible();
6066     }
6067 
makeInvisible()6068     void makeInvisible() {
6069         if (!mVisibleRequested) {
6070             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);
6071             return;
6072         }
6073         // Now for any activities that aren't visible to the user, make sure they no longer are
6074         // keeping the screen frozen.
6075         if (DEBUG_VISIBILITY) {
6076             Slog.v(TAG_VISIBILITY, "Making invisible: " + this + ", state=" + getState());
6077         }
6078         try {
6079             final boolean canEnterPictureInPicture = checkEnterPictureInPictureState(
6080                     "makeInvisible", true /* beforeStopping */);
6081             // Defer telling the client it is hidden if it can enter Pip and isn't current paused,
6082             // stopped or stopping. This gives it a chance to enter Pip in onPause().
6083             final boolean deferHidingClient = canEnterPictureInPicture
6084                     && !isState(STARTED, STOPPING, STOPPED, PAUSED);
6085             setDeferHidingClient(deferHidingClient);
6086             setVisibility(false);
6087 
6088             switch (getState()) {
6089                 case STOPPING:
6090                 case STOPPED:
6091                     // Reset the flag indicating that an app can enter picture-in-picture once the
6092                     // activity is hidden
6093                     supportsEnterPipOnTaskSwitch = false;
6094                     break;
6095                 case RESUMED:
6096                 case INITIALIZING:
6097                 case PAUSING:
6098                 case PAUSED:
6099                 case STARTED:
6100                     addToStopping(true /* scheduleIdle */,
6101                             canEnterPictureInPicture /* idleDelayed */, "makeInvisible");
6102                     break;
6103 
6104                 default:
6105                     break;
6106             }
6107         } catch (Exception e) {
6108             // Just skip on any failure; we'll make it visible when it next restarts.
6109             Slog.w(TAG, "Exception thrown making hidden: " + intent.getComponent(), e);
6110         }
6111     }
6112 
6113     /**
6114      * Make activity resumed or paused if needed.
6115      * @param activeActivity an activity that is resumed or just completed pause action.
6116      *                       We won't change the state of this activity.
6117      */
makeActiveIfNeeded(ActivityRecord activeActivity)6118     boolean makeActiveIfNeeded(ActivityRecord activeActivity) {
6119         if (shouldResumeActivity(activeActivity)) {
6120             if (DEBUG_VISIBILITY) {
6121                 Slog.v(TAG_VISIBILITY, "Resume visible activity, " + this);
6122             }
6123             return getRootTask().resumeTopActivityUncheckedLocked(activeActivity /* prev */,
6124                     null /* options */);
6125         } else if (shouldPauseActivity(activeActivity)) {
6126             if (DEBUG_VISIBILITY) {
6127                 Slog.v(TAG_VISIBILITY, "Pause visible activity, " + this);
6128             }
6129             // An activity must be in the {@link PAUSING} state for the system to validate
6130             // the move to {@link PAUSED}.
6131             setState(PAUSING, "makeActiveIfNeeded");
6132             EventLogTags.writeWmPauseActivity(mUserId, System.identityHashCode(this),
6133                     shortComponentName, "userLeaving=false", "make-active");
6134             try {
6135                 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
6136                         PauseActivityItem.obtain(finishing, false /* userLeaving */,
6137                                 configChangeFlags, false /* dontReport */, mAutoEnteringPip));
6138             } catch (Exception e) {
6139                 Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
6140             }
6141         } else if (shouldStartActivity()) {
6142             if (DEBUG_VISIBILITY) {
6143                 Slog.v(TAG_VISIBILITY, "Start visible activity, " + this);
6144             }
6145             setState(STARTED, "makeActiveIfNeeded");
6146 
6147             try {
6148                 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
6149                         StartActivityItem.obtain(takeOptions()));
6150             } catch (Exception e) {
6151                 Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e);
6152             }
6153             // The activity may be waiting for stop, but that is no longer appropriate if we are
6154             // starting the activity again
6155             mTaskSupervisor.mStoppingActivities.remove(this);
6156         }
6157         return false;
6158     }
6159 
6160     /**
6161      * Check if activity should be moved to PAUSED state. The activity:
6162      * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
6163      * - should be non-focusable
6164      * - should not be currently pausing or paused
6165      * @param activeActivity the activity that is active or just completed pause action. We won't
6166      *                       resume if this activity is active.
6167      */
6168     @VisibleForTesting
shouldPauseActivity(ActivityRecord activeActivity)6169     boolean shouldPauseActivity(ActivityRecord activeActivity) {
6170         return shouldMakeActive(activeActivity) && !isFocusable() && !isState(PAUSING, PAUSED)
6171                 // We will only allow pausing if results is null, otherwise it will cause this
6172                 // activity to resume before getting result
6173                 && (results == null);
6174     }
6175 
6176     /**
6177      * Check if activity should be moved to RESUMED state.
6178      * See {@link #shouldBeResumed(ActivityRecord)}
6179      * @param activeActivity the activity that is active or just completed pause action. We won't
6180      *                       resume if this activity is active.
6181      */
6182     @VisibleForTesting
shouldResumeActivity(ActivityRecord activeActivity)6183     boolean shouldResumeActivity(ActivityRecord activeActivity) {
6184         return shouldBeResumed(activeActivity) && !isState(RESUMED);
6185     }
6186 
6187     /**
6188      * Check if activity should be RESUMED now. The activity:
6189      * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
6190      * - should be focusable
6191      */
shouldBeResumed(ActivityRecord activeActivity)6192     private boolean shouldBeResumed(ActivityRecord activeActivity) {
6193         return shouldMakeActive(activeActivity) && isFocusable()
6194                 && getTaskFragment().getVisibility(activeActivity)
6195                         == TASK_FRAGMENT_VISIBILITY_VISIBLE
6196                 && canResumeByCompat();
6197     }
6198 
6199     /**
6200      * Check if activity should be moved to STARTED state.
6201      * NOTE: This will not check if activity should be made paused or resumed first, so it must only
6202      * be called after checking with {@link #shouldResumeActivity(ActivityRecord)}
6203      * and {@link #shouldPauseActivity(ActivityRecord)}.
6204      */
shouldStartActivity()6205     private boolean shouldStartActivity() {
6206         return mVisibleRequested && (isState(STOPPED) || isState(STOPPING));
6207     }
6208 
6209     /**
6210      * Check if activity is eligible to be made active (resumed of paused). The activity:
6211      * - should be paused, stopped or stopping
6212      * - should not be the currently active one or launching behind other tasks
6213      * - should be either the topmost in task, or right below the top activity that is finishing
6214      * If all of these conditions are not met at the same time, the activity cannot be made active.
6215      */
6216     @VisibleForTesting
shouldMakeActive(ActivityRecord activeActivity)6217     boolean shouldMakeActive(ActivityRecord activeActivity) {
6218         // If the activity is stopped, stopping, cycle to an active state. We avoid doing
6219         // this when there is an activity waiting to become translucent as the extra binder
6220         // calls will lead to noticeable jank. A later call to
6221         // Task#ensureActivitiesVisible will bring the activity to a proper
6222         // active state.
6223         if (!isState(STARTED, RESUMED, PAUSED, STOPPED, STOPPING)
6224                 // TODO (b/185876784) Check could we remove the check condition
6225                 //  mTranslucentActivityWaiting != null here
6226                 || getRootTask().mTranslucentActivityWaiting != null) {
6227             return false;
6228         }
6229 
6230         if (this == activeActivity) {
6231             return false;
6232         }
6233 
6234         if (!mTaskSupervisor.readyToResume()) {
6235             // Making active is currently deferred (e.g. because an activity launch is in progress).
6236             return false;
6237         }
6238 
6239         if (this.mLaunchTaskBehind) {
6240             // This activity is being launched from behind, which means that it's not intended to be
6241             // presented to user right now, even if it's set to be visible.
6242             return false;
6243         }
6244 
6245         // Check if position in task allows to become paused
6246         if (!task.hasChild(this)) {
6247             throw new IllegalStateException("Activity not found in its task");
6248         }
6249         return getTaskFragment().topRunningActivity() == this;
6250     }
6251 
handleAlreadyVisible()6252     void handleAlreadyVisible() {
6253         stopFreezingScreenLocked(false);
6254         try {
6255             if (returningOptions != null) {
6256                 app.getThread().scheduleOnNewActivityOptions(token, returningOptions.toBundle());
6257             }
6258         } catch(RemoteException e) {
6259         }
6260     }
6261 
activityResumedLocked(IBinder token, boolean handleSplashScreenExit)6262     static void activityResumedLocked(IBinder token, boolean handleSplashScreenExit) {
6263         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
6264         ProtoLog.i(WM_DEBUG_STATES, "Resumed activity; dropping state of: %s", r);
6265         if (r == null) {
6266             // If an app reports resumed after a long delay, the record on server side might have
6267             // been removed (e.g. destroy timeout), so the token could be null.
6268             return;
6269         }
6270         r.setCustomizeSplashScreenExitAnimation(handleSplashScreenExit);
6271         r.setSavedState(null /* savedState */);
6272 
6273         r.mDisplayContent.handleActivitySizeCompatModeIfNeeded(r);
6274         r.mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(r);
6275     }
6276 
activityRefreshedLocked(IBinder token)6277     static void activityRefreshedLocked(IBinder token) {
6278         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
6279         ProtoLog.i(WM_DEBUG_STATES, "Refreshed activity: %s", r);
6280         if (r == null) {
6281             // In case the record on server side has been removed (e.g. destroy timeout)
6282             // and the token could be null.
6283             return;
6284         }
6285         if (r.mDisplayContent.mDisplayRotationCompatPolicy != null) {
6286             r.mDisplayContent.mDisplayRotationCompatPolicy.onActivityRefreshed(r);
6287         }
6288     }
6289 
splashScreenAttachedLocked(IBinder token)6290     static void splashScreenAttachedLocked(IBinder token) {
6291         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
6292         if (r == null) {
6293             Slog.w(TAG, "splashScreenTransferredLocked cannot find activity");
6294             return;
6295         }
6296         r.onSplashScreenAttachComplete();
6297     }
6298 
6299     /**
6300      * Once we know that we have asked an application to put an activity in the resumed state
6301      * (either by launching it or explicitly telling it), this function updates the rest of our
6302      * state to match that fact.
6303      */
completeResumeLocked()6304     void completeResumeLocked() {
6305         final boolean wasVisible = mVisibleRequested;
6306         setVisibility(true);
6307         if (!wasVisible) {
6308             // Visibility has changed, so take a note of it so we call the TaskStackChangedListener
6309             mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
6310         }
6311         idle = false;
6312         results = null;
6313         if (newIntents != null && newIntents.size() > 0) {
6314             mLastNewIntent = newIntents.get(newIntents.size() - 1);
6315         }
6316         newIntents = null;
6317 
6318         if (isActivityTypeHome()) {
6319             mTaskSupervisor.updateHomeProcess(task.getBottomMostActivity().app);
6320         }
6321 
6322         if (nowVisible) {
6323             mTaskSupervisor.stopWaitingForActivityVisible(this);
6324         }
6325 
6326         // Schedule an idle timeout in case the app doesn't do it for us.
6327         mTaskSupervisor.scheduleIdleTimeout(this);
6328 
6329         mTaskSupervisor.reportResumedActivityLocked(this);
6330 
6331         resumeKeyDispatchingLocked();
6332         final Task rootTask = getRootTask();
6333         mTaskSupervisor.mNoAnimActivities.clear();
6334         returningOptions = null;
6335 
6336         if (canTurnScreenOn()) {
6337             mTaskSupervisor.wakeUp("turnScreenOnFlag");
6338         } else {
6339             // If the screen is going to turn on because the caller explicitly requested it and
6340             // the keyguard is not showing don't attempt to sleep. Otherwise the Activity will
6341             // pause and then resume again later, which will result in a double life-cycle event.
6342             rootTask.checkReadyForSleep();
6343         }
6344     }
6345 
activityPaused(boolean timeout)6346     void activityPaused(boolean timeout) {
6347         ProtoLog.v(WM_DEBUG_STATES, "Activity paused: token=%s, timeout=%b", token,
6348                 timeout);
6349 
6350         final TaskFragment taskFragment = getTaskFragment();
6351         if (taskFragment != null) {
6352             removePauseTimeout();
6353 
6354             final ActivityRecord pausingActivity = taskFragment.getPausingActivity();
6355             if (pausingActivity == this) {
6356                 ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s %s", this,
6357                         (timeout ? "(due to timeout)" : " (pause complete)"));
6358                 mAtmService.deferWindowLayout();
6359                 try {
6360                     taskFragment.completePause(true /* resumeNext */, null /* resumingActivity */);
6361                 } finally {
6362                     mAtmService.continueWindowLayout();
6363                 }
6364                 return;
6365             } else {
6366                 EventLogTags.writeWmFailedToPause(mUserId, System.identityHashCode(this),
6367                         shortComponentName, pausingActivity != null
6368                                 ? pausingActivity.shortComponentName : "(none)");
6369                 if (isState(PAUSING)) {
6370                     setState(PAUSED, "activityPausedLocked");
6371                     if (finishing) {
6372                         ProtoLog.v(WM_DEBUG_STATES,
6373                                 "Executing finish of failed to pause activity: %s", this);
6374                         completeFinishing("activityPausedLocked");
6375                     }
6376                 }
6377             }
6378         }
6379 
6380         mDisplayContent.handleActivitySizeCompatModeIfNeeded(this);
6381         mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
6382     }
6383 
6384     /**
6385      * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
6386      * this directly impacts the responsiveness seen by the user.
6387      */
schedulePauseTimeout()6388     void schedulePauseTimeout() {
6389         pauseTime = SystemClock.uptimeMillis();
6390         mAtmService.mH.postDelayed(mPauseTimeoutRunnable, PAUSE_TIMEOUT);
6391         ProtoLog.v(WM_DEBUG_STATES, "Waiting for pause to complete...");
6392     }
6393 
removePauseTimeout()6394     private void removePauseTimeout() {
6395         mAtmService.mH.removeCallbacks(mPauseTimeoutRunnable);
6396     }
6397 
removeDestroyTimeout()6398     private void removeDestroyTimeout() {
6399         mAtmService.mH.removeCallbacks(mDestroyTimeoutRunnable);
6400     }
6401 
removeStopTimeout()6402     private void removeStopTimeout() {
6403         mAtmService.mH.removeCallbacks(mStopTimeoutRunnable);
6404     }
6405 
removeTimeouts()6406     void removeTimeouts() {
6407         mTaskSupervisor.removeIdleTimeoutForActivity(this);
6408         removePauseTimeout();
6409         removeStopTimeout();
6410         removeDestroyTimeout();
6411         finishLaunchTickingLocked();
6412     }
6413 
stopIfPossible()6414     void stopIfPossible() {
6415         if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this);
6416         final Task rootTask = getRootTask();
6417         if (isNoHistory()) {
6418             if (!finishing) {
6419                 if (!rootTask.shouldSleepActivities()) {
6420                     ProtoLog.d(WM_DEBUG_STATES, "no-history finish of %s", this);
6421                     if (finishIfPossible("stop-no-history", false /* oomAdj */)
6422                             != FINISH_RESULT_CANCELLED) {
6423                         resumeKeyDispatchingLocked();
6424                         return;
6425                     }
6426                 } else {
6427                     ProtoLog.d(WM_DEBUG_STATES, "Not finishing noHistory %s on stop "
6428                             + "because we're just sleeping", this);
6429                 }
6430             }
6431         }
6432 
6433         if (!attachedToProcess()) {
6434             return;
6435         }
6436         resumeKeyDispatchingLocked();
6437         try {
6438             ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPING: %s (stop requested)", this);
6439 
6440             setState(STOPPING, "stopIfPossible");
6441             if (DEBUG_VISIBILITY) {
6442                 Slog.v(TAG_VISIBILITY, "Stopping:" + this);
6443             }
6444             EventLogTags.writeWmStopActivity(
6445                     mUserId, System.identityHashCode(this), shortComponentName);
6446             mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
6447                     StopActivityItem.obtain(configChangeFlags));
6448 
6449             mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);
6450         } catch (Exception e) {
6451             // Maybe just ignore exceptions here...  if the process has crashed, our death
6452             // notification will clean things up.
6453             Slog.w(TAG, "Exception thrown during pause", e);
6454             // Just in case, assume it to be stopped.
6455             mAppStopped = true;
6456             ProtoLog.v(WM_DEBUG_STATES, "Stop failed; moving to STOPPED: %s", this);
6457             setState(STOPPED, "stopIfPossible");
6458             if (deferRelaunchUntilPaused) {
6459                 destroyImmediately("stop-except");
6460             }
6461         }
6462     }
6463 
6464     /**
6465      * Notifies that the activity has stopped, and it is okay to destroy any surfaces which were
6466      * keeping alive in case they were still being used.
6467      */
activityStopped(Bundle newIcicle, PersistableBundle newPersistentState, CharSequence description)6468     void activityStopped(Bundle newIcicle, PersistableBundle newPersistentState,
6469             CharSequence description) {
6470         removeStopTimeout();
6471         final boolean isStopping = mState == STOPPING;
6472         if (!isStopping && mState != RESTARTING_PROCESS) {
6473             Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this + " " + mState);
6474             return;
6475         }
6476         if (newPersistentState != null) {
6477             mPersistentState = newPersistentState;
6478             mAtmService.notifyTaskPersisterLocked(task, false);
6479         }
6480 
6481         if (newIcicle != null) {
6482             // If icicle is null, this is happening due to a timeout, so we haven't really saved
6483             // the state.
6484             setSavedState(newIcicle);
6485             launchCount = 0;
6486             updateTaskDescription(description);
6487         }
6488         ProtoLog.i(WM_DEBUG_STATES, "Saving icicle of %s: %s", this, mIcicle);
6489 
6490         if (isStopping) {
6491             ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPED: %s (stop complete)", this);
6492             setState(STOPPED, "activityStopped");
6493         }
6494 
6495         mAppStopped = true;
6496         firstWindowDrawn = false;
6497         // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls
6498         // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787.
6499         // Clear any surface transactions and content overlay in this case.
6500         if (task.mLastRecentsAnimationTransaction != null) {
6501             task.clearLastRecentsAnimationTransaction(true /* forceRemoveOverlay */);
6502         }
6503         // Reset the last saved PiP snap fraction on app stop.
6504         mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
6505         mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
6506         if (isClientVisible()) {
6507             // Though this is usually unlikely to happen, still make sure the client is invisible.
6508             setClientVisible(false);
6509         }
6510         destroySurfaces();
6511         // Remove any starting window that was added for this app if they are still around.
6512         removeStartingWindow();
6513 
6514         if (finishing) {
6515             abortAndClearOptionsAnimation();
6516         } else {
6517             if (deferRelaunchUntilPaused) {
6518                 destroyImmediately("stop-config");
6519                 mRootWindowContainer.resumeFocusedTasksTopActivities();
6520             } else {
6521                 mAtmService.updatePreviousProcess(this);
6522             }
6523         }
6524         mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
6525     }
6526 
addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason)6527     void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) {
6528         if (!mTaskSupervisor.mStoppingActivities.contains(this)) {
6529             EventLogTags.writeWmAddToStopping(mUserId, System.identityHashCode(this),
6530                     shortComponentName, reason);
6531             mTaskSupervisor.mStoppingActivities.add(this);
6532         }
6533 
6534         final Task rootTask = getRootTask();
6535         // If we already have a few activities waiting to stop, then give up on things going idle
6536         // and start clearing them out. Or if r is the last of activity of the last task the root
6537         // task will be empty and must be cleared immediately.
6538         boolean forceIdle = mTaskSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
6539                 || (isRootOfTask() && rootTask.getChildCount() <= 1);
6540         if (scheduleIdle || forceIdle) {
6541             ProtoLog.v(WM_DEBUG_STATES,
6542                     "Scheduling idle now: forceIdle=%b immediate=%b", forceIdle, !idleDelayed);
6543 
6544             if (!idleDelayed) {
6545                 mTaskSupervisor.scheduleIdle();
6546             } else {
6547                 mTaskSupervisor.scheduleIdleTimeout(this);
6548             }
6549         } else {
6550             rootTask.checkReadyForSleep();
6551         }
6552     }
6553 
startLaunchTickingLocked()6554     void startLaunchTickingLocked() {
6555         if (Build.IS_USER) {
6556             return;
6557         }
6558         if (launchTickTime == 0) {
6559             launchTickTime = SystemClock.uptimeMillis();
6560             continueLaunchTicking();
6561         }
6562     }
6563 
continueLaunchTicking()6564     private boolean continueLaunchTicking() {
6565         if (launchTickTime == 0) {
6566             return false;
6567         }
6568 
6569         final Task rootTask = getRootTask();
6570         if (rootTask == null) {
6571             return false;
6572         }
6573 
6574         rootTask.removeLaunchTickMessages();
6575         mAtmService.mH.postDelayed(mLaunchTickRunnable, LAUNCH_TICK);
6576         return true;
6577     }
6578 
removeLaunchTickRunnable()6579     void removeLaunchTickRunnable() {
6580         mAtmService.mH.removeCallbacks(mLaunchTickRunnable);
6581     }
6582 
finishLaunchTickingLocked()6583     void finishLaunchTickingLocked() {
6584         launchTickTime = 0;
6585         final Task rootTask = getRootTask();
6586         if (rootTask == null) {
6587             return;
6588         }
6589         rootTask.removeLaunchTickMessages();
6590     }
6591 
mayFreezeScreenLocked()6592     boolean mayFreezeScreenLocked() {
6593         return mayFreezeScreenLocked(app);
6594     }
6595 
mayFreezeScreenLocked(WindowProcessController app)6596     private boolean mayFreezeScreenLocked(WindowProcessController app) {
6597         // Only freeze the screen if this activity is currently attached to
6598         // an application, and that application is not blocked or unresponding.
6599         // In any other case, we can't count on getting the screen unfrozen,
6600         // so it is best to leave as-is.
6601         return hasProcess() && !app.isCrashing() && !app.isNotResponding();
6602     }
6603 
startFreezingScreenLocked(int configChanges)6604     void startFreezingScreenLocked(int configChanges) {
6605         startFreezingScreenLocked(app, configChanges);
6606     }
6607 
startFreezingScreenLocked(WindowProcessController app, int configChanges)6608     void startFreezingScreenLocked(WindowProcessController app, int configChanges) {
6609         if (mayFreezeScreenLocked(app)) {
6610             if (getParent() == null) {
6611                 Slog.w(TAG_WM,
6612                         "Attempted to freeze screen with non-existing app token: " + token);
6613                 return;
6614             }
6615 
6616             // Window configuration changes only effect windows, so don't require a screen freeze.
6617             int freezableConfigChanges = configChanges & ~(CONFIG_WINDOW_CONFIGURATION);
6618             if (freezableConfigChanges == 0 && okToDisplay()) {
6619                 ProtoLog.v(WM_DEBUG_ORIENTATION, "Skipping set freeze of %s", token);
6620                 return;
6621             }
6622 
6623             startFreezingScreen();
6624         }
6625     }
6626 
startFreezingScreen()6627     void startFreezingScreen() {
6628         startFreezingScreen(ROTATION_UNDEFINED /* overrideOriginalDisplayRotation */);
6629     }
6630 
startFreezingScreen(int overrideOriginalDisplayRotation)6631     void startFreezingScreen(int overrideOriginalDisplayRotation) {
6632         if (mTransitionController.isShellTransitionsEnabled()) {
6633             return;
6634         }
6635         ProtoLog.i(WM_DEBUG_ORIENTATION,
6636                 "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
6637                 token, isVisible(), mFreezingScreen, mVisibleRequested,
6638                 new RuntimeException().fillInStackTrace());
6639         if (!mVisibleRequested) {
6640             return;
6641         }
6642 
6643         // If the override is given, the rotation of display doesn't change but we still want to
6644         // cover the activity whose configuration is changing by freezing the display and running
6645         // the rotation animation.
6646         final boolean forceRotation = overrideOriginalDisplayRotation != ROTATION_UNDEFINED;
6647         if (!mFreezingScreen) {
6648             mFreezingScreen = true;
6649             mWmService.registerAppFreezeListener(this);
6650             mWmService.mAppsFreezingScreen++;
6651             if (mWmService.mAppsFreezingScreen == 1) {
6652                 if (forceRotation) {
6653                     // Make sure normal rotation animation will be applied.
6654                     mDisplayContent.getDisplayRotation().cancelSeamlessRotation();
6655                 }
6656                 mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */,
6657                         mDisplayContent, overrideOriginalDisplayRotation);
6658                 mWmService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
6659                 mWmService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
6660             }
6661         }
6662         if (forceRotation) {
6663             // The rotation of the real display won't change, so in order to unfreeze the screen
6664             // via {@link #checkAppWindowsReadyToShow}, the windows have to be able to call
6665             // {@link WindowState#reportResized} (it is skipped if the window is freezing) to update
6666             // the drawn state.
6667             return;
6668         }
6669         final int count = mChildren.size();
6670         for (int i = 0; i < count; i++) {
6671             final WindowState w = mChildren.get(i);
6672             w.onStartFreezingScreen();
6673         }
6674     }
6675 
isFreezingScreen()6676     boolean isFreezingScreen() {
6677         return mFreezingScreen;
6678     }
6679 
6680     @Override
onAppFreezeTimeout()6681     public void onAppFreezeTimeout() {
6682         Slog.w(TAG_WM, "Force clearing freeze: " + this);
6683         stopFreezingScreen(true, true);
6684     }
6685 
stopFreezingScreenLocked(boolean force)6686     void stopFreezingScreenLocked(boolean force) {
6687         if (force || frozenBeforeDestroy) {
6688             frozenBeforeDestroy = false;
6689             if (getParent() == null) {
6690                 return;
6691             }
6692             ProtoLog.v(WM_DEBUG_ORIENTATION,
6693                         "Clear freezing of %s: visible=%b freezing=%b", token,
6694                                 isVisible(), isFreezingScreen());
6695             stopFreezingScreen(true, force);
6696         }
6697     }
6698 
stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force)6699     void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) {
6700         if (!mFreezingScreen) {
6701             return;
6702         }
6703         ProtoLog.v(WM_DEBUG_ORIENTATION,
6704                 "Clear freezing of %s force=%b", this, force);
6705         final int count = mChildren.size();
6706         boolean unfrozeWindows = false;
6707         for (int i = 0; i < count; i++) {
6708             final WindowState w = mChildren.get(i);
6709             unfrozeWindows |= w.onStopFreezingScreen();
6710         }
6711         if (force || unfrozeWindows) {
6712             ProtoLog.v(WM_DEBUG_ORIENTATION, "No longer freezing: %s", this);
6713             mFreezingScreen = false;
6714             mWmService.unregisterAppFreezeListener(this);
6715             mWmService.mAppsFreezingScreen--;
6716             mWmService.mLastFinishedFreezeSource = this;
6717         }
6718         if (unfreezeSurfaceNow) {
6719             if (unfrozeWindows) {
6720                 mWmService.mWindowPlacerLocked.performSurfacePlacement();
6721             }
6722             mWmService.stopFreezingDisplayLocked();
6723         }
6724     }
6725 
onFirstWindowDrawn(WindowState win)6726     void onFirstWindowDrawn(WindowState win) {
6727         firstWindowDrawn = true;
6728         // stop tracking
6729         mSplashScreenStyleSolidColor = true;
6730 
6731         if (mStartingWindow != null) {
6732             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s"
6733                     + ": first real window is shown, no animation", win.mToken);
6734             // If this initial window is animating, stop it -- we will do an animation to reveal
6735             // it from behind the starting window, so there is no need for it to also be doing its
6736             // own stuff.
6737             win.cancelAnimation();
6738         }
6739 
6740         // Remove starting window directly if is in a pure task. Otherwise if it is associated with
6741         // a task (e.g. nested task fragment), then remove only if all visible windows in the task
6742         // are drawn.
6743         final Task associatedTask = task.mSharedStartingData != null ? task : null;
6744         if (associatedTask == null) {
6745             removeStartingWindow();
6746         } else if (associatedTask.getActivity(
6747                 r -> r.isVisibleRequested() && !r.firstWindowDrawn) == null) {
6748             // The last drawn activity may not be the one that owns the starting window.
6749             final ActivityRecord r = associatedTask.topActivityContainsStartingWindow();
6750             if (r != null) {
6751                 r.removeStartingWindow();
6752             }
6753         }
6754         updateReportedVisibilityLocked();
6755     }
6756 
6757     /**
6758      * Sets whether something has been visible in the task and returns {@code true} if the state
6759      * is changed from invisible to visible.
6760      */
setTaskHasBeenVisible()6761     private boolean setTaskHasBeenVisible() {
6762         final boolean wasTaskVisible = task.getHasBeenVisible();
6763         if (wasTaskVisible) {
6764             return false;
6765         }
6766         if (inTransition()) {
6767             // The deferring will be canceled until transition is ready so it won't dispatch
6768             // intermediate states to organizer.
6769             task.setDeferTaskAppear(true);
6770         }
6771         task.setHasBeenVisible(true);
6772         return true;
6773     }
6774 
onStartingWindowDrawn()6775     void onStartingWindowDrawn() {
6776         boolean wasTaskVisible = false;
6777         if (task != null) {
6778             mSplashScreenStyleSolidColor = true;
6779             wasTaskVisible = !setTaskHasBeenVisible();
6780         }
6781 
6782         // The transition may not be executed if the starting process hasn't attached. But if the
6783         // starting window is drawn, the transition can start earlier. Exclude finishing and bubble
6784         // because it may be a trampoline.
6785         if (!wasTaskVisible && mStartingData != null && !finishing && !mLaunchedFromBubble
6786                 && mVisibleRequested && !mDisplayContent.mAppTransition.isReady()
6787                 && !mDisplayContent.mAppTransition.isRunning()
6788                 && mDisplayContent.isNextTransitionForward()) {
6789             // The pending transition state will be cleared after the transition is started, so
6790             // save the state for launching the client later (used by LaunchActivityItem).
6791             mStartingData.mIsTransitionForward = true;
6792             // Ensure that the transition can run with the latest orientation.
6793             if (this != mDisplayContent.getLastOrientationSource()) {
6794                 mDisplayContent.updateOrientation();
6795             }
6796             mDisplayContent.executeAppTransition();
6797         }
6798     }
6799 
6800     /** Called when the windows associated app window container are drawn. */
onWindowsDrawn()6801     private void onWindowsDrawn() {
6802         final TransitionInfoSnapshot info = mTaskSupervisor
6803                 .getActivityMetricsLogger().notifyWindowsDrawn(this);
6804         final boolean validInfo = info != null;
6805         final int windowsDrawnDelayMs = validInfo ? info.windowsDrawnDelayMs : INVALID_DELAY;
6806         final @WaitResult.LaunchState int launchState =
6807                 validInfo ? info.getLaunchState() : WaitResult.LAUNCH_STATE_UNKNOWN;
6808         // The activity may have been requested to be invisible (another activity has been launched)
6809         // so there is no valid info. But if it is the current top activity (e.g. sleeping), the
6810         // invalid state is still reported to make sure the waiting result is notified.
6811         if (validInfo || this == getDisplayArea().topRunningActivity()) {
6812             mTaskSupervisor.reportActivityLaunched(false /* timeout */, this,
6813                     windowsDrawnDelayMs, launchState);
6814         }
6815         finishLaunchTickingLocked();
6816         if (task != null) {
6817             setTaskHasBeenVisible();
6818         }
6819         // Clear indicated launch root task because there's no trampoline activity to expect after
6820         // the windows are drawn.
6821         mLaunchRootTask = null;
6822     }
6823 
6824     /** Called when the windows associated app window container are visible. */
onWindowsVisible()6825     void onWindowsVisible() {
6826         if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in " + token);
6827         mTaskSupervisor.stopWaitingForActivityVisible(this);
6828         if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
6829         if (!nowVisible) {
6830             nowVisible = true;
6831             lastVisibleTime = SystemClock.uptimeMillis();
6832             mAtmService.scheduleAppGcsLocked();
6833             // The nowVisible may be false in onAnimationFinished because the transition animation
6834             // was started by starting window but the main window hasn't drawn so the procedure
6835             // didn't schedule. Hence also check when nowVisible becomes true (drawn) to avoid the
6836             // closing activity having to wait until idle timeout to be stopped or destroyed if the
6837             // next activity won't report idle (e.g. repeated view animation).
6838             mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
6839 
6840             // If the activity is visible, but no windows are eligible to start input, unfreeze
6841             // to avoid permanently frozen IME insets.
6842             if (mImeInsetsFrozenUntilStartInput && getWindow(
6843                     win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags))
6844                     == null) {
6845                 mImeInsetsFrozenUntilStartInput = false;
6846             }
6847         }
6848     }
6849 
6850     /** Called when the windows associated app window container are no longer visible. */
onWindowsGone()6851     void onWindowsGone() {
6852         if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in " + token);
6853         if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
6854         nowVisible = false;
6855     }
6856 
6857     @Override
checkAppWindowsReadyToShow()6858     void checkAppWindowsReadyToShow() {
6859         if (allDrawn == mLastAllDrawn) {
6860             return;
6861         }
6862 
6863         mLastAllDrawn = allDrawn;
6864         if (!allDrawn) {
6865             return;
6866         }
6867 
6868         // The token has now changed state to having all windows shown...  what to do, what to do?
6869         if (mFreezingScreen) {
6870             showAllWindowsLocked();
6871             stopFreezingScreen(false, true);
6872             ProtoLog.i(WM_DEBUG_ORIENTATION,
6873                     "Setting mOrientationChangeComplete=true because wtoken %s "
6874                             + "numInteresting=%d numDrawn=%d",
6875                     this, mNumInterestingWindows, mNumDrawnWindows);
6876             // This will set mOrientationChangeComplete and cause a pass through layout.
6877             setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
6878                     "checkAppWindowsReadyToShow: freezingScreen");
6879         } else {
6880             setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
6881 
6882             // We can now show all of the drawn windows!
6883             if (!getDisplayContent().mOpeningApps.contains(this) && canShowWindows()) {
6884                 showAllWindowsLocked();
6885             }
6886         }
6887     }
6888 
6889     /**
6890      * This must be called while inside a transaction.
6891      */
showAllWindowsLocked()6892     void showAllWindowsLocked() {
6893         forAllWindows(windowState -> {
6894             if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState);
6895             windowState.performShowLocked();
6896         }, false /* traverseTopToBottom */);
6897     }
6898 
updateReportedVisibilityLocked()6899     void updateReportedVisibilityLocked() {
6900         if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
6901         final int count = mChildren.size();
6902 
6903         mReportedVisibilityResults.reset();
6904 
6905         for (int i = 0; i < count; i++) {
6906             final WindowState win = mChildren.get(i);
6907             win.updateReportedVisibility(mReportedVisibilityResults);
6908         }
6909 
6910         int numInteresting = mReportedVisibilityResults.numInteresting;
6911         int numVisible = mReportedVisibilityResults.numVisible;
6912         int numDrawn = mReportedVisibilityResults.numDrawn;
6913         boolean nowGone = mReportedVisibilityResults.nowGone;
6914 
6915         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
6916         boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && isVisible();
6917         if (!nowGone) {
6918             // If the app is not yet gone, then it can only become visible/drawn.
6919             if (!nowDrawn) {
6920                 nowDrawn = mReportedDrawn;
6921             }
6922             if (!nowVisible) {
6923                 nowVisible = reportedVisible;
6924             }
6925         }
6926         if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
6927                 + numInteresting + " visible=" + numVisible);
6928         if (nowDrawn != mReportedDrawn) {
6929             if (nowDrawn) {
6930                 onWindowsDrawn();
6931             }
6932             mReportedDrawn = nowDrawn;
6933         }
6934         if (nowVisible != reportedVisible) {
6935             if (DEBUG_VISIBILITY) Slog.v(TAG,
6936                     "Visibility changed in " + this + ": vis=" + nowVisible);
6937             reportedVisible = nowVisible;
6938             if (nowVisible) {
6939                 onWindowsVisible();
6940             } else {
6941                 onWindowsGone();
6942             }
6943         }
6944     }
6945 
isReportedDrawn()6946     boolean isReportedDrawn() {
6947         return mReportedDrawn;
6948     }
6949 
6950     @Override
setClientVisible(boolean clientVisible)6951     void setClientVisible(boolean clientVisible) {
6952         // TODO(shell-transitions): Remove mDeferHidingClient once everything is shell-transitions.
6953         //                          pip activities should just remain in clientVisible.
6954         if (!clientVisible && mDeferHidingClient) return;
6955         super.setClientVisible(clientVisible);
6956     }
6957 
6958     /**
6959      * Updated this app token tracking states for interesting and drawn windows based on the window.
6960      *
6961      * @return Returns true if the input window is considered interesting and drawn while all the
6962      *         windows in this app token where not considered drawn as of the last pass.
6963      */
updateDrawnWindowStates(WindowState w)6964     boolean updateDrawnWindowStates(WindowState w) {
6965         w.setDrawnStateEvaluated(true /*evaluated*/);
6966 
6967         if (DEBUG_STARTING_WINDOW_VERBOSE && w == mStartingWindow) {
6968             Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
6969                     + " allDrawn=" + allDrawn + " freezingScreen=" + mFreezingScreen);
6970         }
6971 
6972         if (allDrawn && !mFreezingScreen) {
6973             return false;
6974         }
6975 
6976         if (mLastTransactionSequence != mWmService.mTransactionSequence) {
6977             mLastTransactionSequence = mWmService.mTransactionSequence;
6978             mNumDrawnWindows = 0;
6979 
6980             // There is the main base application window, even if it is exiting, wait for it
6981             mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0;
6982         }
6983 
6984         final WindowStateAnimator winAnimator = w.mWinAnimator;
6985 
6986         boolean isInterestingAndDrawn = false;
6987 
6988         if (!allDrawn && w.mightAffectAllDrawn()) {
6989             if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
6990                 final boolean isAnimationSet = isAnimating(TRANSITION | PARENTS,
6991                         ANIMATION_TYPE_APP_TRANSITION);
6992                 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawn()
6993                         + ", isAnimationSet=" + isAnimationSet);
6994                 if (!w.isDrawn()) {
6995                     Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
6996                             + " pv=" + w.isVisibleByPolicy()
6997                             + " mDrawState=" + winAnimator.drawStateToString()
6998                             + " ph=" + w.isParentWindowHidden() + " th=" + mVisibleRequested
6999                             + " a=" + isAnimationSet);
7000                 }
7001             }
7002 
7003             if (w != mStartingWindow) {
7004                 if (w.isInteresting()) {
7005                     // Add non-main window as interesting since the main app has already been added
7006                     if (findMainWindow(false /* includeStartingApp */) != w) {
7007                         mNumInterestingWindows++;
7008                     }
7009                     if (w.isDrawn()) {
7010                         mNumDrawnWindows++;
7011 
7012                         if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
7013                             Slog.v(TAG, "tokenMayBeDrawn: "
7014                                     + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
7015                                     + " freezingScreen=" + mFreezingScreen
7016                                     + " mAppFreezing=" + w.mAppFreezing);
7017                         }
7018 
7019                         isInterestingAndDrawn = true;
7020                     }
7021                 }
7022             } else if (mStartingData != null && w.isDrawn()) {
7023                 // The starting window for this container is drawn.
7024                 mStartingData.mIsDisplayed = true;
7025             }
7026         }
7027 
7028         return isInterestingAndDrawn;
7029     }
7030 
7031     /**
7032      * Called when the input dispatching to a window associated with the app window container
7033      * timed-out.
7034      *
7035      * @param reason The reason for input dispatching time out.
7036      * @param windowPid The pid of the window input dispatching timed out on.
7037      * @return True if input dispatching should be aborted.
7038      */
inputDispatchingTimedOut(TimeoutRecord timeoutRecord, int windowPid)7039     public boolean inputDispatchingTimedOut(TimeoutRecord timeoutRecord, int windowPid) {
7040         try {
7041             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
7042                     "ActivityRecord#inputDispatchingTimedOut()");
7043             ActivityRecord anrActivity;
7044             WindowProcessController anrApp;
7045             boolean blameActivityProcess;
7046             timeoutRecord.mLatencyTracker.waitingOnGlobalLockStarted();
7047             synchronized (mAtmService.mGlobalLock) {
7048                 timeoutRecord.mLatencyTracker.waitingOnGlobalLockEnded();
7049                 anrActivity = getWaitingHistoryRecordLocked();
7050                 anrApp = app;
7051                 blameActivityProcess =  hasProcess()
7052                         && (app.getPid() == windowPid || windowPid == INVALID_PID);
7053             }
7054 
7055             if (blameActivityProcess) {
7056                 return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner,
7057                         anrActivity.shortComponentName, anrActivity.info.applicationInfo,
7058                         shortComponentName, app, false, timeoutRecord);
7059             } else {
7060                 // In this case another process added windows using this activity token.
7061                 // So, we call the generic service input dispatch timed out method so
7062                 // that the right process is blamed.
7063                 long timeoutMillis = mAtmService.mAmInternal.inputDispatchingTimedOut(
7064                         windowPid, false /* aboveSystem */, timeoutRecord);
7065                 return timeoutMillis <= 0;
7066             }
7067         } finally {
7068             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
7069         }
7070 
7071     }
7072 
getWaitingHistoryRecordLocked()7073     private ActivityRecord getWaitingHistoryRecordLocked() {
7074         // First find the real culprit...  if this activity has stopped, then the key dispatching
7075         // timeout should not be caused by this.
7076         if (mAppStopped) {
7077             final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
7078             if (rootTask == null) {
7079                 return this;
7080             }
7081             // Try to use the one which is closest to top.
7082             ActivityRecord r = rootTask.getTopResumedActivity();
7083             if (r == null) {
7084                 r = rootTask.getTopPausingActivity();
7085             }
7086             if (r != null) {
7087                 return r;
7088             }
7089         }
7090         return this;
7091     }
7092 
canBeTopRunning()7093     boolean canBeTopRunning() {
7094         return !finishing && showToCurrentUser();
7095     }
7096 
7097     /**
7098      * This method will return true if the activity is either visible, is becoming visible, is
7099      * currently pausing, or is resumed.
7100      */
isInterestingToUserLocked()7101     public boolean isInterestingToUserLocked() {
7102         return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED;
7103     }
7104 
getTaskForActivityLocked(IBinder token, boolean onlyRoot)7105     static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7106         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
7107         if (r == null || r.getParent() == null) {
7108             return INVALID_TASK_ID;
7109         }
7110         return getTaskForActivityLocked(r, onlyRoot);
7111     }
7112 
getTaskForActivityLocked(ActivityRecord r, boolean onlyRoot)7113     static int getTaskForActivityLocked(ActivityRecord r, boolean onlyRoot) {
7114         final Task task = r.task;
7115         if (onlyRoot && r.compareTo(task.getRootActivity(
7116                 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)) > 0) {
7117             return INVALID_TASK_ID;
7118         }
7119         return task.mTaskId;
7120     }
7121 
isInRootTaskLocked(IBinder token)7122     static ActivityRecord isInRootTaskLocked(IBinder token) {
7123         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
7124         return (r != null) ? r.getRootTask().isInTask(r) : null;
7125     }
7126 
getRootTask(IBinder token)7127     static Task getRootTask(IBinder token) {
7128         final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
7129         if (r != null) {
7130             return r.getRootTask();
7131         }
7132         return null;
7133     }
7134 
7135     @Nullable
isInAnyTask(IBinder token)7136     static ActivityRecord isInAnyTask(IBinder token) {
7137         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
7138         return (r != null && r.isAttached()) ? r : null;
7139     }
7140 
7141     /**
7142      * @return display id to which this record is attached,
7143      *         {@link android.view.Display#INVALID_DISPLAY} if not attached.
7144      */
getDisplayId()7145     int getDisplayId() {
7146         return task != null && task.mDisplayContent != null
7147                  ? task.mDisplayContent.mDisplayId : INVALID_DISPLAY;
7148     }
7149 
isDestroyable()7150     final boolean isDestroyable() {
7151         if (finishing || !hasProcess()) {
7152             // This would be redundant.
7153             return false;
7154         }
7155         if (isState(RESUMED) || getRootTask() == null
7156                 || this == getTaskFragment().getPausingActivity()
7157                 || !mHaveState || !mAppStopped) {
7158             // We're not ready for this kind of thing.
7159             return false;
7160         }
7161         if (mVisibleRequested) {
7162             // The user would notice this!
7163             return false;
7164         }
7165         return true;
7166     }
7167 
createImageFilename(long createTime, int taskId)7168     private static String createImageFilename(long createTime, int taskId) {
7169         return String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + createTime +
7170                 IMAGE_EXTENSION;
7171     }
7172 
setTaskDescription(TaskDescription _taskDescription)7173     void setTaskDescription(TaskDescription _taskDescription) {
7174         Bitmap icon;
7175         if (_taskDescription.getIconFilename() == null &&
7176                 (icon = _taskDescription.getIcon()) != null) {
7177             final String iconFilename = createImageFilename(createTime, task.mTaskId);
7178             final File iconFile = new File(TaskPersister.getUserImagesDir(task.mUserId),
7179                     iconFilename);
7180             final String iconFilePath = iconFile.getAbsolutePath();
7181             mAtmService.getRecentTasks().saveImage(icon, iconFilePath);
7182             _taskDescription.setIconFilename(iconFilePath);
7183         }
7184         taskDescription = _taskDescription;
7185         getTask().updateTaskDescription();
7186     }
7187 
setLocusId(LocusId locusId)7188     void setLocusId(LocusId locusId) {
7189         if (Objects.equals(locusId, mLocusId)) return;
7190         mLocusId = locusId;
7191         final Task task = getTask();
7192         if (task != null) getTask().dispatchTaskInfoChangedIfNeeded(false /* force */);
7193     }
7194 
getLocusId()7195     LocusId getLocusId() {
7196         return mLocusId;
7197     }
7198 
reportScreenCaptured()7199     public void reportScreenCaptured() {
7200         if (mCaptureCallbacks != null) {
7201             final int n = mCaptureCallbacks.beginBroadcast();
7202             for (int i = 0; i < n; i++) {
7203                 IScreenCaptureObserver obs = mCaptureCallbacks.getBroadcastItem(i);
7204                 try {
7205                     obs.onScreenCaptured();
7206                 } catch (RemoteException e) {
7207                 }
7208             }
7209             mCaptureCallbacks.finishBroadcast();
7210         }
7211     }
7212 
registerCaptureObserver(IScreenCaptureObserver observer)7213     public void registerCaptureObserver(IScreenCaptureObserver observer) {
7214         synchronized (mWmService.mGlobalLock) {
7215             if (mCaptureCallbacks == null) {
7216                 mCaptureCallbacks = new RemoteCallbackList<IScreenCaptureObserver>();
7217             }
7218             mCaptureCallbacks.register(observer);
7219         }
7220     }
7221 
unregisterCaptureObserver(IScreenCaptureObserver observer)7222     public void unregisterCaptureObserver(IScreenCaptureObserver observer) {
7223         synchronized (mWmService.mGlobalLock) {
7224             if (mCaptureCallbacks != null) {
7225                 mCaptureCallbacks.unregister(observer);
7226             }
7227         }
7228     }
7229 
isRegisteredForScreenCaptureCallback()7230     boolean isRegisteredForScreenCaptureCallback() {
7231         return mCaptureCallbacks != null && mCaptureCallbacks.getRegisteredCallbackCount() > 0;
7232     }
7233 
setVoiceSessionLocked(IVoiceInteractionSession session)7234     void setVoiceSessionLocked(IVoiceInteractionSession session) {
7235         voiceSession = session;
7236         pendingVoiceInteractionStart = false;
7237     }
7238 
clearVoiceSessionLocked()7239     void clearVoiceSessionLocked() {
7240         voiceSession = null;
7241         pendingVoiceInteractionStart = false;
7242     }
7243 
showStartingWindow(boolean taskSwitch)7244     void showStartingWindow(boolean taskSwitch) {
7245         showStartingWindow(null /* prev */, false /* newTask */, taskSwitch,
7246                 false /* startActivity */, null);
7247     }
7248 
7249     /**
7250      * Search for the candidate launching activity from currently visible activities.
7251      *
7252      * This activity could be launched from service, so we need to check whether there is existing a
7253      * foreground activity from the same process or same package.
7254      *
7255      */
searchCandidateLaunchingActivity()7256     private ActivityRecord searchCandidateLaunchingActivity() {
7257         // Get previous activity below self
7258         ActivityRecord below = task.getActivityBelow(this);
7259         if (below == null) {
7260             below = task.getParent().getActivityBelow(this);
7261         }
7262 
7263         if (below == null || below.isActivityTypeHome()) {
7264             return null;
7265         }
7266         final WindowProcessController myProcess = app != null
7267                 ? app : mAtmService.mProcessNames.get(processName, info.applicationInfo.uid);
7268         final WindowProcessController candidateProcess = below.app != null
7269                         ? below.app
7270                         : mAtmService.mProcessNames.get(below.processName,
7271                                 below.info.applicationInfo.uid);
7272         // same process or same package
7273         if (candidateProcess == myProcess
7274                 || mActivityComponent.getPackageName()
7275                 .equals(below.mActivityComponent.getPackageName())) {
7276             return below;
7277         }
7278         return null;
7279     }
7280 
isIconStylePreferred(int theme)7281     private boolean isIconStylePreferred(int theme) {
7282         if (theme == 0) {
7283             return false;
7284         }
7285         final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, theme,
7286                 R.styleable.Window, mWmService.mCurrentUserId);
7287         if (ent != null) {
7288             if (ent.array.hasValue(R.styleable.Window_windowSplashScreenBehavior)) {
7289                 return ent.array.getInt(R.styleable.Window_windowSplashScreenBehavior,
7290                         SPLASH_SCREEN_BEHAVIOR_DEFAULT)
7291                         == SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED;
7292             }
7293         }
7294         return false;
7295     }
shouldUseSolidColorSplashScreen(ActivityRecord sourceRecord, boolean startActivity, ActivityOptions options, int resolvedTheme)7296     private boolean shouldUseSolidColorSplashScreen(ActivityRecord sourceRecord,
7297             boolean startActivity, ActivityOptions options, int resolvedTheme) {
7298         if (sourceRecord == null && !startActivity) {
7299             // Use simple style if this activity is not top activity. This could happen when adding
7300             // a splash screen window to the warm start activity which is re-create because top is
7301             // finishing.
7302             final ActivityRecord above = task.getActivityAbove(this);
7303             if (above != null) {
7304                 return true;
7305             }
7306         }
7307 
7308         // setSplashScreenStyle decide in priority of windowSplashScreenBehavior.
7309         if (options != null) {
7310             final int optionsStyle = options.getSplashScreenStyle();
7311             if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR) {
7312                 return true;
7313             } else if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_ICON
7314                     || isIconStylePreferred(resolvedTheme)) {
7315                 return false;
7316             }
7317             // Choose the default behavior for Launcher and SystemUI when the SplashScreen style is
7318             // not specified in the ActivityOptions.
7319             if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME
7320                     || launchedFromUid == Process.SHELL_UID) {
7321                 return false;
7322             } else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) {
7323                 return true;
7324             }
7325         } else if (isIconStylePreferred(resolvedTheme)) {
7326             return false;
7327         }
7328         if (sourceRecord == null) {
7329             sourceRecord = searchCandidateLaunchingActivity();
7330         }
7331 
7332         if (sourceRecord != null && !sourceRecord.isActivityTypeHome()) {
7333             return sourceRecord.mSplashScreenStyleSolidColor;
7334         }
7335 
7336         // If this activity was launched from Launcher or System for first start, never use a
7337         // solid color splash screen.
7338         // Need to check sourceRecord before in case this activity is launched from service.
7339         return !startActivity || !(mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEM
7340                 || mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME
7341                 || launchedFromUid == Process.SHELL_UID);
7342     }
7343 
getSplashscreenTheme(ActivityOptions options)7344     private int getSplashscreenTheme(ActivityOptions options) {
7345         // Find the splash screen theme. User can override the persisted theme by
7346         // ActivityOptions.
7347         String splashScreenThemeResName = options != null
7348                 ? options.getSplashScreenThemeResName() : null;
7349         if (splashScreenThemeResName == null || splashScreenThemeResName.isEmpty()) {
7350             try {
7351                 splashScreenThemeResName = mAtmService.getPackageManager()
7352                         .getSplashScreenTheme(packageName, mUserId);
7353             } catch (RemoteException ignore) {
7354                 // Just use the default theme
7355             }
7356         }
7357         int splashScreenThemeResId = 0;
7358         if (splashScreenThemeResName != null && !splashScreenThemeResName.isEmpty()) {
7359             try {
7360                 final Context packageContext = mAtmService.mContext
7361                         .createPackageContext(packageName, 0);
7362                 splashScreenThemeResId = packageContext.getResources()
7363                         .getIdentifier(splashScreenThemeResName, null, null);
7364             } catch (PackageManager.NameNotFoundException
7365                     | Resources.NotFoundException ignore) {
7366                 // Just use the default theme
7367             }
7368         }
7369         return splashScreenThemeResId;
7370     }
7371 
showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, boolean startActivity, ActivityRecord sourceRecord)7372     void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
7373             boolean startActivity, ActivityRecord sourceRecord) {
7374         showStartingWindow(prev, newTask, taskSwitch, isProcessRunning(), startActivity,
7375                 sourceRecord, null /* candidateOptions */);
7376     }
7377 
7378     /**
7379      * @param prev Previous activity which contains a starting window.
7380      * @param processRunning Whether the client process is running.
7381      * @param startActivity Whether this activity is just created from starter.
7382      * @param sourceRecord The source activity which start this activity.
7383      * @param candidateOptions The options for the style of starting window.
7384      */
showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, boolean processRunning, boolean startActivity, ActivityRecord sourceRecord, ActivityOptions candidateOptions)7385     void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
7386             boolean processRunning, boolean startActivity, ActivityRecord sourceRecord,
7387             ActivityOptions candidateOptions) {
7388         if (mTaskOverlay) {
7389             // We don't show starting window for overlay activities.
7390             return;
7391         }
7392         final ActivityOptions startOptions = candidateOptions != null
7393                 ? candidateOptions : mPendingOptions;
7394         if (startOptions != null
7395                 && startOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
7396             // Don't show starting window when using shared element transition.
7397             return;
7398         }
7399 
7400         final int splashScreenTheme = startActivity ? getSplashscreenTheme(startOptions) : 0;
7401         final int resolvedTheme = evaluateStartingWindowTheme(prev, packageName, theme,
7402                 splashScreenTheme);
7403 
7404         mSplashScreenStyleSolidColor = shouldUseSolidColorSplashScreen(sourceRecord, startActivity,
7405                 startOptions, resolvedTheme);
7406 
7407         final boolean activityCreated =
7408                 mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal();
7409         // If this activity is just created and all activities below are finish, treat this
7410         // scenario as warm launch.
7411         final boolean newSingleActivity = !newTask && !activityCreated
7412                 && task.getActivity((r) -> !r.finishing && r != this) == null;
7413 
7414         final boolean scheduled = addStartingWindow(packageName, resolvedTheme,
7415                 prev, newTask || newSingleActivity, taskSwitch, processRunning,
7416                 allowTaskSnapshot(), activityCreated, mSplashScreenStyleSolidColor, allDrawn);
7417         if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) {
7418             Slog.d(TAG, "Scheduled starting window for " + this);
7419         }
7420     }
7421 
7422     /**
7423      * If any activities below the top running one are in the INITIALIZING state and they have a
7424      * starting window displayed then remove that starting window. It is possible that the activity
7425      * in this state will never resumed in which case that starting window will be orphaned.
7426      * <p>
7427      * It should only be called if this activity is behind other fullscreen activity.
7428      */
cancelInitializing()7429     void cancelInitializing() {
7430         if (mStartingData != null) {
7431             // Remove orphaned starting window.
7432             if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
7433             removeStartingWindowAnimation(false /* prepareAnimation */);
7434         }
7435         if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
7436             // Remove the unknown visibility record because an invisible activity shouldn't block
7437             // the keyguard transition.
7438             mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
7439         }
7440     }
7441 
postWindowRemoveStartingWindowCleanup()7442     void postWindowRemoveStartingWindowCleanup() {
7443         if (mChildren.size() == 0 && mVisibleSetFromTransferredStartingWindow) {
7444             // We set the visible state to true for the token from a transferred starting
7445             // window. We now reset it back to false since the starting window was the last
7446             // window in the token.
7447             setVisible(false);
7448         }
7449     }
7450 
requestUpdateWallpaperIfNeeded()7451     void requestUpdateWallpaperIfNeeded() {
7452         for (int i = mChildren.size() - 1; i >= 0; i--) {
7453             final WindowState w = mChildren.get(i);
7454             w.requestUpdateWallpaperIfNeeded();
7455         }
7456     }
7457 
7458     /**
7459      * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns
7460      *         true and isn't fully transparent.
7461      */
getTopFullscreenOpaqueWindow()7462     WindowState getTopFullscreenOpaqueWindow() {
7463         for (int i = mChildren.size() - 1; i >= 0; i--) {
7464             final WindowState win = mChildren.get(i);
7465             if (win != null && win.mAttrs.isFullscreen() && !win.isFullyTransparent()) {
7466                 return win;
7467             }
7468         }
7469         return null;
7470     }
7471 
findMainWindow()7472     WindowState findMainWindow() {
7473         return findMainWindow(true);
7474     }
7475 
7476     /**
7477      * Finds the main window that either has type base application or application starting if
7478      * requested.
7479      *
7480      * @param includeStartingApp Allow to search application-starting windows to also be returned.
7481      * @return The main window of type base application or application starting if requested.
7482      */
findMainWindow(boolean includeStartingApp)7483     WindowState findMainWindow(boolean includeStartingApp) {
7484         WindowState candidate = null;
7485         for (int j = mChildren.size() - 1; j >= 0; --j) {
7486             final WindowState win = mChildren.get(j);
7487             final int type = win.mAttrs.type;
7488             // No need to loop through child window as base application and starting types can't be
7489             // child windows.
7490             if (type == TYPE_BASE_APPLICATION
7491                     || (includeStartingApp && type == TYPE_APPLICATION_STARTING)) {
7492                 // In cases where there are multiple windows, we prefer the non-exiting window. This
7493                 // happens for example when replacing windows during an activity relaunch. When
7494                 // constructing the animation, we want the new window, not the exiting one.
7495                 if (win.mAnimatingExit) {
7496                     candidate = win;
7497                 } else {
7498                     return win;
7499                 }
7500             }
7501         }
7502         return candidate;
7503     }
7504 
7505     @Override
needsZBoost()7506     boolean needsZBoost() {
7507         return mNeedsZBoost || super.needsZBoost();
7508     }
7509 
7510     @Override
getAnimationLeashParent()7511     public SurfaceControl getAnimationLeashParent() {
7512         // For transitions in the root pinned task (menu activity) we just let them occur as a child
7513         // of the root pinned task.
7514         // All normal app transitions take place in an animation layer which is below the root
7515         // pinned task but may be above the parent tasks of the given animating apps by default.
7516         // When a new hierarchical animation is enabled, we just let them occur as a child of the
7517         // parent task, i.e. the hierarchy of the surfaces is unchanged.
7518         if (inPinnedWindowingMode()) {
7519             return getRootTask().getSurfaceControl();
7520         } else {
7521             return super.getAnimationLeashParent();
7522         }
7523     }
7524 
7525     @VisibleForTesting
shouldAnimate()7526     boolean shouldAnimate() {
7527         return task == null || task.shouldAnimate();
7528     }
7529 
7530     /**
7531      * Creates a layer to apply crop to an animation.
7532      */
createAnimationBoundsLayer(Transaction t)7533     private SurfaceControl createAnimationBoundsLayer(Transaction t) {
7534         ProtoLog.i(WM_DEBUG_APP_TRANSITIONS_ANIM, "Creating animation bounds layer");
7535         final SurfaceControl.Builder builder = makeAnimationLeash()
7536                 .setParent(getAnimationLeashParent())
7537                 .setName(getSurfaceControl() + " - animation-bounds")
7538                 .setCallsite("ActivityRecord.createAnimationBoundsLayer");
7539         if (mNeedsLetterboxedAnimation) {
7540             // Needs to be an effect layer to support rounded corners
7541             builder.setEffectLayer();
7542         }
7543         final SurfaceControl boundsLayer = builder.build();
7544         t.show(boundsLayer);
7545         return boundsLayer;
7546     }
7547 
7548     @Override
shouldDeferAnimationFinish(Runnable endDeferFinishCallback)7549     public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
7550         return mAnimatingActivityRegistry != null
7551                 && mAnimatingActivityRegistry.notifyAboutToFinish(
7552                 this, endDeferFinishCallback);
7553     }
7554 
7555     @Override
isWaitingForTransitionStart()7556     boolean isWaitingForTransitionStart() {
7557         final DisplayContent dc = getDisplayContent();
7558         return dc != null && dc.mAppTransition.isTransitionSet()
7559                 && (dc.mOpeningApps.contains(this)
7560                 || dc.mClosingApps.contains(this)
7561                 || dc.mChangingContainers.contains(this));
7562     }
7563 
isTransitionForward()7564     boolean isTransitionForward() {
7565         return (mStartingData != null && mStartingData.mIsTransitionForward)
7566                 || mDisplayContent.isNextTransitionForward();
7567     }
7568 
7569     @Override
resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t)7570     void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) {
7571         // Noop as Activity may be offset for letterbox
7572     }
7573 
7574     @Override
onLeashAnimationStarting(Transaction t, SurfaceControl leash)7575     public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) {
7576         if (mAnimatingActivityRegistry != null) {
7577             mAnimatingActivityRegistry.notifyStarting(this);
7578         }
7579 
7580         if (mNeedsLetterboxedAnimation) {
7581             updateLetterboxSurface(findMainWindow(), t);
7582             mNeedsAnimationBoundsLayer = true;
7583         }
7584 
7585         // If the animation needs to be cropped then an animation bounds layer is created as a
7586         // child of the root pinned task or animation layer. The leash is then reparented to this
7587         // new layer.
7588         if (mNeedsAnimationBoundsLayer) {
7589             mTmpRect.setEmpty();
7590             if (getDisplayContent().mAppTransitionController.isTransitWithinTask(
7591                     getTransit(), task)) {
7592                 task.getBounds(mTmpRect);
7593             } else {
7594                 final Task rootTask = getRootTask();
7595                 if (rootTask == null) {
7596                     return;
7597                 }
7598                 // Set clip rect to root task bounds.
7599                 rootTask.getBounds(mTmpRect);
7600             }
7601             mAnimationBoundsLayer = createAnimationBoundsLayer(t);
7602 
7603             // Crop to root task bounds.
7604             t.setLayer(leash, 0);
7605             t.setLayer(mAnimationBoundsLayer, getLastLayer());
7606 
7607             if (mNeedsLetterboxedAnimation) {
7608                 final int cornerRadius = mLetterboxUiController
7609                         .getRoundedCornersRadius(findMainWindow());
7610 
7611                 final Rect letterboxInnerBounds = new Rect();
7612                 getLetterboxInnerBounds(letterboxInnerBounds);
7613 
7614                 t.setCornerRadius(mAnimationBoundsLayer, cornerRadius)
7615                         .setCrop(mAnimationBoundsLayer, letterboxInnerBounds);
7616             }
7617 
7618             // Reparent leash to animation bounds layer.
7619             t.reparent(leash, mAnimationBoundsLayer);
7620         }
7621     }
7622 
7623     @Override
showSurfaceOnCreation()7624     boolean showSurfaceOnCreation() {
7625         return false;
7626     }
7627 
7628     @Override
prepareSurfaces()7629     void prepareSurfaces() {
7630         final boolean show = isVisible() || isAnimating(PARENTS,
7631                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS
7632                         | ANIMATION_TYPE_PREDICT_BACK);
7633 
7634         if (mSurfaceControl != null) {
7635             if (show && !mLastSurfaceShowing) {
7636                 getSyncTransaction().show(mSurfaceControl);
7637             } else if (!show && mLastSurfaceShowing) {
7638                 getSyncTransaction().hide(mSurfaceControl);
7639             }
7640             // Input sink surface is not a part of animation, so just apply in a steady state
7641             // (non-sync) with pending transaction.
7642             if (show && mSyncState == SYNC_STATE_NONE) {
7643                 mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getPendingTransaction());
7644             }
7645         }
7646         if (mThumbnail != null) {
7647             mThumbnail.setShowing(getPendingTransaction(), show);
7648         }
7649         mLastSurfaceShowing = show;
7650         super.prepareSurfaces();
7651     }
7652 
7653     /**
7654      * @return Whether our {@link #getSurfaceControl} is currently showing.
7655      */
isSurfaceShowing()7656     boolean isSurfaceShowing() {
7657         return mLastSurfaceShowing;
7658     }
7659 
attachThumbnailAnimation()7660     void attachThumbnailAnimation() {
7661         if (!isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
7662             return;
7663         }
7664         final HardwareBuffer thumbnailHeader =
7665                 getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(task);
7666         if (thumbnailHeader == null) {
7667             ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", task);
7668             return;
7669         }
7670         clearThumbnail();
7671         final Transaction transaction = getAnimatingContainer().getPendingTransaction();
7672         mThumbnail = new WindowContainerThumbnail(transaction, getAnimatingContainer(),
7673                 thumbnailHeader);
7674         mThumbnail.startAnimation(transaction, loadThumbnailAnimation(thumbnailHeader));
7675     }
7676 
7677     /**
7678      * Attaches a surface with a thumbnail for the
7679      * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation.
7680      */
attachCrossProfileAppsThumbnailAnimation()7681     void attachCrossProfileAppsThumbnailAnimation() {
7682         if (!isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
7683             return;
7684         }
7685         clearThumbnail();
7686 
7687         final WindowState win = findMainWindow();
7688         if (win == null) {
7689             return;
7690         }
7691         final Rect frame = win.getRelativeFrame();
7692         final Drawable thumbnailDrawable = task.mUserId == mWmService.mCurrentUserId
7693                 ? mAtmService.getUiContext().getDrawable(R.drawable.ic_account_circle)
7694                 : mEnterpriseThumbnailDrawable;
7695         final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
7696                 .createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
7697         if (thumbnail == null) {
7698             return;
7699         }
7700         final Transaction transaction = getPendingTransaction();
7701         mThumbnail = new WindowContainerThumbnail(transaction, getTask(), thumbnail);
7702         final Animation animation =
7703                 getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(
7704                         frame);
7705         mThumbnail.startAnimation(transaction, animation, new Point(frame.left, frame.top));
7706     }
7707 
loadThumbnailAnimation(HardwareBuffer thumbnailHeader)7708     private Animation loadThumbnailAnimation(HardwareBuffer thumbnailHeader) {
7709         final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
7710 
7711         // If this is a multi-window scenario, we use the windows frame as
7712         // destination of the thumbnail header animation. If this is a full screen
7713         // window scenario, we use the whole display as the target.
7714         WindowState win = findMainWindow();
7715         Rect insets;
7716         Rect appRect;
7717         if (win != null) {
7718             insets = win.getInsetsStateWithVisibilityOverride().calculateInsets(
7719                     win.getFrame(), Type.systemBars(), false /* ignoreVisibility */).toRect();
7720             appRect = new Rect(win.getFrame());
7721             appRect.inset(insets);
7722         } else {
7723             insets = null;
7724             appRect = new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
7725         }
7726         final Configuration displayConfig = mDisplayContent.getConfiguration();
7727         return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
7728                 appRect, insets, thumbnailHeader, task, displayConfig.orientation);
7729     }
7730 
7731     @Override
onAnimationLeashLost(Transaction t)7732     public void onAnimationLeashLost(Transaction t) {
7733         super.onAnimationLeashLost(t);
7734         if (mAnimationBoundsLayer != null) {
7735             t.remove(mAnimationBoundsLayer);
7736             mAnimationBoundsLayer = null;
7737         }
7738 
7739         mNeedsAnimationBoundsLayer = false;
7740         if (mNeedsLetterboxedAnimation) {
7741             mNeedsLetterboxedAnimation = false;
7742             updateLetterboxSurface(findMainWindow(), t);
7743         }
7744 
7745         if (mAnimatingActivityRegistry != null) {
7746             mAnimatingActivityRegistry.notifyFinished(this);
7747         }
7748     }
7749 
7750     @Override
onAnimationFinished(@nimationType int type, AnimationAdapter anim)7751     protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
7752         super.onAnimationFinished(type, anim);
7753 
7754         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished");
7755         mTransit = TRANSIT_OLD_UNSET;
7756         mTransitFlags = 0;
7757 
7758         setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
7759                 "ActivityRecord");
7760 
7761         clearThumbnail();
7762         setClientVisible(isVisible() || mVisibleRequested);
7763 
7764         getDisplayContent().computeImeTargetIfNeeded(this);
7765 
7766         ProtoLog.v(WM_DEBUG_ANIM, "Animation done in %s"
7767                 + ": reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
7768                 this, reportedVisible, okToDisplay(), okToAnimate(),
7769                 isStartingWindowDisplayed());
7770 
7771         // clean up thumbnail window
7772         if (mThumbnail != null) {
7773             mThumbnail.destroy();
7774             mThumbnail = null;
7775         }
7776 
7777         // WindowState.onExitAnimationDone might modify the children list, so make a copy and then
7778         // traverse the copy.
7779         final ArrayList<WindowState> children = new ArrayList<>(mChildren);
7780         children.forEach(WindowState::onExitAnimationDone);
7781         // The starting window could transfer to another activity after app transition started, in
7782         // that case the latest top activity might not receive exit animation done callback if the
7783         // starting window didn't applied exit animation success. Notify animation finish to the
7784         // starting window if needed.
7785         if (task != null && startingMoved) {
7786             final WindowState transferredStarting = task.getWindow(w ->
7787                     w.mAttrs.type == TYPE_APPLICATION_STARTING);
7788             if (transferredStarting != null && transferredStarting.mAnimatingExit
7789                     && !transferredStarting.isSelfAnimating(0 /* flags */,
7790                     ANIMATION_TYPE_WINDOW_ANIMATION)) {
7791                 transferredStarting.onExitAnimationDone();
7792             }
7793         }
7794 
7795         getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
7796         scheduleAnimation();
7797 
7798         // Schedule to handle the stopping and finishing activities which the animation is done
7799         // because the activities which were animating have not been stopped yet.
7800         mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
7801         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
7802     }
7803 
clearAnimatingFlags()7804     void clearAnimatingFlags() {
7805         boolean wallpaperMightChange = false;
7806         for (int i = mChildren.size() - 1; i >= 0; i--) {
7807             final WindowState win = mChildren.get(i);
7808             wallpaperMightChange |= win.clearAnimatingFlags();
7809         }
7810         if (wallpaperMightChange) {
7811             requestUpdateWallpaperIfNeeded();
7812         }
7813     }
7814 
7815     @Override
cancelAnimation()7816     void cancelAnimation() {
7817         super.cancelAnimation();
7818         clearThumbnail();
7819     }
7820 
clearThumbnail()7821     private void clearThumbnail() {
7822         if (mThumbnail == null) {
7823             return;
7824         }
7825         mThumbnail.destroy();
7826         mThumbnail = null;
7827     }
7828 
getTransit()7829     public @TransitionOldType int getTransit() {
7830         return mTransit;
7831     }
7832 
7833 
registerRemoteAnimations(RemoteAnimationDefinition definition)7834     void registerRemoteAnimations(RemoteAnimationDefinition definition) {
7835         mRemoteAnimationDefinition = definition;
7836         if (definition != null) {
7837             definition.linkToDeath(this::unregisterRemoteAnimations);
7838         }
7839     }
7840 
unregisterRemoteAnimations()7841     void unregisterRemoteAnimations() {
7842         mRemoteAnimationDefinition = null;
7843     }
7844 
7845     @Override
getRemoteAnimationDefinition()7846     RemoteAnimationDefinition getRemoteAnimationDefinition() {
7847         return mRemoteAnimationDefinition;
7848     }
7849 
7850     @Override
applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, Configuration config)7851     void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames,
7852             Configuration config) {
7853         super.applyFixedRotationTransform(info, displayFrames, config);
7854         ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
7855     }
7856 
7857     /**
7858      * Returns the requested {@link Configuration.Orientation} for the current activity.
7859      */
7860     @Configuration.Orientation
7861     @Override
getRequestedConfigurationOrientation(boolean forDisplay)7862     int getRequestedConfigurationOrientation(boolean forDisplay) {
7863         return getRequestedConfigurationOrientation(forDisplay, getOverrideOrientation());
7864     }
7865 
7866     /**
7867      * Returns the requested {@link Configuration.Orientation} for the requested
7868      * {@link ActivityInfo.ScreenOrientation}.
7869      *
7870      * <p>When the current screen orientation is set to {@link SCREEN_ORIENTATION_BEHIND} it returns
7871      * the requested orientation for the activity below which is the first activity with an explicit
7872      * (different from {@link SCREEN_ORIENTATION_UNSET}) orientation which is not {@link
7873      * SCREEN_ORIENTATION_BEHIND}.
7874      */
7875     @Configuration.Orientation
getRequestedConfigurationOrientation(boolean forDisplay, @ActivityInfo.ScreenOrientation int requestedOrientation)7876     int getRequestedConfigurationOrientation(boolean forDisplay,
7877             @ActivityInfo.ScreenOrientation int requestedOrientation) {
7878         if (mLetterboxUiController.hasInheritedOrientation()) {
7879             final RootDisplayArea root = getRootDisplayArea();
7880             if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
7881                 return reverseConfigurationOrientation(
7882                         mLetterboxUiController.getInheritedOrientation());
7883             } else {
7884                 return mLetterboxUiController.getInheritedOrientation();
7885             }
7886         }
7887         if (task != null && requestedOrientation == SCREEN_ORIENTATION_BEHIND) {
7888             // We use Task here because we want to be consistent with what happens in
7889             // multi-window mode where other tasks orientations are ignored.
7890             final ActivityRecord belowCandidate = task.getActivity(
7891                     a -> a.canDefineOrientationForActivitiesAbove() /* callback */,
7892                     this /* boundary */, false /* includeBoundary */,
7893                     true /* traverseTopToBottom */);
7894             if (belowCandidate != null) {
7895                 return belowCandidate.getRequestedConfigurationOrientation(forDisplay);
7896             }
7897         }
7898         return super.getRequestedConfigurationOrientation(forDisplay, requestedOrientation);
7899     }
7900 
7901     /**
7902      * Returns the reversed configuration orientation.
7903      * @hide
7904      */
7905     @Configuration.Orientation
reverseConfigurationOrientation(@onfiguration.Orientation int orientation)7906     public static int reverseConfigurationOrientation(@Configuration.Orientation int orientation) {
7907         switch (orientation) {
7908             case ORIENTATION_LANDSCAPE:
7909                 return ORIENTATION_PORTRAIT;
7910             case ORIENTATION_PORTRAIT:
7911                 return ORIENTATION_LANDSCAPE;
7912             default:
7913                 return orientation;
7914         }
7915     }
7916 
7917     /**
7918      * Whether this activity can be used as an orientation source for activities above with
7919      * {@link SCREEN_ORIENTATION_BEHIND}.
7920      */
canDefineOrientationForActivitiesAbove()7921     boolean canDefineOrientationForActivitiesAbove() {
7922         if (finishing) {
7923             return false;
7924         }
7925         final int overrideOrientation = getOverrideOrientation();
7926         return overrideOrientation != SCREEN_ORIENTATION_UNSET
7927                 && overrideOrientation != SCREEN_ORIENTATION_BEHIND;
7928     }
7929 
7930     @Override
onCancelFixedRotationTransform(int originalDisplayRotation)7931     void onCancelFixedRotationTransform(int originalDisplayRotation) {
7932         if (this != mDisplayContent.getLastOrientationSource()) {
7933             // This activity doesn't affect display rotation.
7934             return;
7935         }
7936         final int requestedOrientation = getRequestedConfigurationOrientation();
7937         if (requestedOrientation != ORIENTATION_UNDEFINED
7938                 && requestedOrientation != mDisplayContent.getConfiguration().orientation) {
7939             // Only need to handle the activity that can be rotated with display or the activity
7940             // has requested the same orientation.
7941             return;
7942         }
7943 
7944         mDisplayContent.mPinnedTaskController.onCancelFixedRotationTransform();
7945         // Perform rotation animation according to the rotation of this activity.
7946         startFreezingScreen(originalDisplayRotation);
7947         // This activity may relaunch or perform configuration change so once it has reported drawn,
7948         // the screen can be unfrozen.
7949         ensureActivityConfiguration(0 /* globalChanges */, !PRESERVE_WINDOWS);
7950         if (mTransitionController.isCollecting(this)) {
7951             // In case the task was changed from PiP but still keeps old transform.
7952             task.resetSurfaceControlTransforms();
7953         }
7954     }
7955 
setRequestedOrientation(@ctivityInfo.ScreenOrientation int requestedOrientation)7956     void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
7957         if (mLetterboxUiController.shouldIgnoreRequestedOrientation(requestedOrientation)) {
7958             return;
7959         }
7960         // This is necessary in order to avoid going into size compat mode when the orientation
7961         // change request comes from the app
7962         if (getRequestedConfigurationOrientation(false, requestedOrientation)
7963                     != getRequestedConfigurationOrientation(false /*forDisplay */)) {
7964             // Do not change the requested configuration now, because this will be done when setting
7965             // the orientation below with the new mCompatDisplayInsets
7966             clearSizeCompatModeAttributes();
7967         }
7968         ProtoLog.v(WM_DEBUG_ORIENTATION,
7969                 "Setting requested orientation %s for %s",
7970                 ActivityInfo.screenOrientationToString(requestedOrientation), this);
7971         setOrientation(requestedOrientation, this);
7972 
7973         // Push the new configuration to the requested app in case where it's not pushed, e.g. when
7974         // the request is handled at task level with letterbox.
7975         if (!getMergedOverrideConfiguration().equals(
7976                 mLastReportedConfiguration.getMergedConfiguration())) {
7977             ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */,
7978                     false /* ignoreVisibility */, true /* isRequestedOrientationChanged */);
7979             if (mTransitionController.inPlayingTransition(this)) {
7980                 mTransitionController.mValidateActivityCompat.add(this);
7981             }
7982         }
7983 
7984         mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
7985                 task.mTaskId, requestedOrientation);
7986 
7987         mDisplayContent.getDisplayRotation().onSetRequestedOrientation();
7988     }
7989 
7990     /*
7991      * Called from {@link RootWindowContainer#ensureVisibilityAndConfig} to make sure the
7992      * orientation is updated before the app becomes visible.
7993      */
reportDescendantOrientationChangeIfNeeded()7994     void reportDescendantOrientationChangeIfNeeded() {
7995         // Orientation request is exposed only when we're visible. Therefore visibility change
7996         // will change requested orientation. Notify upward the hierarchy ladder to adjust
7997         // configuration. This is important to cases where activities with incompatible
7998         // orientations launch, or user goes back from an activity of bi-orientation to an
7999         // activity with specified orientation.
8000         if (onDescendantOrientationChanged(this)) {
8001             // WM Shell can show additional UI elements, e.g. a restart button for size compat mode
8002             // so ensure that WM Shell is called when an activity becomes visible.
8003             task.dispatchTaskInfoChangedIfNeeded(/* force= */ true);
8004         }
8005     }
8006 
8007     /**
8008      * Ignores the activity orientation request if the App is fixed-orientation portrait and has
8009      * ActivityEmbedding enabled and is currently running on large screen display. Or the display
8010      * could be rotated to portrait and not having large enough width for app to split.
8011      */
8012     @VisibleForTesting
shouldIgnoreOrientationRequests()8013     boolean shouldIgnoreOrientationRequests() {
8014         if (!mAppActivityEmbeddingSplitsEnabled
8015                 || !ActivityInfo.isFixedOrientationPortrait(getOverrideOrientation())
8016                 || task.inMultiWindowMode()) {
8017             return false;
8018         }
8019 
8020         return getTask().getConfiguration().smallestScreenWidthDp
8021                 >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
8022     }
8023 
8024     /**
8025      * We override because this class doesn't want its children affecting its reported orientation
8026      * in anyway.
8027      */
8028     @Override
getOrientation(int candidate)8029     int getOrientation(int candidate) {
8030         if (shouldIgnoreOrientationRequests()) {
8031             return SCREEN_ORIENTATION_UNSET;
8032         }
8033 
8034         if (candidate == SCREEN_ORIENTATION_BEHIND) {
8035             // Allow app to specify orientation regardless of its visibility state if the current
8036             // candidate want us to use orientation behind. I.e. the visible app on-top of this one
8037             // wants us to use the orientation of the app behind it.
8038             return getOverrideOrientation();
8039         }
8040 
8041         // The {@link ActivityRecord} should only specify an orientation when it is not closing.
8042         // Allowing closing {@link ActivityRecord} to participate can lead to an Activity in another
8043         // task being started in the wrong orientation during the transition.
8044         if (!getDisplayContent().mClosingApps.contains(this)
8045                 && (isVisibleRequested() || getDisplayContent().mOpeningApps.contains(this))) {
8046             return getOverrideOrientation();
8047         }
8048 
8049         return SCREEN_ORIENTATION_UNSET;
8050     }
8051 
8052     /**
8053      * Returns the app's preferred orientation regardless of its current visibility state taking
8054      * into account orientation per-app overrides applied by the device manufacturers.
8055      */
8056     @Override
getOverrideOrientation()8057     protected int getOverrideOrientation() {
8058         return mLetterboxUiController.overrideOrientationIfNeeded(super.getOverrideOrientation());
8059     }
8060 
8061     /**
8062      * Returns the app's preferred orientation regardless of its currently visibility state. This
8063      * is used to return a requested value to an app if they call {@link
8064      * android.app.Activity#getRequestedOrientation} since {@link #getOverrideOrientation} value
8065      * with override can confuse an app if it's different from what they requested with {@link
8066      * android.app.Activity#setRequestedOrientation}.
8067      */
8068     @ActivityInfo.ScreenOrientation
getRequestedOrientation()8069     int getRequestedOrientation() {
8070         return super.getOverrideOrientation();
8071     }
8072 
8073     /**
8074      * Set the last reported global configuration to the client. Should be called whenever a new
8075      * global configuration is sent to the client for this activity.
8076      */
setLastReportedGlobalConfiguration(@onNull Configuration config)8077     void setLastReportedGlobalConfiguration(@NonNull Configuration config) {
8078         mLastReportedConfiguration.setGlobalConfiguration(config);
8079     }
8080 
8081     /**
8082      * Set the last reported configuration to the client. Should be called whenever
8083      * a new merged configuration is sent to the client for this activity.
8084      */
setLastReportedConfiguration(@onNull MergedConfiguration config)8085     void setLastReportedConfiguration(@NonNull MergedConfiguration config) {
8086         setLastReportedConfiguration(config.getGlobalConfiguration(),
8087             config.getOverrideConfiguration());
8088     }
8089 
setLastReportedConfiguration(Configuration global, Configuration override)8090     private void setLastReportedConfiguration(Configuration global, Configuration override) {
8091         mLastReportedConfiguration.setConfiguration(global, override);
8092     }
8093 
8094     @Nullable
getCompatDisplayInsets()8095     CompatDisplayInsets getCompatDisplayInsets() {
8096         if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
8097             return mLetterboxUiController.getInheritedCompatDisplayInsets();
8098         }
8099         return mCompatDisplayInsets;
8100     }
8101 
8102     /**
8103      * @return The {@code true} if the current instance has {@link mCompatDisplayInsets} without
8104      * considering the inheritance implemented in {@link #getCompatDisplayInsets()}
8105      */
hasCompatDisplayInsetsWithoutInheritance()8106     boolean hasCompatDisplayInsetsWithoutInheritance() {
8107         return mCompatDisplayInsets != null;
8108     }
8109 
8110     /**
8111      * @return {@code true} if this activity is in size compatibility mode that uses the different
8112      *         density than its parent or its bounds don't fit in parent naturally.
8113      */
inSizeCompatMode()8114     boolean inSizeCompatMode() {
8115         if (mInSizeCompatModeForBounds) {
8116             return true;
8117         }
8118         if (getCompatDisplayInsets() == null || !shouldCreateCompatDisplayInsets()
8119                 // The orientation is different from parent when transforming.
8120                 || isFixedRotationTransforming()) {
8121             return false;
8122         }
8123         final Rect appBounds = getConfiguration().windowConfiguration.getAppBounds();
8124         if (appBounds == null) {
8125             // The app bounds hasn't been computed yet.
8126             return false;
8127         }
8128         final WindowContainer parent = getParent();
8129         if (parent == null) {
8130             // The parent of detached Activity can be null.
8131             return false;
8132         }
8133         final Configuration parentConfig = parent.getConfiguration();
8134         // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these
8135         // fields should be changed with density and bounds, so here only compares the most
8136         // significant field.
8137         return parentConfig.densityDpi != getConfiguration().densityDpi;
8138     }
8139 
8140     /**
8141      * Indicates the activity will keep the bounds and screen configuration when it was first
8142      * launched, no matter how its parent changes.
8143      *
8144      * <p>If {@true}, then {@link CompatDisplayInsets} will be created in {@link
8145      * #resolveOverrideConfiguration} to "freeze" activity bounds and insets.
8146      *
8147      * @return {@code true} if this activity is declared as non-resizable and fixed orientation or
8148      *         aspect ratio.
8149      */
shouldCreateCompatDisplayInsets()8150     boolean shouldCreateCompatDisplayInsets() {
8151         switch (supportsSizeChanges()) {
8152             case SIZE_CHANGES_SUPPORTED_METADATA:
8153             case SIZE_CHANGES_SUPPORTED_OVERRIDE:
8154                 return false;
8155             case SIZE_CHANGES_UNSUPPORTED_OVERRIDE:
8156                 return true;
8157             default:
8158                 // Fall through
8159         }
8160         if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) {
8161             final ActivityRecord root = task != null ? task.getRootActivity() : null;
8162             if (root != null && root != this && !root.shouldCreateCompatDisplayInsets()) {
8163                 // If the root activity doesn't use size compatibility mode, the activities above
8164                 // are forced to be the same for consistent visual appearance.
8165                 return false;
8166             }
8167         }
8168         return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio())
8169                 // The configuration of non-standard type should be enforced by system.
8170                 // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is
8171                 // added to a task, but this function is called when resolving the launch params, at
8172                 // which point, the activity type is still undefined if it will be standard.
8173                 // For other non-standard types, the type is set in the constructor, so this should
8174                 // not be a problem.
8175                 && isActivityTypeStandardOrUndefined();
8176     }
8177 
8178     /**
8179      * Returns whether the activity supports size changes.
8180      */
8181     @ActivityInfo.SizeChangesSupportMode
supportsSizeChanges()8182     private int supportsSizeChanges() {
8183         if (mLetterboxUiController.shouldOverrideForceNonResizeApp()) {
8184             return SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
8185         }
8186 
8187         if (info.supportsSizeChanges) {
8188             return SIZE_CHANGES_SUPPORTED_METADATA;
8189         }
8190 
8191         if (mLetterboxUiController.shouldOverrideForceResizeApp()) {
8192             return SIZE_CHANGES_SUPPORTED_OVERRIDE;
8193         }
8194 
8195         return SIZE_CHANGES_UNSUPPORTED_METADATA;
8196     }
8197 
8198     @Override
hasSizeCompatBounds()8199     boolean hasSizeCompatBounds() {
8200         return mSizeCompatBounds != null;
8201     }
8202 
8203     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
updateCompatDisplayInsets()8204     private void updateCompatDisplayInsets() {
8205         if (getCompatDisplayInsets() != null || !shouldCreateCompatDisplayInsets()) {
8206             // The override configuration is set only once in size compatibility mode.
8207             return;
8208         }
8209 
8210         Configuration overrideConfig = getRequestedOverrideConfiguration();
8211         final Configuration fullConfig = getConfiguration();
8212 
8213         // Ensure the screen related fields are set. It is used to prevent activity relaunch
8214         // when moving between displays. For screenWidthDp and screenWidthDp, because they
8215         // are relative to bounds and density, they will be calculated in
8216         // {@link Task#computeConfigResourceOverrides} and the result will also be
8217         // relatively fixed.
8218         overrideConfig.colorMode = fullConfig.colorMode;
8219         overrideConfig.densityDpi = fullConfig.densityDpi;
8220         // The smallest screen width is the short side of screen bounds. Because the bounds
8221         // and density won't be changed, smallestScreenWidthDp is also fixed.
8222         overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
8223         if (ActivityInfo.isFixedOrientation(getOverrideOrientation())) {
8224             // lock rotation too. When in size-compat, onConfigurationChanged will watch for and
8225             // apply runtime rotation changes.
8226             overrideConfig.windowConfiguration.setRotation(
8227                     fullConfig.windowConfiguration.getRotation());
8228         }
8229 
8230         // The role of CompatDisplayInsets is like the override bounds.
8231         mCompatDisplayInsets =
8232                 new CompatDisplayInsets(
8233                         mDisplayContent, this, mLetterboxBoundsForFixedOrientationAndAspectRatio);
8234     }
8235 
clearSizeCompatModeAttributes()8236     private void clearSizeCompatModeAttributes() {
8237         mInSizeCompatModeForBounds = false;
8238         mSizeCompatScale = 1f;
8239         mSizeCompatBounds = null;
8240         mCompatDisplayInsets = null;
8241         mLetterboxUiController.clearInheritedCompatDisplayInsets();
8242     }
8243 
8244     @VisibleForTesting
clearSizeCompatMode()8245     void clearSizeCompatMode() {
8246         final float lastSizeCompatScale = mSizeCompatScale;
8247         clearSizeCompatModeAttributes();
8248         if (mSizeCompatScale != lastSizeCompatScale) {
8249             forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */);
8250         }
8251         // Clear config override in #updateCompatDisplayInsets().
8252         final int activityType = getActivityType();
8253         final Configuration overrideConfig = getRequestedOverrideConfiguration();
8254         overrideConfig.unset();
8255         // Keep the activity type which was set when attaching to a task to prevent leaving it
8256         // undefined.
8257         overrideConfig.windowConfiguration.setActivityType(activityType);
8258         onRequestedOverrideConfigurationChanged(overrideConfig);
8259     }
8260 
8261     @Override
matchParentBounds()8262     public boolean matchParentBounds() {
8263         final Rect overrideBounds = getResolvedOverrideBounds();
8264         if (overrideBounds.isEmpty()) {
8265             return true;
8266         }
8267         // An activity in size compatibility mode may have override bounds which equals to its
8268         // parent bounds, so the exact bounds should also be checked to allow IME window to attach
8269         // to the activity. See {@link DisplayContent#shouldImeAttachedToApp}.
8270         final WindowContainer parent = getParent();
8271         return parent == null || parent.getBounds().equals(overrideBounds);
8272     }
8273 
8274     @Override
getCompatScale()8275     float getCompatScale() {
8276         return hasSizeCompatBounds() ? mSizeCompatScale : super.getCompatScale();
8277     }
8278 
8279     @Override
resolveOverrideConfiguration(Configuration newParentConfiguration)8280     void resolveOverrideConfiguration(Configuration newParentConfiguration) {
8281         final Configuration requestedOverrideConfig = getRequestedOverrideConfiguration();
8282         if (requestedOverrideConfig.assetsSeq != ASSETS_SEQ_UNDEFINED
8283                 && newParentConfiguration.assetsSeq > requestedOverrideConfig.assetsSeq) {
8284             requestedOverrideConfig.assetsSeq = ASSETS_SEQ_UNDEFINED;
8285         }
8286         super.resolveOverrideConfiguration(newParentConfiguration);
8287         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
8288 
8289         applyLocaleOverrideIfNeeded(resolvedConfig);
8290 
8291         if (isFixedRotationTransforming()) {
8292             // The resolved configuration is applied with rotated display configuration. If this
8293             // activity matches its parent (the following resolving procedures are no-op), then it
8294             // can use the resolved configuration directly. Otherwise (e.g. fixed aspect ratio),
8295             // the rotated configuration is used as parent configuration to compute the actual
8296             // resolved configuration. It is like putting the activity in a rotated container.
8297             mTmpConfig.setTo(newParentConfiguration);
8298             mTmpConfig.updateFrom(resolvedConfig);
8299             newParentConfiguration = mTmpConfig;
8300         }
8301 
8302         mIsAspectRatioApplied = false;
8303         mIsEligibleForFixedOrientationLetterbox = false;
8304         mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
8305 
8306         // Can't use resolvedConfig.windowConfiguration.getWindowingMode() because it can be
8307         // different from windowing mode of the task (PiP) during transition from fullscreen to PiP
8308         // and back which can cause visible issues (see b/184078928).
8309         final int parentWindowingMode =
8310                 newParentConfiguration.windowConfiguration.getWindowingMode();
8311         final boolean isFixedOrientationLetterboxAllowed =
8312                 parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
8313                         || parentWindowingMode == WINDOWING_MODE_FULLSCREEN
8314                         // When starting to switch between PiP and fullscreen, the task is pinned
8315                         // and the activity is fullscreen. But only allow to apply letterbox if the
8316                         // activity is exiting PiP because an entered PiP should fill the task.
8317                         || (!mWaitForEnteringPinnedMode
8318                                 && parentWindowingMode == WINDOWING_MODE_PINNED
8319                                 && resolvedConfig.windowConfiguration.getWindowingMode()
8320                                         == WINDOWING_MODE_FULLSCREEN);
8321         // TODO(b/181207944): Consider removing the if condition and always run
8322         // resolveFixedOrientationConfiguration() since this should be applied for all cases.
8323         if (isFixedOrientationLetterboxAllowed) {
8324             resolveFixedOrientationConfiguration(newParentConfiguration);
8325         }
8326         final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets();
8327         if (compatDisplayInsets != null) {
8328             resolveSizeCompatModeConfiguration(newParentConfiguration, compatDisplayInsets);
8329         } else if (inMultiWindowMode() && !isFixedOrientationLetterboxAllowed) {
8330             // We ignore activities' requested orientation in multi-window modes. They may be
8331             // taken into consideration in resolveFixedOrientationConfiguration call above.
8332             resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
8333             // If the activity has requested override bounds, the configuration needs to be
8334             // computed accordingly.
8335             if (!matchParentBounds()) {
8336                 getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
8337                         newParentConfiguration);
8338             }
8339         // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
8340         // are already calculated in resolveFixedOrientationConfiguration.
8341         } else if (!isLetterboxedForFixedOrientationAndAspectRatio()) {
8342             resolveAspectRatioRestriction(newParentConfiguration);
8343         }
8344 
8345         if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null
8346                 // In fullscreen, can be letterboxed for aspect ratio.
8347                 || !inMultiWindowMode()) {
8348             updateResolvedBoundsPosition(newParentConfiguration);
8349         }
8350 
8351         boolean isIgnoreOrientationRequest = mDisplayContent != null
8352                 && mDisplayContent.getIgnoreOrientationRequest();
8353         if (compatDisplayInsets == null
8354                 // for size compat mode set in updateCompatDisplayInsets
8355                 // Fixed orientation letterboxing is possible on both large screen devices
8356                 // with ignoreOrientationRequest enabled and on phones in split screen even with
8357                 // ignoreOrientationRequest disabled.
8358                 && (mLetterboxBoundsForFixedOrientationAndAspectRatio != null
8359                         // Limiting check for aspect ratio letterboxing to devices with enabled
8360                         // ignoreOrientationRequest. This avoids affecting phones where apps may
8361                         // not expect the change of smallestScreenWidthDp after rotation which is
8362                         // possible with this logic. Not having smallestScreenWidthDp completely
8363                         // accurate on phones shouldn't make the big difference and is expected
8364                         // to be already well-tested by apps.
8365                         || (isIgnoreOrientationRequest && mIsAspectRatioApplied))) {
8366             // TODO(b/264034555): Use mDisplayContent to calculate smallestScreenWidthDp from all
8367             // rotations and only re-calculate if parent bounds have non-orientation size change.
8368             resolvedConfig.smallestScreenWidthDp =
8369                     Math.min(resolvedConfig.screenWidthDp, resolvedConfig.screenHeightDp);
8370         }
8371 
8372         // Assign configuration sequence number into hierarchy because there is a different way than
8373         // ensureActivityConfiguration() in this class that uses configuration in WindowState during
8374         // layout traversals.
8375         mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
8376         getResolvedOverrideConfiguration().seq = mConfigurationSeq;
8377 
8378         // Sandbox max bounds by setting it to the activity bounds, if activity is letterboxed, or
8379         // has or will have mCompatDisplayInsets for size compat. Also forces an activity to be
8380         // sandboxed or not depending upon the configuration settings.
8381         if (providesMaxBounds()) {
8382             mTmpBounds.set(resolvedConfig.windowConfiguration.getBounds());
8383             if (mTmpBounds.isEmpty()) {
8384                 // When there is no override bounds, the activity will inherit the bounds from
8385                 // parent.
8386                 mTmpBounds.set(newParentConfiguration.windowConfiguration.getBounds());
8387             }
8388             if (DEBUG_CONFIGURATION) {
8389                 ProtoLog.d(WM_DEBUG_CONFIGURATION, "Sandbox max bounds for uid %s to bounds %s. "
8390                                 + "config to never sandbox = %s, "
8391                                 + "config to always sandbox = %s, "
8392                                 + "letterboxing from mismatch with parent bounds = %s, "
8393                                 + "has mCompatDisplayInsets = %s, "
8394                                 + "should create compatDisplayInsets = %s",
8395                         getUid(),
8396                         mTmpBounds,
8397                         info.neverSandboxDisplayApis(sConstrainDisplayApisConfig),
8398                         info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig),
8399                         !matchParentBounds(),
8400                         compatDisplayInsets != null,
8401                         shouldCreateCompatDisplayInsets());
8402             }
8403             resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
8404         }
8405 
8406         logAppCompatState();
8407     }
8408 
8409     /**
8410      * @return The orientation to use to understand if reachability is enabled.
8411      */
8412     @Configuration.Orientation
getOrientationForReachability()8413     int getOrientationForReachability() {
8414         return mLetterboxUiController.hasInheritedLetterboxBehavior()
8415                 ? mLetterboxUiController.getInheritedOrientation()
8416                 : getRequestedConfigurationOrientation();
8417     }
8418 
8419     /**
8420      * Returns whether activity bounds are letterboxed.
8421      *
8422      * <p>Note that letterbox UI may not be shown even when this returns {@code true}. See {@link
8423      * LetterboxUiController#shouldShowLetterboxUi} for more context.
8424      */
areBoundsLetterboxed()8425     boolean areBoundsLetterboxed() {
8426         return getAppCompatState(/* ignoreVisibility= */ true)
8427                 != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
8428     }
8429 
8430     /**
8431      * Logs the current App Compat state via {@link ActivityMetricsLogger#logAppCompatState}.
8432      */
logAppCompatState()8433     private void logAppCompatState() {
8434         mTaskSupervisor.getActivityMetricsLogger().logAppCompatState(this);
8435     }
8436 
8437     /**
8438      * Returns the current App Compat state of this activity.
8439      *
8440      * <p>The App Compat state indicates whether the activity is visible and letterboxed, and if so
8441      * what is the reason for letterboxing. The state is used for logging the time spent in
8442      * letterbox (sliced by the reason) vs non-letterbox per app.
8443      */
getAppCompatState()8444     int getAppCompatState() {
8445         return getAppCompatState(/* ignoreVisibility= */ false);
8446     }
8447 
8448     /**
8449      * Same as {@link #getAppCompatState()} except when {@code ignoreVisibility} the visibility
8450      * of the activity is ignored.
8451      *
8452      * @param ignoreVisibility whether to ignore the visibility of the activity and not return
8453      *                         NOT_VISIBLE if {@code mVisibleRequested} is false.
8454      */
getAppCompatState(boolean ignoreVisibility)8455     private int getAppCompatState(boolean ignoreVisibility) {
8456         if (!ignoreVisibility && !mVisibleRequested) {
8457             return APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
8458         }
8459         // TODO(b/256564921): Investigate if we need new metrics for translucent activities
8460         if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
8461             return mLetterboxUiController.getInheritedAppCompatState();
8462         }
8463         if (mInSizeCompatModeForBounds) {
8464             return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
8465         }
8466         // Letterbox for fixed orientation. This check returns true only when an activity is
8467         // letterboxed for fixed orientation. Aspect ratio restrictions are also applied if
8468         // present. But this doesn't return true when the activity is letterboxed only because
8469         // of aspect ratio restrictions.
8470         if (isLetterboxedForFixedOrientationAndAspectRatio()) {
8471             return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
8472         }
8473         // Letterbox for limited aspect ratio.
8474         if (mIsAspectRatioApplied) {
8475             return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
8476         }
8477 
8478         return APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
8479     }
8480 
8481     /**
8482      * Adjusts position of resolved bounds if they don't fill the parent using gravity
8483      * requested in the config or via an ADB command. For more context see {@link
8484      * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)} and
8485      * {@link LetterboxUiController#getVerticalPositionMultiplier(Configuration)}
8486      * <p>
8487      * Note that this is the final step that can change the resolved bounds. After this method
8488      * is called, the position of the bounds will be moved to app space as sandboxing if the
8489      * activity has a size compat scale.
8490      */
updateResolvedBoundsPosition(Configuration newParentConfiguration)8491     private void updateResolvedBoundsPosition(Configuration newParentConfiguration) {
8492         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
8493         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
8494         if (resolvedBounds.isEmpty()) {
8495             return;
8496         }
8497         final Rect screenResolvedBounds =
8498                 mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
8499         final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
8500         final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
8501         final float screenResolvedBoundsWidth = screenResolvedBounds.width();
8502         final float parentAppBoundsWidth = parentAppBounds.width();
8503         // Horizontal position
8504         int offsetX = 0;
8505         if (parentBounds.width() != screenResolvedBoundsWidth) {
8506             if (screenResolvedBoundsWidth <= parentAppBoundsWidth) {
8507                 float positionMultiplier = mLetterboxUiController.getHorizontalPositionMultiplier(
8508                         newParentConfiguration);
8509                 offsetX = Math.max(0, (int) Math.ceil((parentAppBoundsWidth
8510                         - screenResolvedBoundsWidth) * positionMultiplier)
8511                         // This is added to make sure that insets added inside
8512                         // CompatDisplayInsets#getContainerBounds() do not break the alignment
8513                         // provided by the positionMultiplier
8514                         - screenResolvedBounds.left + parentAppBounds.left);
8515             }
8516         }
8517 
8518         final float parentAppBoundsHeight = parentAppBounds.height();
8519         final float parentBoundsHeight = parentBounds.height();
8520         final float screenResolvedBoundsHeight = screenResolvedBounds.height();
8521         // Vertical position
8522         int offsetY = 0;
8523         if (parentBoundsHeight != screenResolvedBoundsHeight) {
8524             if (screenResolvedBoundsHeight <= parentAppBoundsHeight) {
8525                 float positionMultiplier = mLetterboxUiController.getVerticalPositionMultiplier(
8526                         newParentConfiguration);
8527                 // If in immersive mode, always align to bottom and overlap bottom insets (nav bar,
8528                 // task bar) as they are transient and hidden. This removes awkward bottom spacing.
8529                 final float newHeight = mDisplayContent.getDisplayPolicy().isImmersiveMode()
8530                         ? parentBoundsHeight : parentAppBoundsHeight;
8531                 offsetY = Math.max(0, (int) Math.ceil((newHeight
8532                         - screenResolvedBoundsHeight) * positionMultiplier)
8533                         // This is added to make sure that insets added inside
8534                         // CompatDisplayInsets#getContainerBounds() do not break the alignment
8535                         // provided by the positionMultiplier
8536                         - screenResolvedBounds.top + parentAppBounds.top);
8537             }
8538         }
8539 
8540         if (mSizeCompatBounds != null) {
8541             mSizeCompatBounds.offset(offsetX , offsetY);
8542             final int dy = mSizeCompatBounds.top - resolvedBounds.top;
8543             final int dx = mSizeCompatBounds.left - resolvedBounds.left;
8544             offsetBounds(resolvedConfig, dx, dy);
8545         } else {
8546             offsetBounds(resolvedConfig, offsetX, offsetY);
8547         }
8548 
8549         // If the top is aligned with parentAppBounds add the vertical insets back so that the app
8550         // content aligns with the status bar
8551         if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top) {
8552             resolvedConfig.windowConfiguration.getBounds().top = parentBounds.top;
8553             if (mSizeCompatBounds != null) {
8554                 mSizeCompatBounds.top = parentBounds.top;
8555             }
8556         }
8557 
8558         // Since bounds has changed, the configuration needs to be computed accordingly.
8559         getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
8560 
8561         // The position of configuration bounds were calculated in screen space because that is
8562         // easier to resolve the relative position in parent container. However, if the activity is
8563         // scaled, the position should follow the scale because the configuration will be sent to
8564         // the client which is expected to be in a scaled environment.
8565         if (mSizeCompatScale != 1f) {
8566             final int screenPosX = resolvedBounds.left;
8567             final int screenPosY = resolvedBounds.top;
8568             final int dx = (int) (screenPosX / mSizeCompatScale + 0.5f) - screenPosX;
8569             final int dy = (int) (screenPosY / mSizeCompatScale + 0.5f) - screenPosY;
8570             offsetBounds(resolvedConfig, dx, dy);
8571         }
8572     }
8573 
getScreenResolvedBounds()8574     @NonNull Rect getScreenResolvedBounds() {
8575         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
8576         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
8577         return mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
8578     }
8579 
recomputeConfiguration()8580     void recomputeConfiguration() {
8581         // We check if the current activity is transparent. In that case we need to
8582         // recomputeConfiguration of the first opaque activity beneath, to allow a
8583         // proper computation of the new bounds.
8584         if (!mLetterboxUiController.applyOnOpaqueActivityBelow(
8585                 ActivityRecord::recomputeConfiguration)) {
8586             onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
8587         }
8588     }
8589 
isInTransition()8590     boolean isInTransition() {
8591         return inTransitionSelfOrParent();
8592     }
8593 
isDisplaySleepingAndSwapping()8594     boolean isDisplaySleepingAndSwapping() {
8595         for (int i = mDisplayContent.mAllSleepTokens.size() - 1; i >= 0; i--) {
8596             RootWindowContainer.SleepToken sleepToken = mDisplayContent.mAllSleepTokens.get(i);
8597             if (sleepToken.isDisplaySwapping()) {
8598                 return true;
8599             }
8600         }
8601         return false;
8602     }
8603 
8604     /**
8605      * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
8606      * orientation then aspect ratio restrictions are also already respected.
8607      *
8608      * <p>This happens when an activity has fixed orientation which doesn't match orientation of the
8609      * parent because a display setting 'ignoreOrientationRequest' is set to true. See {@link
8610      * WindowManagerService#getIgnoreOrientationRequest} for more context.
8611      */
isLetterboxedForFixedOrientationAndAspectRatio()8612     boolean isLetterboxedForFixedOrientationAndAspectRatio() {
8613         return mLetterboxBoundsForFixedOrientationAndAspectRatio != null;
8614     }
8615 
isAspectRatioApplied()8616     boolean isAspectRatioApplied() {
8617         return mIsAspectRatioApplied;
8618     }
8619 
8620     /**
8621      * Whether this activity is eligible for letterbox eduction.
8622      *
8623      * <p>Conditions that need to be met:
8624      *
8625      * <ul>
8626      *     <li>{@link LetterboxConfiguration#getIsEducationEnabled} is true.
8627      *     <li>The activity is eligible for fixed orientation letterbox.
8628      *     <li>The activity is in fullscreen.
8629      *     <li>The activity is portrait-only.
8630      *     <li>The activity doesn't have a starting window (education should only be displayed
8631      *     once the starting window is removed in {@link #removeStartingWindow}).
8632      * </ul>
8633      */
isEligibleForLetterboxEducation()8634     boolean isEligibleForLetterboxEducation() {
8635         return mWmService.mLetterboxConfiguration.getIsEducationEnabled()
8636                 && mIsEligibleForFixedOrientationLetterbox
8637                 && getWindowingMode() == WINDOWING_MODE_FULLSCREEN
8638                 && getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT
8639                 && mStartingWindow == null;
8640     }
8641 
8642     /**
8643      * In some cases, applying insets to bounds changes the orientation. For example, if a
8644      * close-to-square display rotates to portrait to respect a portrait orientation activity, after
8645      * insets such as the status and nav bars are applied, the activity may actually have a
8646      * landscape orientation. This method checks whether the orientations of the activity window
8647      * with and without insets match or if the orientation with insets already matches the
8648      * requested orientation. If not, it may be necessary to letterbox the window.
8649      * @param parentBounds are the new parent bounds passed down to the activity and should be used
8650      *                     to compute the stable bounds.
8651      * @param outStableBounds will store the stable bounds, which are the bounds with insets
8652      *                        applied, if orientation is not respected when insets are applied.
8653      *                        Otherwise outStableBounds will be empty. Stable bounds should be used
8654      *                        to compute letterboxed bounds if orientation is not respected when
8655      *                        insets are applied.
8656      */
orientationRespectedWithInsets(Rect parentBounds, Rect outStableBounds)8657     private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outStableBounds) {
8658         outStableBounds.setEmpty();
8659         if (mDisplayContent == null) {
8660             return true;
8661         }
8662         // Only need to make changes if activity sets an orientation
8663         final int requestedOrientation = getRequestedConfigurationOrientation();
8664         if (requestedOrientation == ORIENTATION_UNDEFINED) {
8665             return true;
8666         }
8667         // Compute parent orientation from bounds
8668         final int orientation = parentBounds.height() >= parentBounds.width()
8669                 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
8670         // Compute orientation from stable parent bounds (= parent bounds with insets applied)
8671         final DisplayInfo di = isFixedRotationTransforming()
8672                 ? getFixedRotationTransformDisplayInfo()
8673                 : mDisplayContent.getDisplayInfo();
8674         final Task task = getTask();
8675         task.calculateInsetFrames(mTmpBounds /* outNonDecorBounds */,
8676                 outStableBounds /* outStableBounds */, parentBounds /* bounds */, di);
8677         final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
8678                 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
8679         // If orientation does not match the orientation with insets applied, then a
8680         // display rotation will not be enough to respect orientation. However, even if they do
8681         // not match but the orientation with insets applied matches the requested orientation, then
8682         // there is no need to modify the bounds because when insets are applied, the activity will
8683         // have the desired orientation.
8684         final boolean orientationRespectedWithInsets = orientation == orientationWithInsets
8685                 || orientationWithInsets == requestedOrientation;
8686         if (orientationRespectedWithInsets) {
8687             outStableBounds.setEmpty();
8688         }
8689         return orientationRespectedWithInsets;
8690     }
8691 
8692     @Override
handlesOrientationChangeFromDescendant(int orientation)8693     boolean handlesOrientationChangeFromDescendant(int orientation) {
8694         if (shouldIgnoreOrientationRequests()) {
8695             return false;
8696         }
8697         return super.handlesOrientationChangeFromDescendant(orientation);
8698     }
8699 
8700     /**
8701      * Computes bounds (letterbox or pillarbox) when either:
8702      * 1. The parent doesn't handle the orientation change and the requested orientation is
8703      *    different from the parent (see {@link DisplayContent#setIgnoreOrientationRequest()}.
8704      * 2. The parent handling the orientation is not enough. This occurs when the display rotation
8705      *    may not be enough to respect orientation requests (see {@link
8706      *    ActivityRecord#orientationRespectedWithInsets}).
8707      *
8708      * <p>If letterboxed due to fixed orientation then aspect ratio restrictions are also applied
8709      * in this method.
8710      */
resolveFixedOrientationConfiguration(@onNull Configuration newParentConfig)8711     private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig) {
8712         final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
8713         final Rect stableBounds = new Rect();
8714         // If orientation is respected when insets are applied, then stableBounds will be empty.
8715         boolean orientationRespectedWithInsets =
8716                 orientationRespectedWithInsets(parentBounds, stableBounds);
8717         if (orientationRespectedWithInsets && handlesOrientationChangeFromDescendant(
8718                 getOverrideOrientation())) {
8719             // No need to letterbox because of fixed orientation. Display will handle
8720             // fixed-orientation requests and a display rotation is enough to respect requested
8721             // orientation with insets applied.
8722             return;
8723         }
8724         // TODO(b/232898850): always respect fixed-orientation request.
8725         // Ignore orientation request for activity in ActivityEmbedding split.
8726         final TaskFragment organizedTf = getOrganizedTaskFragment();
8727         if (organizedTf != null && !organizedTf.fillsParent()) {
8728             return;
8729         }
8730 
8731         final Rect resolvedBounds =
8732                 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
8733         final int parentOrientation = newParentConfig.orientation;
8734 
8735         // If the activity requires a different orientation (either by override or activityInfo),
8736         // make it fit the available bounds by scaling down its bounds.
8737         final int forcedOrientation = getRequestedConfigurationOrientation();
8738 
8739         mIsEligibleForFixedOrientationLetterbox = forcedOrientation != ORIENTATION_UNDEFINED
8740                 && forcedOrientation != parentOrientation;
8741 
8742         if (!mIsEligibleForFixedOrientationLetterbox && (forcedOrientation == ORIENTATION_UNDEFINED
8743                 || orientationRespectedWithInsets)) {
8744             return;
8745         }
8746         final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets();
8747 
8748         if (compatDisplayInsets != null && !compatDisplayInsets.mIsInFixedOrientationLetterbox) {
8749             // App prefers to keep its original size.
8750             // If the size compat is from previous fixed orientation letterboxing, we may want to
8751             // have fixed orientation letterbox again, otherwise it will show the size compat
8752             // restart button even if the restart bounds will be the same.
8753             return;
8754         }
8755 
8756         // TODO(b/182268157): Explore using only one type of parentBoundsWithInsets, either app
8757         // bounds or stable bounds to unify aspect ratio logic.
8758         final Rect parentBoundsWithInsets = orientationRespectedWithInsets
8759                 ? newParentConfig.windowConfiguration.getAppBounds() : stableBounds;
8760         final Rect containingBounds = new Rect();
8761         final Rect containingBoundsWithInsets = new Rect();
8762         // Need to shrink the containing bounds into a square because the parent orientation
8763         // does not match the activity requested orientation.
8764         if (forcedOrientation == ORIENTATION_LANDSCAPE) {
8765             // Landscape is defined as width > height. Make the container respect landscape
8766             // orientation by shrinking height to one less than width. Landscape activity will be
8767             // vertically centered within parent bounds with insets, so position vertical bounds
8768             // within parent bounds with insets to prevent insets from unnecessarily trimming
8769             // vertical bounds.
8770             final int bottom = Math.min(parentBoundsWithInsets.top + parentBounds.width() - 1,
8771                     parentBoundsWithInsets.bottom);
8772             containingBounds.set(parentBounds.left, parentBoundsWithInsets.top, parentBounds.right,
8773                     bottom);
8774             containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
8775                     parentBoundsWithInsets.right, bottom);
8776         } else {
8777             // Portrait is defined as width <= height. Make the container respect portrait
8778             // orientation by shrinking width to match height. Portrait activity will be
8779             // horizontally centered within parent bounds with insets, so position horizontal bounds
8780             // within parent bounds with insets to prevent insets from unnecessarily trimming
8781             // horizontal bounds.
8782             final int right = Math.min(parentBoundsWithInsets.left + parentBounds.height(),
8783                     parentBoundsWithInsets.right);
8784             containingBounds.set(parentBoundsWithInsets.left, parentBounds.top, right,
8785                     parentBounds.bottom);
8786             containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
8787                     right, parentBoundsWithInsets.bottom);
8788         }
8789 
8790         // Store the current bounds to be able to revert to size compat mode values below if needed.
8791         final Rect prevResolvedBounds = new Rect(resolvedBounds);
8792         resolvedBounds.set(containingBounds);
8793 
8794         final float letterboxAspectRatioOverride =
8795                 mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig);
8796 
8797         // Aspect ratio as suggested by the system. Apps requested mix/max aspect ratio will
8798         // be respected in #applyAspectRatio.
8799         final float desiredAspectRatio;
8800         if (isDefaultMultiWindowLetterboxAspectRatioDesired(newParentConfig)) {
8801             desiredAspectRatio = DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
8802         } else if (letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
8803             desiredAspectRatio = letterboxAspectRatioOverride;
8804         } else {
8805             desiredAspectRatio = computeAspectRatio(parentBounds);
8806         }
8807 
8808         // Apply aspect ratio to resolved bounds
8809         mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
8810                 containingBounds, desiredAspectRatio);
8811 
8812         if (compatDisplayInsets != null) {
8813             compatDisplayInsets.getBoundsByRotation(mTmpBounds,
8814                     newParentConfig.windowConfiguration.getRotation());
8815             if (resolvedBounds.width() != mTmpBounds.width()
8816                     || resolvedBounds.height() != mTmpBounds.height()) {
8817                 // The app shouldn't be resized, we only do fixed orientation letterboxing if the
8818                 // compat bounds are also from the same fixed orientation letterbox. Otherwise,
8819                 // clear the fixed orientation bounds to show app in size compat mode.
8820                 resolvedBounds.set(prevResolvedBounds);
8821                 return;
8822             }
8823         }
8824 
8825         // Calculate app bounds using fixed orientation bounds because they will be needed later
8826         // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
8827         getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
8828                 newParentConfig, compatDisplayInsets);
8829         mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
8830     }
8831 
8832     /**
8833      * Returns {@code true} if the default aspect ratio for a letterboxed app in multi-window mode
8834      * should be used.
8835      */
isDefaultMultiWindowLetterboxAspectRatioDesired( @onNull Configuration parentConfig)8836     private boolean isDefaultMultiWindowLetterboxAspectRatioDesired(
8837             @NonNull Configuration parentConfig) {
8838         if (mDisplayContent == null) {
8839             return false;
8840         }
8841         final int windowingMode = parentConfig.windowConfiguration.getWindowingMode();
8842         return WindowConfiguration.inMultiWindowMode(windowingMode)
8843                 && !mDisplayContent.getIgnoreOrientationRequest();
8844     }
8845 
8846     /**
8847      * Resolves aspect ratio restrictions for an activity. If the bounds are restricted by
8848      * aspect ratio, the position will be adjusted later in {@link #updateResolvedBoundsPosition
8849      * within parent's app bounds to balance the visual appearance. The policy of aspect ratio has
8850      * higher priority than the requested override bounds.
8851      */
resolveAspectRatioRestriction(Configuration newParentConfiguration)8852     private void resolveAspectRatioRestriction(Configuration newParentConfiguration) {
8853         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
8854         final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
8855         final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
8856         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
8857         // Use tmp bounds to calculate aspect ratio so we can know whether the activity should use
8858         // restricted size (resolved bounds may be the requested override bounds).
8859         mTmpBounds.setEmpty();
8860         mIsAspectRatioApplied = applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
8861         // If the out bounds is not empty, it means the activity cannot fill parent's app bounds,
8862         // then they should be aligned later in #updateResolvedBoundsPosition()
8863         if (!mTmpBounds.isEmpty()) {
8864             resolvedBounds.set(mTmpBounds);
8865         }
8866         if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
8867             // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
8868             // restrict, the bounds should be the requested override bounds.
8869             getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
8870                     getFixedRotationTransformDisplayInfo());
8871         }
8872     }
8873 
8874     /**
8875      * Resolves consistent screen configuration for orientation and rotation changes without
8876      * inheriting the parent bounds.
8877      */
resolveSizeCompatModeConfiguration(Configuration newParentConfiguration, @NonNull CompatDisplayInsets compatDisplayInsets)8878     private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration,
8879             @NonNull CompatDisplayInsets compatDisplayInsets) {
8880         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
8881         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
8882 
8883         // When an activity needs to be letterboxed because of fixed orientation, use fixed
8884         // orientation bounds (stored in resolved bounds) instead of parent bounds since the
8885         // activity will be displayed within them even if it is in size compat mode. They should be
8886         // saved here before resolved bounds are overridden below.
8887         final Rect containerBounds = isLetterboxedForFixedOrientationAndAspectRatio()
8888                 ? new Rect(resolvedBounds)
8889                 : newParentConfiguration.windowConfiguration.getBounds();
8890         final Rect containerAppBounds = isLetterboxedForFixedOrientationAndAspectRatio()
8891                 ? new Rect(getResolvedOverrideConfiguration().windowConfiguration.getAppBounds())
8892                 : newParentConfiguration.windowConfiguration.getAppBounds();
8893 
8894         final int requestedOrientation = getRequestedConfigurationOrientation();
8895         final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED;
8896         final int orientation = orientationRequested
8897                 ? requestedOrientation
8898                 // We should use the original orientation of the activity when possible to avoid
8899                 // forcing the activity in the opposite orientation.
8900                 : compatDisplayInsets.mOriginalRequestedOrientation != ORIENTATION_UNDEFINED
8901                         ? compatDisplayInsets.mOriginalRequestedOrientation
8902                         : newParentConfiguration.orientation;
8903         int rotation = newParentConfiguration.windowConfiguration.getRotation();
8904         final boolean isFixedToUserRotation = mDisplayContent == null
8905                 || mDisplayContent.getDisplayRotation().isFixedToUserRotation();
8906         if (!isFixedToUserRotation && !compatDisplayInsets.mIsFloating) {
8907             // Use parent rotation because the original display can be rotated.
8908             resolvedConfig.windowConfiguration.setRotation(rotation);
8909         } else {
8910             final int overrideRotation = resolvedConfig.windowConfiguration.getRotation();
8911             if (overrideRotation != ROTATION_UNDEFINED) {
8912                 rotation = overrideRotation;
8913             }
8914         }
8915 
8916         // Use compat insets to lock width and height. We should not use the parent width and height
8917         // because apps in compat mode should have a constant width and height. The compat insets
8918         // are locked when the app is first launched and are never changed after that, so we can
8919         // rely on them to contain the original and unchanging width and height of the app.
8920         final Rect containingAppBounds = new Rect();
8921         final Rect containingBounds = mTmpBounds;
8922         compatDisplayInsets.getContainerBounds(containingAppBounds, containingBounds, rotation,
8923                 orientation, orientationRequested, isFixedToUserRotation);
8924         resolvedBounds.set(containingBounds);
8925         // The size of floating task is fixed (only swap), so the aspect ratio is already correct.
8926         if (!compatDisplayInsets.mIsFloating) {
8927             mIsAspectRatioApplied =
8928                     applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
8929         }
8930 
8931         // Use resolvedBounds to compute other override configurations such as appBounds. The bounds
8932         // are calculated in compat container space. The actual position on screen will be applied
8933         // later, so the calculation is simpler that doesn't need to involve offset from parent.
8934         getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
8935                 compatDisplayInsets);
8936         // Use current screen layout as source because the size of app is independent to parent.
8937         resolvedConfig.screenLayout = computeScreenLayout(
8938                 getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
8939                 resolvedConfig.screenHeightDp);
8940 
8941         // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside
8942         // the parent bounds appropriately.
8943         if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) {
8944             resolvedConfig.orientation = newParentConfiguration.orientation;
8945         }
8946 
8947         // Below figure is an example that puts an activity which was launched in a larger container
8948         // into a smaller container.
8949         //   The outermost rectangle is the real display bounds.
8950         //   "@" is the container app bounds (parent bounds or fixed orientation bounds)
8951         //   "#" is the {@code resolvedBounds} that applies to application.
8952         //   "*" is the {@code mSizeCompatBounds} that used to show on screen if scaled.
8953         // ------------------------------
8954         // |                            |
8955         // |    @@@@*********@@@@###    |
8956         // |    @   *       *   @  #    |
8957         // |    @   *       *   @  #    |
8958         // |    @   *       *   @  #    |
8959         // |    @@@@*********@@@@  #    |
8960         // ---------#--------------#-----
8961         //          #              #
8962         //          ################
8963         // The application is still layouted in "#" since it was launched, and it will be visually
8964         // scaled and positioned to "*".
8965 
8966         final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
8967 
8968         // Calculates the scale the size compatibility bounds into the region which is available
8969         // to application.
8970         final float lastSizeCompatScale = mSizeCompatScale;
8971         updateSizeCompatScale(resolvedAppBounds, containerAppBounds);
8972 
8973         final int containerTopInset = containerAppBounds.top - containerBounds.top;
8974         final boolean topNotAligned =
8975                 containerTopInset != resolvedAppBounds.top - resolvedBounds.top;
8976         if (mSizeCompatScale != 1f || topNotAligned) {
8977             if (mSizeCompatBounds == null) {
8978                 mSizeCompatBounds = new Rect();
8979             }
8980             mSizeCompatBounds.set(resolvedAppBounds);
8981             mSizeCompatBounds.offsetTo(0, 0);
8982             mSizeCompatBounds.scale(mSizeCompatScale);
8983             // The insets are included in height, e.g. the area of real cutout shouldn't be scaled.
8984             mSizeCompatBounds.bottom += containerTopInset;
8985         } else {
8986             mSizeCompatBounds = null;
8987         }
8988         if (mSizeCompatScale != lastSizeCompatScale) {
8989             forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */);
8990         }
8991 
8992         // The position will be later adjusted in updateResolvedBoundsPosition.
8993         // Above coordinates are in "@" space, now place "*" and "#" to screen space.
8994         final boolean fillContainer = resolvedBounds.equals(containingBounds);
8995         final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
8996         final int screenPosY = fillContainer ? containerBounds.top : containerAppBounds.top;
8997 
8998         if (screenPosX != 0 || screenPosY != 0) {
8999             if (mSizeCompatBounds != null) {
9000                 mSizeCompatBounds.offset(screenPosX, screenPosY);
9001             }
9002             // Add the global coordinates and remove the local coordinates.
9003             final int dx = screenPosX - resolvedBounds.left;
9004             final int dy = screenPosY - resolvedBounds.top;
9005             offsetBounds(resolvedConfig, dx, dy);
9006         }
9007 
9008         mInSizeCompatModeForBounds =
9009                 isInSizeCompatModeForBounds(resolvedAppBounds, containerAppBounds);
9010     }
9011 
updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds)9012     void updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds) {
9013         // Only allow to scale down.
9014         mSizeCompatScale = mLetterboxUiController.findOpaqueNotFinishingActivityBelow()
9015                 .map(activityRecord -> activityRecord.mSizeCompatScale)
9016                 .orElseGet(() -> {
9017                     final int contentW = resolvedAppBounds.width();
9018                     final int contentH = resolvedAppBounds.height();
9019                     final int viewportW = containerAppBounds.width();
9020                     final int viewportH = containerAppBounds.height();
9021                     return (contentW <= viewportW && contentH <= viewportH) ? 1f : Math.min(
9022                             (float) viewportW / contentW, (float) viewportH / contentH);
9023                 });
9024     }
9025 
isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds)9026     private boolean isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds) {
9027         if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
9028             // To avoid wrong app behaviour, we decided to disable SCM when a translucent activity
9029             // is letterboxed.
9030             return false;
9031         }
9032         final int appWidth = appBounds.width();
9033         final int appHeight = appBounds.height();
9034         final int containerAppWidth = containerBounds.width();
9035         final int containerAppHeight = containerBounds.height();
9036 
9037         if (containerAppWidth == appWidth && containerAppHeight == appHeight) {
9038             // Matched the container bounds.
9039             return false;
9040         }
9041         if (containerAppWidth > appWidth && containerAppHeight > appHeight) {
9042             // Both sides are smaller than the container.
9043             return true;
9044         }
9045         if (containerAppWidth < appWidth || containerAppHeight < appHeight) {
9046             // One side is larger than the container.
9047             return true;
9048         }
9049 
9050         // The rest of the condition is that only one side is smaller than the container, but it
9051         // still needs to exclude the cases where the size is limited by the fixed aspect ratio.
9052         final float maxAspectRatio = getMaxAspectRatio();
9053         if (maxAspectRatio > 0) {
9054             final float aspectRatio = (0.5f + Math.max(appWidth, appHeight))
9055                     / Math.min(appWidth, appHeight);
9056             if (aspectRatio >= maxAspectRatio) {
9057                 // The current size has reached the max aspect ratio.
9058                 return false;
9059             }
9060         }
9061         final float minAspectRatio = getMinAspectRatio();
9062         if (minAspectRatio > 0) {
9063             // The activity should have at least the min aspect ratio, so this checks if the
9064             // container still has available space to provide larger aspect ratio.
9065             final float containerAspectRatio =
9066                     (0.5f + Math.max(containerAppWidth, containerAppHeight))
9067                             / Math.min(containerAppWidth, containerAppHeight);
9068             if (containerAspectRatio <= minAspectRatio) {
9069                 // The long side has reached the parent.
9070                 return false;
9071             }
9072         }
9073         return true;
9074     }
9075 
9076     /** @return The horizontal / vertical offset of putting the content in the center of viewport.*/
getCenterOffset(int viewportDim, int contentDim)9077     private static int getCenterOffset(int viewportDim, int contentDim) {
9078         return (int) ((viewportDim - contentDim + 1) * 0.5f);
9079     }
9080 
offsetBounds(Configuration inOutConfig, int offsetX, int offsetY)9081     private static void offsetBounds(Configuration inOutConfig, int offsetX, int offsetY) {
9082         inOutConfig.windowConfiguration.getBounds().offset(offsetX, offsetY);
9083         inOutConfig.windowConfiguration.getAppBounds().offset(offsetX, offsetY);
9084     }
9085 
9086     @Override
getBounds()9087     public Rect getBounds() {
9088         // TODO(b/268458693): Refactor configuration inheritance in case of translucent activities
9089         final Rect superBounds = super.getBounds();
9090         return mLetterboxUiController.findOpaqueNotFinishingActivityBelow()
9091                 .map(ActivityRecord::getBounds)
9092                 .orElseGet(() -> {
9093                     if (mSizeCompatBounds != null) {
9094                         return mSizeCompatBounds;
9095                     }
9096                     return superBounds;
9097                 });
9098     }
9099 
9100     @Override
9101     public boolean providesMaxBounds() {
9102         // System should always be able to access the DisplayArea bounds, so do not provide it with
9103         // compat max window bounds.
9104         if (getUid() == SYSTEM_UID) {
9105             return false;
9106         }
9107         // Do not sandbox to activity window bounds if the feature is disabled.
9108         if (mDisplayContent != null && !mDisplayContent.sandboxDisplayApis()) {
9109             return false;
9110         }
9111         // Never apply sandboxing to an app that should be explicitly excluded from the config.
9112         if (info.neverSandboxDisplayApis(sConstrainDisplayApisConfig)) {
9113             return false;
9114         }
9115         // Always apply sandboxing to an app that should be explicitly included from the config.
9116         if (info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig)) {
9117             return true;
9118         }
9119         // Max bounds should be sandboxed when an activity should have compatDisplayInsets, and it
9120         // will keep the same bounds and screen configuration when it was first launched regardless
9121         // how its parent window changes, so that the sandbox API will provide a consistent result.
9122         if (getCompatDisplayInsets() != null || shouldCreateCompatDisplayInsets()) {
9123             return true;
9124         }
9125 
9126         // No need to sandbox for resizable apps in (including in multi-window) because
9127         // resizableActivity=true indicates that they support multi-window. Likewise, do not sandbox
9128         // for activities in letterbox since the activity has declared it can handle resizing.
9129         return false;
9130     }
9131 
9132     @VisibleForTesting
9133     @Override
9134     Rect getAnimationBounds(int appRootTaskClipMode) {
9135         // Use TaskFragment-bounds if available so that activity-level letterbox (maxAspectRatio) is
9136         // included in the animation.
9137         final TaskFragment taskFragment = getTaskFragment();
9138         return taskFragment != null ? taskFragment.getBounds() : getBounds();
9139     }
9140 
9141     @Override
9142     void getAnimationPosition(Point outPosition) {
9143         // Always animate from zero because if the activity doesn't fill the task, the letterbox
9144         // will fill the remaining area that should be included in the animation.
9145         outPosition.set(0, 0);
9146     }
9147 
9148     @Override
9149     public void onConfigurationChanged(Configuration newParentConfig) {
9150         // We want to collect the ActivityRecord if the windowing mode is changed, so that it will
9151         // dispatch app transition finished event correctly at the end.
9152         // Check #isVisible() because we don't want to animate for activity that stays invisible.
9153         // Activity with #isVisibleRequested() changed should be collected when that is requested.
9154         if (mTransitionController.isShellTransitionsEnabled() && isVisible()
9155                 && isVisibleRequested()) {
9156             final int projectedWindowingMode =
9157                     getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED
9158                             ? newParentConfig.windowConfiguration.getWindowingMode()
9159                             : getRequestedOverrideWindowingMode();
9160             if (getWindowingMode() != projectedWindowingMode) {
9161                 mTransitionController.collect(this);
9162             }
9163         }
9164         if (getCompatDisplayInsets() != null) {
9165             Configuration overrideConfig = getRequestedOverrideConfiguration();
9166             // Adapt to changes in orientation locking. The app is still non-resizable, but
9167             // it can change which orientation is fixed. If the fixed orientation changes,
9168             // update the rotation used on the "compat" display
9169             boolean wasFixedOrient =
9170                     overrideConfig.windowConfiguration.getRotation() != ROTATION_UNDEFINED;
9171             int requestedOrient = getRequestedConfigurationOrientation();
9172             if (requestedOrient != ORIENTATION_UNDEFINED
9173                     && requestedOrient != getConfiguration().orientation
9174                     // The task orientation depends on the top activity orientation, so it
9175                     // should match. If it doesn't, just wait until it does.
9176                     && requestedOrient == getParent().getConfiguration().orientation
9177                     && (overrideConfig.windowConfiguration.getRotation()
9178                             != getParent().getWindowConfiguration().getRotation())) {
9179                 overrideConfig.windowConfiguration.setRotation(
9180                         getParent().getWindowConfiguration().getRotation());
9181                 onRequestedOverrideConfigurationChanged(overrideConfig);
9182                 return;
9183             } else if (wasFixedOrient && requestedOrient == ORIENTATION_UNDEFINED
9184                     && (overrideConfig.windowConfiguration.getRotation()
9185                             != ROTATION_UNDEFINED)) {
9186                 overrideConfig.windowConfiguration.setRotation(ROTATION_UNDEFINED);
9187                 onRequestedOverrideConfigurationChanged(overrideConfig);
9188                 return;
9189             }
9190         }
9191 
9192         final boolean wasInPictureInPicture = inPinnedWindowingMode();
9193         final DisplayContent display = mDisplayContent;
9194         final int activityType = getActivityType();
9195         if (wasInPictureInPicture && attachedToProcess() && display != null) {
9196             // If the PIP activity is changing to fullscreen with display orientation change, the
9197             // fixed rotation will take effect that requires to send fixed rotation adjustments
9198             // before the process configuration (if the process is a configuration listener of the
9199             // activity). So when performing process configuration on client side, it can apply
9200             // the adjustments (see WindowToken#onFixedRotationStatePrepared).
9201             try {
9202                 app.pauseConfigurationDispatch();
9203                 super.onConfigurationChanged(newParentConfig);
9204                 if (mVisibleRequested && !inMultiWindowMode()) {
9205                     final int rotation = display.rotationForActivityInDifferentOrientation(this);
9206                     if (rotation != ROTATION_UNDEFINED) {
9207                         app.resumeConfigurationDispatch();
9208                         display.setFixedRotationLaunchingApp(this, rotation);
9209                     }
9210                 }
9211             } finally {
9212                 if (app.resumeConfigurationDispatch()) {
9213                     app.dispatchConfiguration(app.getConfiguration());
9214                 }
9215             }
9216         } else {
9217             super.onConfigurationChanged(newParentConfig);
9218         }
9219         if (activityType != ACTIVITY_TYPE_UNDEFINED
9220                 && activityType != getActivityType()) {
9221             final String errorMessage = "Can't change activity type once set: " + this
9222                     + " activityType=" + activityTypeToString(getActivityType()) + ", was "
9223                     + activityTypeToString(activityType);
9224             if (Build.IS_DEBUGGABLE) {
9225                 throw new IllegalStateException(errorMessage);
9226             }
9227             Slog.w(TAG, errorMessage);
9228         }
9229 
9230         // Configuration's equality doesn't consider seq so if only seq number changes in resolved
9231         // override configuration. Therefore ConfigurationContainer doesn't change merged override
9232         // configuration, but it's used to push configuration changes so explicitly update that.
9233         if (getMergedOverrideConfiguration().seq != getResolvedOverrideConfiguration().seq) {
9234             onMergedOverrideConfigurationChanged();
9235         }
9236 
9237         // Before PiP animation is done, th windowing mode of the activity is still the previous
9238         // mode (see RootWindowContainer#moveActivityToPinnedRootTask). So once the windowing mode
9239         // of activity is changed, it is the signal of the last step to update the PiP states.
9240         if (!wasInPictureInPicture && inPinnedWindowingMode() && task != null) {
9241             mWaitForEnteringPinnedMode = false;
9242             mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, task.getBounds());
9243         }
9244 
9245         if (display == null) {
9246             return;
9247         }
9248         if (mVisibleRequested) {
9249             // It may toggle the UI for user to restart the size compatibility mode activity.
9250             display.handleActivitySizeCompatModeIfNeeded(this);
9251         } else if (getCompatDisplayInsets() != null && !visibleIgnoringKeyguard
9252                 && (app == null || !app.hasVisibleActivities())) {
9253             // visibleIgnoringKeyguard is checked to avoid clearing mCompatDisplayInsets during
9254             // displays change. Displays are turned off during the change so mVisibleRequested
9255             // can be false.
9256             // The override changes can only be obtained from display, because we don't have the
9257             // difference of full configuration in each hierarchy.
9258             final int displayChanges = display.getCurrentOverrideConfigurationChanges();
9259             final int orientationChanges = CONFIG_WINDOW_CONFIGURATION
9260                     | CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION;
9261             final boolean hasNonOrienSizeChanged = hasResizeChange(displayChanges)
9262                     // Filter out the case of simple orientation change.
9263                     && (displayChanges & orientationChanges) != orientationChanges;
9264             // For background activity that uses size compatibility mode, if the size or density of
9265             // the display is changed, then reset the override configuration and kill the activity's
9266             // process if its process state is not important to user.
9267             if (hasNonOrienSizeChanged || (displayChanges & ActivityInfo.CONFIG_DENSITY) != 0) {
9268                 restartProcessIfVisible();
9269             }
9270         }
9271     }
9272 
9273     private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
9274             Rect containingBounds) {
9275         return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
9276                 0 /* desiredAspectRatio */);
9277     }
9278 
9279     /**
9280      * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
9281      * made to outBounds.
9282      *
9283      * @return {@code true} if aspect ratio restrictions were applied.
9284      */
9285     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
9286     private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
9287             Rect containingBounds, float desiredAspectRatio) {
9288         final float maxAspectRatio = getMaxAspectRatio();
9289         final Task rootTask = getRootTask();
9290         final float minAspectRatio = getMinAspectRatio();
9291         final TaskFragment organizedTf = getOrganizedTaskFragment();
9292         if (task == null || rootTask == null
9293                 || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1)
9294                 // Don't set aspect ratio if we are in VR mode.
9295                 || isInVrUiMode(getConfiguration())
9296                 // TODO(b/232898850): Always respect aspect ratio requests.
9297                 // Don't set aspect ratio for activity in ActivityEmbedding split.
9298                 || (organizedTf != null && !organizedTf.fillsParent())) {
9299             return false;
9300         }
9301 
9302         final int containingAppWidth = containingAppBounds.width();
9303         final int containingAppHeight = containingAppBounds.height();
9304         final float containingRatio = computeAspectRatio(containingAppBounds);
9305 
9306         if (desiredAspectRatio < 1) {
9307             desiredAspectRatio = containingRatio;
9308         }
9309 
9310         if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) {
9311             desiredAspectRatio = maxAspectRatio;
9312         } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) {
9313             desiredAspectRatio = minAspectRatio;
9314         }
9315 
9316         int activityWidth = containingAppWidth;
9317         int activityHeight = containingAppHeight;
9318 
9319         if (containingRatio - desiredAspectRatio > ASPECT_RATIO_ROUNDING_TOLERANCE) {
9320             if (containingAppWidth < containingAppHeight) {
9321                 // Width is the shorter side, so we use that to figure-out what the max. height
9322                 // should be given the aspect ratio.
9323                 activityHeight = (int) ((activityWidth * desiredAspectRatio) + 0.5f);
9324             } else {
9325                 // Height is the shorter side, so we use that to figure-out what the max. width
9326                 // should be given the aspect ratio.
9327                 activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f);
9328             }
9329         } else if (desiredAspectRatio - containingRatio > ASPECT_RATIO_ROUNDING_TOLERANCE) {
9330             boolean adjustWidth;
9331             switch (getRequestedConfigurationOrientation()) {
9332                 case ORIENTATION_LANDSCAPE:
9333                     // Width should be the longer side for this landscape app, so we use the width
9334                     // to figure-out what the max. height should be given the aspect ratio.
9335                     adjustWidth = false;
9336                     break;
9337                 case ORIENTATION_PORTRAIT:
9338                     // Height should be the longer side for this portrait app, so we use the height
9339                     // to figure-out what the max. width should be given the aspect ratio.
9340                     adjustWidth = true;
9341                     break;
9342                 default:
9343                     // This app doesn't have a preferred orientation, so we keep the length of the
9344                     // longer side, and use it to figure-out the length of the shorter side.
9345                     if (containingAppWidth < containingAppHeight) {
9346                         // Width is the shorter side, so we use the height to figure-out what the
9347                         // max. width should be given the aspect ratio.
9348                         adjustWidth = true;
9349                     } else {
9350                         // Height is the shorter side, so we use the width to figure-out what the
9351                         // max. height should be given the aspect ratio.
9352                         adjustWidth = false;
9353                     }
9354                     break;
9355             }
9356             if (adjustWidth) {
9357                 activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f);
9358             } else {
9359                 activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f);
9360             }
9361         }
9362 
9363         if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) {
9364             // The display matches or is less than the activity aspect ratio, so nothing else to do.
9365             return false;
9366         }
9367 
9368         // Compute configuration based on max or min supported width and height.
9369         // Also account for the insets (e.g. display cutouts, navigation bar), which will be
9370         // clipped away later in {@link Task#computeConfigResourceOverrides()}, i.e., the out
9371         // bounds are the app bounds restricted by aspect ratio + clippable insets. Otherwise,
9372         // the app bounds would end up too small. To achieve this we will also add clippable insets
9373         // when the corresponding dimension fully fills the parent
9374 
9375         int right = activityWidth + containingAppBounds.left;
9376         int left = containingAppBounds.left;
9377         if (right >= containingAppBounds.right) {
9378             right = containingBounds.right;
9379             left = containingBounds.left;
9380         }
9381         int bottom = activityHeight + containingAppBounds.top;
9382         int top = containingAppBounds.top;
9383         if (bottom >= containingAppBounds.bottom) {
9384             bottom = containingBounds.bottom;
9385             top = containingBounds.top;
9386         }
9387         outBounds.set(left, top, right, bottom);
9388         return true;
9389     }
9390 
9391     /**
9392      * Returns the min aspect ratio of this activity.
9393      */
9394     float getMinAspectRatio() {
9395         if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
9396             return mLetterboxUiController.getInheritedMinAspectRatio();
9397         }
9398         if (info.applicationInfo == null) {
9399             return info.getMinAspectRatio();
9400         }
9401         if (mLetterboxUiController.shouldApplyUserMinAspectRatioOverride()) {
9402             return mLetterboxUiController.getUserMinAspectRatio();
9403         }
9404         if (!mLetterboxUiController.shouldOverrideMinAspectRatio()) {
9405             return info.getMinAspectRatio();
9406         }
9407 
9408         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
9409                 && !ActivityInfo.isFixedOrientationPortrait(
9410                         getOverrideOrientation())) {
9411             return info.getMinAspectRatio();
9412         }
9413 
9414         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN)
9415                 && isParentFullscreenPortrait()) {
9416             // We are using the parent configuration here as this is the most recent one that gets
9417             // passed to onConfigurationChanged when a relevant change takes place
9418             return info.getMinAspectRatio();
9419         }
9420 
9421         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN)) {
9422             return Math.max(mLetterboxUiController.getSplitScreenAspectRatio(),
9423                     info.getMinAspectRatio());
9424         }
9425 
9426         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) {
9427             return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
9428                     info.getMinAspectRatio());
9429         }
9430 
9431         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) {
9432             return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE,
9433                     info.getMinAspectRatio());
9434         }
9435         return info.getMinAspectRatio();
9436     }
9437 
9438     private boolean isParentFullscreenPortrait() {
9439         final WindowContainer parent = getParent();
9440         return parent != null
9441                 && parent.getConfiguration().orientation == ORIENTATION_PORTRAIT
9442                 && parent.getWindowConfiguration().getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
9443     }
9444 
9445     float getMaxAspectRatio() {
9446         if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
9447             return mLetterboxUiController.getInheritedMaxAspectRatio();
9448         }
9449         return info.getMaxAspectRatio();
9450     }
9451 
9452     /**
9453      * Returns true if the activity has maximum or minimum aspect ratio.
9454      */
9455     private boolean hasFixedAspectRatio() {
9456         return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0;
9457     }
9458 
9459     /**
9460      * Returns the aspect ratio of the given {@code rect}.
9461      */
9462     static float computeAspectRatio(Rect rect) {
9463         final int width = rect.width();
9464         final int height = rect.height();
9465         if (width == 0 || height == 0) {
9466             return 0;
9467         }
9468         return Math.max(width, height) / (float) Math.min(width, height);
9469     }
9470 
9471     /**
9472      * @return {@code true} if this activity was reparented to another display but
9473      *         {@link #ensureActivityConfiguration} is not called.
9474      */
9475     boolean shouldUpdateConfigForDisplayChanged() {
9476         return mLastReportedDisplayId != getDisplayId();
9477     }
9478 
9479     boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) {
9480         return ensureActivityConfiguration(globalChanges, preserveWindow,
9481                 false /* ignoreVisibility */, false /* isRequestedOrientationChanged */);
9482     }
9483 
9484     boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
9485             boolean ignoreVisibility) {
9486         return ensureActivityConfiguration(globalChanges, preserveWindow, ignoreVisibility,
9487                 false /* isRequestedOrientationChanged */);
9488     }
9489 
9490     /**
9491      * Make sure the given activity matches the current configuration. Ensures the HistoryRecord
9492      * is updated with the correct configuration and all other bookkeeping is handled.
9493      *
9494      * @param globalChanges The changes to the global configuration.
9495      * @param preserveWindow If the activity window should be preserved on screen if the activity
9496      *                       is relaunched.
9497      * @param ignoreVisibility If we should try to relaunch the activity even if it is invisible
9498      *                         (stopped state). This is useful for the case where we know the
9499      *                         activity will be visible soon and we want to ensure its configuration
9500      *                         before we make it visible.
9501      * @param isRequestedOrientationChanged whether this is triggered in response to an app calling
9502      *                                      {@link android.app.Activity#setRequestedOrientation}.
9503      * @return False if the activity was relaunched and true if it wasn't relaunched because we
9504      *         can't or the app handles the specific configuration that is changing.
9505      */
9506     boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
9507             boolean ignoreVisibility, boolean isRequestedOrientationChanged) {
9508         final Task rootTask = getRootTask();
9509         if (rootTask.mConfigWillChange) {
9510             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
9511                     + "(will change): %s", this);
9512             return true;
9513         }
9514 
9515         // We don't worry about activities that are finishing.
9516         if (finishing) {
9517             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter "
9518                     + "in finishing %s", this);
9519             stopFreezingScreenLocked(false);
9520             return true;
9521         }
9522 
9523         if (isState(DESTROYED)) {
9524             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
9525                     + "in destroyed state %s", this);
9526             return true;
9527         }
9528 
9529         if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
9530             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
9531                     + "invisible: %s", this);
9532             return true;
9533         }
9534 
9535         ProtoLog.v(WM_DEBUG_CONFIGURATION, "Ensuring correct "
9536                 + "configuration: %s", this);
9537 
9538         final int newDisplayId = getDisplayId();
9539         final boolean displayChanged = mLastReportedDisplayId != newDisplayId;
9540         if (displayChanged) {
9541             mLastReportedDisplayId = newDisplayId;
9542         }
9543 
9544         // Calling from here rather than from onConfigurationChanged because it's possible that
9545         // onConfigurationChanged was called before mVisibleRequested became true and
9546         // mCompatDisplayInsets may not be called again when mVisibleRequested changes. And we
9547         // don't want to save mCompatDisplayInsets in onConfigurationChanged without visibility
9548         // check to avoid remembering obsolete configuration which can lead to unnecessary
9549         // size-compat mode.
9550         if (mVisibleRequested) {
9551             // Calling from here rather than resolveOverrideConfiguration to ensure that this is
9552             // called after full config is updated in ConfigurationContainer#onConfigurationChanged.
9553             updateCompatDisplayInsets();
9554         }
9555 
9556         // Short circuit: if the two full configurations are equal (the common case), then there is
9557         // nothing to do.  We test the full configuration instead of the global and merged override
9558         // configurations because there are cases (like moving a task to the root pinned task) where
9559         // the combine configurations are equal, but would otherwise differ in the override config
9560         mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration());
9561         if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) {
9562             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display "
9563                     + "unchanged in %s", this);
9564             return true;
9565         }
9566 
9567         // Okay we now are going to make this activity have the new config.
9568         // But then we need to figure out how it needs to deal with that.
9569 
9570         // Find changes between last reported merged configuration and the current one. This is used
9571         // to decide whether to relaunch an activity or just report a configuration change.
9572         final int changes = getConfigurationChanges(mTmpConfig);
9573 
9574         // Update last reported values.
9575         final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
9576 
9577         setLastReportedConfiguration(getProcessGlobalConfiguration(), newMergedOverrideConfig);
9578 
9579         if (mState == INITIALIZING) {
9580             // No need to relaunch or schedule new config for activity that hasn't been launched
9581             // yet. We do, however, return after applying the config to activity record, so that
9582             // it will use it for launch transaction.
9583             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check for "
9584                     + "initializing activity: %s", this);
9585             return true;
9586         }
9587 
9588         if (changes == 0 && !forceNewConfig) {
9589             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration no differences in %s",
9590                     this);
9591             // There are no significant differences, so we won't relaunch but should still deliver
9592             // the new configuration to the client process.
9593             if (displayChanged) {
9594                 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
9595             } else {
9596                 scheduleConfigurationChanged(newMergedOverrideConfig);
9597             }
9598             notifyDisplayCompatPolicyAboutConfigurationChange(
9599                     mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig);
9600             return true;
9601         }
9602 
9603         ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration changes for %s, "
9604                 + "allChanges=%s", this, Configuration.configurationDiffToString(changes));
9605 
9606         // If the activity isn't currently running, just leave the new configuration and it will
9607         // pick that up next time it starts.
9608         if (!attachedToProcess()) {
9609             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter not running %s", this);
9610             stopFreezingScreenLocked(false);
9611             forceNewConfig = false;
9612             return true;
9613         }
9614 
9615         // Figure out how to handle the changes between the configurations.
9616         ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=0x%s, "
9617                 + "handles=0x%s, mLastReportedConfiguration=%s", info.name,
9618                 Integer.toHexString(changes), Integer.toHexString(info.getRealConfigChanged()),
9619                 mLastReportedConfiguration);
9620 
9621         if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
9622             // Aha, the activity isn't handling the change, so DIE DIE DIE.
9623             configChangeFlags |= changes;
9624             startFreezingScreenLocked(globalChanges);
9625             forceNewConfig = false;
9626             // Do not preserve window if it is freezing screen because the original window won't be
9627             // able to update drawn state that causes freeze timeout.
9628             preserveWindow &= isResizeOnlyChange(changes) && !mFreezingScreen;
9629             final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
9630             if (hasResizeChange) {
9631                 final boolean isDragResizing = task.isDragResizing();
9632                 mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE
9633                         : RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
9634             } else {
9635                 mRelaunchReason = RELAUNCH_REASON_NONE;
9636             }
9637             if (isRequestedOrientationChanged) {
9638                 mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(true);
9639             }
9640             if (mState == PAUSING) {
9641                 // A little annoying: we are waiting for this activity to finish pausing. Let's not
9642                 // do anything now, but just flag that it needs to be restarted when done pausing.
9643                 ProtoLog.v(WM_DEBUG_CONFIGURATION,
9644                         "Config is skipping already pausing %s", this);
9645                 deferRelaunchUntilPaused = true;
9646                 preserveWindowOnDeferredRelaunch = preserveWindow;
9647                 return true;
9648             } else {
9649                 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s",
9650                         this);
9651                 if (!mVisibleRequested) {
9652                     ProtoLog.v(WM_DEBUG_STATES, "Config is relaunching invisible "
9653                             + "activity %s called by %s", this, Debug.getCallers(4));
9654                 }
9655                 relaunchActivityLocked(preserveWindow);
9656             }
9657 
9658             // All done...  tell the caller we weren't able to keep this activity around.
9659             return false;
9660         }
9661 
9662         // Default case: the activity can handle this new configuration, so hand it over.
9663         // NOTE: We only forward the override configuration as the system level configuration
9664         // changes is always sent to all processes when they happen so it can just use whatever
9665         // system level configuration it last got.
9666         if (displayChanged) {
9667             scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
9668         } else {
9669             scheduleConfigurationChanged(newMergedOverrideConfig);
9670         }
9671         notifyDisplayCompatPolicyAboutConfigurationChange(
9672                 mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig);
9673 
9674         stopFreezingScreenLocked(false);
9675 
9676         return true;
9677     }
9678 
9679     private void notifyDisplayCompatPolicyAboutConfigurationChange(
9680             Configuration newConfig, Configuration lastReportedConfig) {
9681         if (mDisplayContent.mDisplayRotationCompatPolicy == null
9682                 || !shouldBeResumed(/* activeActivity */ null)) {
9683             return;
9684         }
9685         mDisplayContent.mDisplayRotationCompatPolicy.onActivityConfigurationChanging(
9686                 this, newConfig, lastReportedConfig);
9687     }
9688 
9689     /** Get process configuration, or global config if the process is not set. */
9690     private Configuration getProcessGlobalConfiguration() {
9691         return app != null ? app.getConfiguration() : mAtmService.getGlobalConfiguration();
9692     }
9693 
9694     /**
9695      * When assessing a configuration change, decide if the changes flags and the new configurations
9696      * should cause the Activity to relaunch.
9697      *
9698      * @param changes the changes due to the given configuration.
9699      * @param changesConfig the configuration that was used to calculate the given changes via a
9700      *        call to getConfigurationChanges.
9701      */
9702     private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {
9703         int configChanged = info.getRealConfigChanged();
9704         boolean onlyVrUiModeChanged = onlyVrUiModeChanged(changes, changesConfig);
9705 
9706         // Override for apps targeting pre-O sdks
9707         // If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode
9708         // to the config change.
9709         // For O and later, apps will be required to add configChanges="uimode" to their manifest.
9710         if (info.applicationInfo.targetSdkVersion < O
9711                 && requestedVrComponent != null
9712                 && onlyVrUiModeChanged) {
9713             configChanged |= CONFIG_UI_MODE;
9714         }
9715 
9716         // TODO(b/274944389): remove workaround after long-term solution is implemented
9717         // Don't restart due to desk mode change if the app does not have desk resources.
9718         if (mWmService.mSkipActivityRelaunchWhenDocking && onlyDeskInUiModeChanged(changesConfig)
9719                 && !hasDeskResources()) {
9720             configChanged |= CONFIG_UI_MODE;
9721         }
9722 
9723         return (changes & (~configChanged)) != 0;
9724     }
9725 
9726     /**
9727      * Returns true if the configuration change is solely due to the UI mode switching into or out
9728      * of UI_MODE_TYPE_VR_HEADSET.
9729      */
9730     private boolean onlyVrUiModeChanged(int changes, Configuration lastReportedConfig) {
9731         final Configuration currentConfig = getConfiguration();
9732         return changes == CONFIG_UI_MODE && (isInVrUiMode(currentConfig)
9733             != isInVrUiMode(lastReportedConfig));
9734     }
9735 
9736     /**
9737      * Returns true if the uiMode configuration changed, and desk mode
9738      * ({@link android.content.res.Configuration#UI_MODE_TYPE_DESK}) was the only change to uiMode.
9739      */
9740     private boolean onlyDeskInUiModeChanged(Configuration lastReportedConfig) {
9741         final Configuration currentConfig = getConfiguration();
9742 
9743         boolean deskModeChanged = isInDeskUiMode(currentConfig) != isInDeskUiMode(
9744                 lastReportedConfig);
9745         // UI mode contains fields other than the UI mode type, so determine if any other fields
9746         // changed.
9747         boolean uiModeOtherFieldsChanged =
9748                 (currentConfig.uiMode & ~UI_MODE_TYPE_MASK) != (lastReportedConfig.uiMode
9749                         & ~UI_MODE_TYPE_MASK);
9750 
9751         return deskModeChanged && !uiModeOtherFieldsChanged;
9752     }
9753 
9754     /**
9755      * Determines whether or not the application has desk mode resources.
9756      */
9757     boolean hasDeskResources() {
9758         if (mHasDeskResources != null) {
9759             // We already determined this, return the cached value.
9760             return mHasDeskResources;
9761         }
9762 
9763         mHasDeskResources = false;
9764         try {
9765             Resources packageResources = mAtmService.mContext.createPackageContextAsUser(
9766                     packageName, 0, UserHandle.of(mUserId)).getResources();
9767             for (Configuration sizeConfiguration :
9768                     packageResources.getSizeAndUiModeConfigurations()) {
9769                 if (isInDeskUiMode(sizeConfiguration)) {
9770                     mHasDeskResources = true;
9771                     break;
9772                 }
9773             }
9774         } catch (PackageManager.NameNotFoundException e) {
9775             Slog.w(TAG, "Exception thrown during checking for desk resources " + this, e);
9776         }
9777         return mHasDeskResources;
9778     }
9779 
9780     private int getConfigurationChanges(Configuration lastReportedConfig) {
9781         // Determine what has changed.  May be nothing, if this is a config that has come back from
9782         // the app after going idle.  In that case we just want to leave the official config object
9783         // now in the activity and do nothing else.
9784         int changes = lastReportedConfig.diff(getConfiguration());
9785         changes = SizeConfigurationBuckets.filterDiff(
9786                     changes, lastReportedConfig, getConfiguration(), mSizeConfigurations);
9787         // We don't want window configuration to cause relaunches.
9788         if ((changes & CONFIG_WINDOW_CONFIGURATION) != 0) {
9789             changes &= ~CONFIG_WINDOW_CONFIGURATION;
9790         }
9791 
9792         return changes;
9793     }
9794 
9795     private static boolean isResizeOnlyChange(int change) {
9796         return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
9797                 | CONFIG_SCREEN_LAYOUT)) == 0;
9798     }
9799 
9800     private static boolean hasResizeChange(int change) {
9801         return (change & (CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
9802                 | CONFIG_SCREEN_LAYOUT)) != 0;
9803     }
9804 
9805     void relaunchActivityLocked(boolean preserveWindow) {
9806         if (mAtmService.mSuppressResizeConfigChanges && preserveWindow) {
9807             configChangeFlags = 0;
9808             return;
9809         }
9810         if (!preserveWindow) {
9811             // If the activity is the IME input target, ensure storing the last IME shown state
9812             // before relaunching it for restoring the IME visibility once its new window focused.
9813             final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget();
9814             mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null
9815                     && imeInputTarget.getWindowState().mActivityRecord == this
9816                     && mDisplayContent.mInputMethodWindow != null
9817                     && mDisplayContent.mInputMethodWindow.isVisible();
9818         }
9819         // Do not waiting for translucent activity if it is going to relaunch.
9820         final Task rootTask = getRootTask();
9821         if (rootTask != null && rootTask.mTranslucentActivityWaiting == this) {
9822             rootTask.checkTranslucentActivityWaiting(null);
9823         }
9824         final boolean andResume = shouldBeResumed(null /*activeActivity*/);
9825         List<ResultInfo> pendingResults = null;
9826         List<ReferrerIntent> pendingNewIntents = null;
9827         if (andResume) {
9828             pendingResults = results;
9829             pendingNewIntents = newIntents;
9830         }
9831         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
9832                 "Relaunching: " + this + " with results=" + pendingResults
9833                         + " newIntents=" + pendingNewIntents + " andResume=" + andResume
9834                         + " preserveWindow=" + preserveWindow);
9835         if (andResume) {
9836             EventLogTags.writeWmRelaunchResumeActivity(mUserId, System.identityHashCode(this),
9837                     task.mTaskId, shortComponentName, Integer.toHexString(configChangeFlags));
9838         } else {
9839             EventLogTags.writeWmRelaunchActivity(mUserId, System.identityHashCode(this),
9840                     task.mTaskId, shortComponentName, Integer.toHexString(configChangeFlags));
9841         }
9842 
9843         startFreezingScreenLocked(0);
9844 
9845         try {
9846             ProtoLog.i(WM_DEBUG_STATES, "Moving to %s Relaunching %s callers=%s" ,
9847                     (andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6));
9848             forceNewConfig = false;
9849             final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
9850                     pendingNewIntents, configChangeFlags,
9851                     new MergedConfiguration(getProcessGlobalConfiguration(),
9852                             getMergedOverrideConfiguration()),
9853                     preserveWindow);
9854             final ActivityLifecycleItem lifecycleItem;
9855             if (andResume) {
9856                 lifecycleItem = ResumeActivityItem.obtain(isTransitionForward(),
9857                         shouldSendCompatFakeFocus());
9858             } else {
9859                 lifecycleItem = PauseActivityItem.obtain();
9860             }
9861             final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), token);
9862             transaction.addCallback(callbackItem);
9863             transaction.setLifecycleStateRequest(lifecycleItem);
9864             mAtmService.getLifecycleManager().scheduleTransaction(transaction);
9865             startRelaunching();
9866             // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
9867             // request resume if this activity is currently resumed, which implies we aren't
9868             // sleeping.
9869         } catch (RemoteException e) {
9870             Slog.w(TAG, "Failed to relaunch " + this + ": " + e);
9871         }
9872 
9873         if (andResume) {
9874             ProtoLog.d(WM_DEBUG_STATES, "Resumed after relaunch %s", this);
9875             results = null;
9876             newIntents = null;
9877             mAtmService.getAppWarningsLocked().onResumeActivity(this);
9878         } else {
9879             removePauseTimeout();
9880             setState(PAUSED, "relaunchActivityLocked");
9881         }
9882 
9883         // The activity may be waiting for stop, but that is no longer appropriate for it.
9884         mTaskSupervisor.mStoppingActivities.remove(this);
9885 
9886         configChangeFlags = 0;
9887         deferRelaunchUntilPaused = false;
9888         preserveWindowOnDeferredRelaunch = false;
9889     }
9890 
9891     /**
9892      * Request the process of the activity to restart with its saved state (from
9893      * {@link android.app.Activity#onSaveInstanceState}) if possible. It also forces to recompute
9894      * the override configuration. Note if the activity is in background, the process will be killed
9895      * directly with keeping its record.
9896      */
9897     void restartProcessIfVisible() {
9898         if (finishing) return;
9899         Slog.i(TAG, "Request to restart process of " + this);
9900 
9901         // Reset the existing override configuration so it can be updated according to the latest
9902         // configuration.
9903         clearSizeCompatMode();
9904 
9905         if (!attachedToProcess()) {
9906             return;
9907         }
9908 
9909         // The restarting state avoids removing this record when process is died.
9910         setState(RESTARTING_PROCESS, "restartActivityProcess");
9911 
9912         if (!mVisibleRequested || mHaveState) {
9913             // Kill its process immediately because the activity should be in background.
9914             // The activity state will be update to {@link #DESTROYED} in
9915             // {@link ActivityStack#cleanUp} when handling process died.
9916             mAtmService.mH.post(() -> {
9917                 final WindowProcessController wpc;
9918                 synchronized (mAtmService.mGlobalLock) {
9919                     if (!hasProcess()
9920                             || app.getReportedProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND) {
9921                         return;
9922                     }
9923                     wpc = app;
9924                 }
9925                 mAtmService.mAmInternal.killProcess(wpc.mName, wpc.mUid, "resetConfig");
9926             });
9927             return;
9928         }
9929 
9930         if (mTransitionController.isShellTransitionsEnabled()) {
9931             final Transition transition = new Transition(TRANSIT_RELAUNCH, 0 /* flags */,
9932                     mTransitionController, mWmService.mSyncEngine);
9933             mTransitionController.startCollectOrQueue(transition, (deferred) -> {
9934                 if (mState != RESTARTING_PROCESS || !attachedToProcess()) {
9935                     transition.abort();
9936                     return;
9937                 }
9938                 // Request invisible so there will be a change after the activity is restarted
9939                 // to be visible.
9940                 setVisibleRequested(false);
9941                 transition.collect(this);
9942                 mTransitionController.requestStartTransition(transition, task,
9943                         null /* remoteTransition */, null /* displayChange */);
9944                 scheduleStopForRestartProcess();
9945             });
9946         } else {
9947             startFreezingScreen();
9948             scheduleStopForRestartProcess();
9949         }
9950     }
9951 
9952     private void scheduleStopForRestartProcess() {
9953         // The process will be killed until the activity reports stopped with saved state (see
9954         // {@link ActivityTaskManagerService.activityStopped}).
9955         try {
9956             mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
9957                     StopActivityItem.obtain(0 /* configChanges */));
9958         } catch (RemoteException e) {
9959             Slog.w(TAG, "Exception thrown during restart " + this, e);
9960         }
9961         mTaskSupervisor.scheduleRestartTimeout(this);
9962     }
9963 
9964     boolean isProcessRunning() {
9965         WindowProcessController proc = app;
9966         if (proc == null) {
9967             proc = mAtmService.mProcessNames.get(processName, info.applicationInfo.uid);
9968         }
9969         return proc != null && proc.hasThread();
9970     }
9971 
9972     /**
9973      * @return Whether a task snapshot starting window may be shown.
9974      */
9975     private boolean allowTaskSnapshot() {
9976         if (newIntents == null) {
9977             return true;
9978         }
9979 
9980         // Restrict task snapshot starting window to launcher start, or is same as the last
9981         // delivered intent, or there is no intent at all (eg. task being brought to front). If
9982         // the intent is something else, likely the app is going to show some specific page or
9983         // view, instead of what's left last time.
9984         for (int i = newIntents.size() - 1; i >= 0; i--) {
9985             final Intent intent = newIntents.get(i);
9986             if (intent == null || ActivityRecord.isMainIntent(intent)) {
9987                 continue;
9988             }
9989 
9990             final boolean sameIntent = mLastNewIntent != null ? mLastNewIntent.filterEquals(intent)
9991                     : this.intent.filterEquals(intent);
9992             if (!sameIntent || intent.getExtras() != null) {
9993                 return false;
9994             }
9995         }
9996         return true;
9997     }
9998 
9999     /**
10000      * Returns {@code true} if the associated activity has the no history flag set on it.
10001      * {@code false} otherwise.
10002      */
10003     boolean isNoHistory() {
10004         return (intent.getFlags() & FLAG_ACTIVITY_NO_HISTORY) != 0
10005                 || (info.flags & FLAG_NO_HISTORY) != 0;
10006     }
10007 
10008     void saveToXml(TypedXmlSerializer out) throws IOException, XmlPullParserException {
10009         out.attributeLong(null, ATTR_ID, createTime);
10010         out.attributeInt(null, ATTR_LAUNCHEDFROMUID, launchedFromUid);
10011         if (launchedFromPackage != null) {
10012             out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
10013         }
10014         if (launchedFromFeatureId != null) {
10015             out.attribute(null, ATTR_LAUNCHEDFROMFEATURE, launchedFromFeatureId);
10016         }
10017         if (resolvedType != null) {
10018             out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
10019         }
10020         out.attributeBoolean(null, ATTR_COMPONENTSPECIFIED, componentSpecified);
10021         out.attributeInt(null, ATTR_USERID, mUserId);
10022 
10023         if (taskDescription != null) {
10024             taskDescription.saveToXml(out);
10025         }
10026 
10027         out.startTag(null, TAG_INTENT);
10028         intent.saveToXml(out);
10029         out.endTag(null, TAG_INTENT);
10030 
10031         if (isPersistable() && mPersistentState != null) {
10032             out.startTag(null, TAG_PERSISTABLEBUNDLE);
10033             mPersistentState.saveToXml(out);
10034             out.endTag(null, TAG_PERSISTABLEBUNDLE);
10035         }
10036     }
10037 
10038     static ActivityRecord restoreFromXml(TypedXmlPullParser in,
10039             ActivityTaskSupervisor taskSupervisor) throws IOException, XmlPullParserException {
10040         Intent intent = null;
10041         PersistableBundle persistentState = null;
10042         int launchedFromUid = in.getAttributeInt(null, ATTR_LAUNCHEDFROMUID, 0);
10043         String launchedFromPackage = in.getAttributeValue(null, ATTR_LAUNCHEDFROMPACKAGE);
10044         String launchedFromFeature = in.getAttributeValue(null, ATTR_LAUNCHEDFROMFEATURE);
10045         String resolvedType = in.getAttributeValue(null, ATTR_RESOLVEDTYPE);
10046         boolean componentSpecified = in.getAttributeBoolean(null, ATTR_COMPONENTSPECIFIED, false);
10047         int userId = in.getAttributeInt(null, ATTR_USERID, 0);
10048         long createTime = in.getAttributeLong(null, ATTR_ID, -1);
10049         final int outerDepth = in.getDepth();
10050 
10051         TaskDescription taskDescription = new TaskDescription();
10052         taskDescription.restoreFromXml(in);
10053 
10054         int event;
10055         while (((event = in.next()) != END_DOCUMENT) &&
10056                 (event != END_TAG || in.getDepth() >= outerDepth)) {
10057             if (event == START_TAG) {
10058                 final String name = in.getName();
10059                 if (DEBUG)
10060                         Slog.d(TaskPersister.TAG, "ActivityRecord: START_TAG name=" + name);
10061                 if (TAG_INTENT.equals(name)) {
10062                     intent = Intent.restoreFromXml(in);
10063                     if (DEBUG)
10064                             Slog.d(TaskPersister.TAG, "ActivityRecord: intent=" + intent);
10065                 } else if (TAG_PERSISTABLEBUNDLE.equals(name)) {
10066                     persistentState = PersistableBundle.restoreFromXml(in);
10067                     if (DEBUG) Slog.d(TaskPersister.TAG,
10068                             "ActivityRecord: persistentState=" + persistentState);
10069                 } else {
10070                     Slog.w(TAG, "restoreActivity: unexpected name=" + name);
10071                     XmlUtils.skipCurrentTag(in);
10072                 }
10073             }
10074         }
10075 
10076         if (intent == null) {
10077             throw new XmlPullParserException("restoreActivity error intent=" + intent);
10078         }
10079 
10080         final ActivityTaskManagerService service = taskSupervisor.mService;
10081         final ActivityInfo aInfo = taskSupervisor.resolveActivity(intent, resolvedType, 0, null,
10082                 userId, Binder.getCallingUid(), 0);
10083         if (aInfo == null) {
10084             throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent +
10085                     " resolvedType=" + resolvedType);
10086         }
10087         return new ActivityRecord.Builder(service)
10088                 .setLaunchedFromUid(launchedFromUid)
10089                 .setLaunchedFromPackage(launchedFromPackage)
10090                 .setLaunchedFromFeature(launchedFromFeature)
10091                 .setIntent(intent)
10092                 .setResolvedType(resolvedType)
10093                 .setActivityInfo(aInfo)
10094                 .setComponentSpecified(componentSpecified)
10095                 .setPersistentState(persistentState)
10096                 .setTaskDescription(taskDescription)
10097                 .setCreateTime(createTime)
10098                 .build();
10099     }
10100 
10101     private static boolean isInVrUiMode(Configuration config) {
10102         return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
10103     }
10104 
10105     private static boolean isInDeskUiMode(Configuration config) {
10106         return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_DESK;
10107     }
10108 
10109     String getProcessName() {
10110         return info.applicationInfo.processName;
10111     }
10112 
10113     int getUid() {
10114         return info.applicationInfo.uid;
10115     }
10116 
10117     boolean isUid(int uid) {
10118         return info.applicationInfo.uid == uid;
10119     }
10120 
10121     int getPid() {
10122         return app != null ? app.getPid() : 0;
10123     }
10124 
10125     int getLaunchedFromPid() {
10126         return launchedFromPid;
10127     }
10128 
10129     int getLaunchedFromUid() {
10130         return launchedFromUid;
10131     }
10132 
10133     /**
10134      * Gets the referrer package name with respect to package visibility. This method returns null
10135      * if the given package is not visible to this activity.
10136      */
10137     String getFilteredReferrer(String referrerPackage) {
10138         if (referrerPackage == null || (!referrerPackage.equals(packageName)
10139                 && mWmService.mPmInternal.filterAppAccess(
10140                         referrerPackage, info.applicationInfo.uid, mUserId))) {
10141             return null;
10142         }
10143         return referrerPackage;
10144     }
10145 
10146     /**
10147      * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag
10148      * {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord
10149      * should be visible depending on Keyguard state.
10150      *
10151      * @return true if the screen can be turned on, false otherwise.
10152      */
10153     boolean canTurnScreenOn() {
10154         if (!getTurnScreenOnFlag()) {
10155             return false;
10156         }
10157         final Task rootTask = getRootTask();
10158         return mCurrentLaunchCanTurnScreenOn && rootTask != null
10159                 && mTaskSupervisor.getKeyguardController().checkKeyguardVisibility(this);
10160     }
10161 
10162     void setTurnScreenOn(boolean turnScreenOn) {
10163         mTurnScreenOn = turnScreenOn;
10164     }
10165 
10166     void setAllowCrossUidActivitySwitchFromBelow(boolean allowed) {
10167         mAllowCrossUidActivitySwitchFromBelow = allowed;
10168     }
10169 
10170     /**
10171      * Determines if a source is allowed to add or remove activities from the task,
10172      * if the current ActivityRecord is above it in the stack
10173      *
10174      * A transition is blocked ({@code false} returned) if all of the following are met:
10175      * <pre>
10176      * 1. The source activity and the current activity record belong to different apps
10177      * (i.e, have different UIDs).
10178      * 2. Both the source activity and the current activity target U+
10179      * 3. The current activity has not set
10180      * {@link ActivityRecord#setAllowCrossUidActivitySwitchFromBelow(boolean)} to {@code true}
10181      * </pre>
10182      *
10183      * Returns a pair where the elements mean:
10184      * <pre>
10185      * First: {@code false} if we should actually block the transition (takes into consideration
10186      * feature flag and targetSdk).
10187      * Second: {@code false} if we should warn about the transition via toasts. This happens if
10188      * the transition would be blocked in case both the app was targeting U+ and the feature was
10189      * enabled.
10190      * </pre>
10191      *
10192      * @param sourceUid The source (s) activity performing the state change
10193      */
10194     Pair<Boolean, Boolean> allowCrossUidActivitySwitchFromBelow(int sourceUid) {
10195         int myUid = info.applicationInfo.uid;
10196         if (sourceUid == myUid) {
10197             return new Pair<>(true, true);
10198         }
10199 
10200         // If mAllowCrossUidActivitySwitchFromBelow is set, honor it.
10201         if (mAllowCrossUidActivitySwitchFromBelow) {
10202             return new Pair<>(true, true);
10203         }
10204 
10205         // If it is not set, default to true if both records target ≥ U, false otherwise
10206         // TODO(b/258792202) Replace with CompatChanges and replace Pair with boolean once feature
10207         // flag is removed
10208         boolean restrictActivitySwitch =
10209                 ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(myUid)
10210                     && ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(sourceUid);
10211         return new Pair<>(!restrictActivitySwitch, false);
10212     }
10213 
10214     boolean getTurnScreenOnFlag() {
10215         return mTurnScreenOn || containsTurnScreenOnWindow();
10216     }
10217 
10218     private boolean containsTurnScreenOnWindow() {
10219         // When we are relaunching, it is possible for us to be unfrozen before our previous
10220         // windows have been added back. Using the cached value ensures that our previous
10221         // showWhenLocked preference is honored until relaunching is complete.
10222         if (isRelaunching()) {
10223             return mLastContainsTurnScreenOnWindow;
10224         }
10225         for (int i = mChildren.size() - 1; i >= 0; i--) {
10226             if ((mChildren.get(i).mAttrs.flags & LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
10227                 return true;
10228             }
10229         }
10230         return false;
10231     }
10232 
10233     /**
10234      * Check if this activity is able to resume. For pre-Q apps, only the topmost activities of each
10235      * process are allowed to be resumed.
10236      *
10237      * @return true if this activity can be resumed.
10238      */
10239     boolean canResumeByCompat() {
10240         return app == null || app.updateTopResumingActivityInProcessIfNeeded(this);
10241     }
10242 
10243     boolean isTopRunningActivity() {
10244         return mRootWindowContainer.topRunningActivity() == this;
10245     }
10246 
10247     /**
10248      * @return {@code true} if this is the focused activity on its current display, {@code false}
10249      * otherwise.
10250      */
10251     boolean isFocusedActivityOnDisplay() {
10252         return mDisplayContent.forAllTaskDisplayAreas(taskDisplayArea ->
10253                 taskDisplayArea.getFocusedActivity() == this);
10254     }
10255 
10256 
10257     /**
10258      * Check if this is the root of the task - first activity that is not finishing, starting from
10259      * the bottom of the task. If all activities are finishing - then this method will return
10260      * {@code true} if the activity is at the bottom.
10261      *
10262      * NOTE: This is different from 'effective root' - an activity that defines the task identity.
10263      */
10264     boolean isRootOfTask() {
10265         if (task == null) {
10266             return false;
10267         }
10268         final ActivityRecord rootActivity = task.getRootActivity(true);
10269         return this == rootActivity;
10270     }
10271 
10272     void setTaskOverlay(boolean taskOverlay) {
10273         mTaskOverlay = taskOverlay;
10274         setAlwaysOnTop(mTaskOverlay);
10275     }
10276 
10277     boolean isTaskOverlay() {
10278         return mTaskOverlay;
10279     }
10280 
10281     @Override
10282     public boolean isAlwaysOnTop() {
10283         return mTaskOverlay || super.isAlwaysOnTop();
10284     }
10285 
10286     @Override
10287     boolean showToCurrentUser() {
10288         return mShowForAllUsers || mWmService.isUserVisible(mUserId);
10289     }
10290 
10291     @Override
10292     boolean canCustomizeAppTransition() {
10293         return true;
10294     }
10295 
10296     @Override
10297     public String toString() {
10298         if (stringName != null) {
10299             return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) +
10300                     (finishing ? " f}" : "") + (mIsExiting ? " isExiting" : "") + "}";
10301         }
10302         StringBuilder sb = new StringBuilder(128);
10303         sb.append("ActivityRecord{");
10304         sb.append(Integer.toHexString(System.identityHashCode(this)));
10305         sb.append(" u");
10306         sb.append(mUserId);
10307         sb.append(' ');
10308         sb.append(intent.getComponent().flattenToShortString());
10309         stringName = sb.toString();
10310         return stringName;
10311     }
10312 
10313     /**
10314      * Write all fields to an {@code ActivityRecordProto}. This assumes the
10315      * {@code ActivityRecordProto} is the outer-most proto data.
10316      */
10317     void dumpDebug(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) {
10318         writeNameToProto(proto, NAME);
10319         super.dumpDebug(proto, WINDOW_TOKEN, logLevel);
10320         proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
10321         proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
10322         proto.write(IS_ANIMATING, isAnimating(TRANSITION | PARENTS | CHILDREN,
10323                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION));
10324         if (mThumbnail != null){
10325             mThumbnail.dumpDebug(proto, THUMBNAIL);
10326         }
10327         proto.write(FILLS_PARENT, fillsParent());
10328         proto.write(APP_STOPPED, mAppStopped);
10329         proto.write(TRANSLUCENT, !occludesParent());
10330         proto.write(VISIBLE, mVisible);
10331         proto.write(VISIBLE_REQUESTED, mVisibleRequested);
10332         proto.write(CLIENT_VISIBLE, isClientVisible());
10333         proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
10334         proto.write(REPORTED_DRAWN, mReportedDrawn);
10335         proto.write(REPORTED_VISIBLE, reportedVisible);
10336         proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows);
10337         proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows);
10338         proto.write(ALL_DRAWN, allDrawn);
10339         proto.write(LAST_ALL_DRAWN, mLastAllDrawn);
10340         if (mStartingWindow != null) {
10341             mStartingWindow.writeIdentifierToProto(proto, STARTING_WINDOW);
10342         }
10343         proto.write(STARTING_DISPLAYED, isStartingWindowDisplayed());
10344         proto.write(STARTING_MOVED, startingMoved);
10345         proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW,
10346                 mVisibleSetFromTransferredStartingWindow);
10347 
10348         proto.write(STATE, mState.toString());
10349         proto.write(FRONT_OF_TASK, isRootOfTask());
10350         if (hasProcess()) {
10351             proto.write(PROC_ID, app.getPid());
10352         }
10353         proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled());
10354         proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
10355         proto.write(MIN_ASPECT_RATIO, getMinAspectRatio());
10356         // Only record if max bounds sandboxing is applied, if the caller has the necessary
10357         // permission to access the device configs.
10358         proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds());
10359         proto.write(ENABLE_RECENTS_SCREENSHOT, mEnableRecentsScreenshot);
10360         proto.write(LAST_DROP_INPUT_MODE, mLastDropInputMode);
10361         proto.write(OVERRIDE_ORIENTATION, getOverrideOrientation());
10362         proto.write(SHOULD_SEND_COMPAT_FAKE_FOCUS, shouldSendCompatFakeFocus());
10363         proto.write(SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT,
10364                 mLetterboxUiController.shouldForceRotateForCameraCompat());
10365         proto.write(SHOULD_REFRESH_ACTIVITY_FOR_CAMERA_COMPAT,
10366                 mLetterboxUiController.shouldRefreshActivityForCameraCompat());
10367         proto.write(SHOULD_REFRESH_ACTIVITY_VIA_PAUSE_FOR_CAMERA_COMPAT,
10368                 mLetterboxUiController.shouldRefreshActivityViaPauseForCameraCompat());
10369     }
10370 
10371     @Override
10372     long getProtoFieldId() {
10373         return ACTIVITY;
10374     }
10375 
10376     @Override
10377     public void dumpDebug(ProtoOutputStream proto, long fieldId,
10378             @WindowTraceLogLevel int logLevel) {
10379         // Critical log level logs only visible elements to mitigate performance overheard
10380         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
10381             return;
10382         }
10383 
10384         final long token = proto.start(fieldId);
10385         dumpDebug(proto, logLevel);
10386         proto.end(token);
10387     }
10388 
10389     void writeNameToProto(ProtoOutputStream proto, long fieldId) {
10390         proto.write(fieldId, shortComponentName);
10391     }
10392 
10393     @Override
10394     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
10395         final long token = proto.start(fieldId);
10396         proto.write(HASH_CODE, System.identityHashCode(this));
10397         proto.write(USER_ID, mUserId);
10398         proto.write(TITLE, intent.getComponent().flattenToShortString());
10399         proto.end(token);
10400     }
10401 
10402     /**
10403      * The precomputed insets of the display in each rotation. This is used to make the size
10404      * compatibility mode activity compute the configuration without relying on its current display.
10405      */
10406     static class CompatDisplayInsets {
10407         /** The original rotation the compat insets were computed in. */
10408         final @Rotation int mOriginalRotation;
10409         /** The original requested orientation for the activity. */
10410         final @Configuration.Orientation int mOriginalRequestedOrientation;
10411         /** The container width on rotation 0. */
10412         private final int mWidth;
10413         /** The container height on rotation 0. */
10414         private final int mHeight;
10415         /** Whether the {@link Task} windowingMode represents a floating window*/
10416         final boolean mIsFloating;
10417         /**
10418          * Whether is letterboxed because of fixed orientation when the unresizable activity is
10419          * first shown.
10420          */
10421         final boolean mIsInFixedOrientationLetterbox;
10422         /**
10423          * The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
10424          * is used to compute the appBounds.
10425          */
10426         final Rect[] mNonDecorInsets = new Rect[4];
10427         /**
10428          * The stableInsets for each rotation. Includes the status bar inset and the
10429          * nonDecorInsets. It is used to compute {@link Configuration#screenWidthDp} and
10430          * {@link Configuration#screenHeightDp}.
10431          */
10432         final Rect[] mStableInsets = new Rect[4];
10433 
10434         /** Constructs the environment to simulate the bounds behavior of the given container. */
10435         CompatDisplayInsets(DisplayContent display, ActivityRecord container,
10436                 @Nullable Rect fixedOrientationBounds) {
10437             mOriginalRotation = display.getRotation();
10438             mIsFloating = container.getWindowConfiguration().tasksAreFloating();
10439             mOriginalRequestedOrientation = container.getRequestedConfigurationOrientation();
10440             if (mIsFloating) {
10441                 final Rect containerBounds = container.getWindowConfiguration().getBounds();
10442                 mWidth = containerBounds.width();
10443                 mHeight = containerBounds.height();
10444                 // For apps in freeform, the task bounds are the parent bounds from the app's
10445                 // perspective. No insets because within a window.
10446                 final Rect emptyRect = new Rect();
10447                 for (int rotation = 0; rotation < 4; rotation++) {
10448                     mNonDecorInsets[rotation] = emptyRect;
10449                     mStableInsets[rotation] = emptyRect;
10450                 }
10451                 mIsInFixedOrientationLetterbox = false;
10452                 return;
10453             }
10454 
10455             final Task task = container.getTask();
10456 
10457             mIsInFixedOrientationLetterbox = fixedOrientationBounds != null;
10458 
10459             // Store the bounds of the Task for the non-resizable activity to use in size compat
10460             // mode so that the activity will not be resized regardless the windowing mode it is
10461             // currently in.
10462             // When an activity needs to be letterboxed because of fixed orientation, use fixed
10463             // orientation bounds instead of task bounds since the activity will be displayed
10464             // within these even if it is in size compat mode.
10465             final Rect filledContainerBounds = mIsInFixedOrientationLetterbox
10466                     ? fixedOrientationBounds
10467                     : task != null ? task.getBounds() : display.getBounds();
10468             final int filledContainerRotation = task != null
10469                     ? task.getConfiguration().windowConfiguration.getRotation()
10470                     : display.getConfiguration().windowConfiguration.getRotation();
10471             final Point dimensions = getRotationZeroDimensions(
10472                     filledContainerBounds, filledContainerRotation);
10473             mWidth = dimensions.x;
10474             mHeight = dimensions.y;
10475 
10476             // Bounds of the filled container if it doesn't fill the display.
10477             final Rect unfilledContainerBounds =
10478                     filledContainerBounds.equals(display.getBounds()) ? null : new Rect();
10479             final DisplayPolicy policy = display.getDisplayPolicy();
10480             for (int rotation = 0; rotation < 4; rotation++) {
10481                 mNonDecorInsets[rotation] = new Rect();
10482                 mStableInsets[rotation] = new Rect();
10483                 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
10484                 final int dw = rotated ? display.mBaseDisplayHeight : display.mBaseDisplayWidth;
10485                 final int dh = rotated ? display.mBaseDisplayWidth : display.mBaseDisplayHeight;
10486                 final DisplayPolicy.DecorInsets.Info decorInfo =
10487                         policy.getDecorInsetsInfo(rotation, dw, dh);
10488                 mNonDecorInsets[rotation].set(decorInfo.mNonDecorInsets);
10489                 mStableInsets[rotation].set(decorInfo.mConfigInsets);
10490 
10491                 if (unfilledContainerBounds == null) {
10492                     continue;
10493                 }
10494                 // The insets is based on the display, but the container may be smaller than the
10495                 // display, so update the insets to exclude parts that are not intersected with the
10496                 // container.
10497                 unfilledContainerBounds.set(filledContainerBounds);
10498                 display.rotateBounds(
10499                         filledContainerRotation,
10500                         rotation,
10501                         unfilledContainerBounds);
10502                 updateInsetsForBounds(unfilledContainerBounds, dw, dh, mNonDecorInsets[rotation]);
10503                 updateInsetsForBounds(unfilledContainerBounds, dw, dh, mStableInsets[rotation]);
10504             }
10505         }
10506 
10507         /**
10508          * Gets the width and height of the {@code container} when it is not rotated, so that after
10509          * the display is rotated, we can calculate the bounds by rotating the dimensions.
10510          * @see #getBoundsByRotation
10511          */
10512         private static Point getRotationZeroDimensions(final Rect bounds, int rotation) {
10513             final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
10514             final int width = bounds.width();
10515             final int height = bounds.height();
10516             return rotated ? new Point(height, width) : new Point(width, height);
10517         }
10518 
10519         /**
10520          * Updates the display insets to exclude the parts that are not intersected with the given
10521          * bounds.
10522          */
10523         private static void updateInsetsForBounds(Rect bounds, int displayWidth, int displayHeight,
10524                 Rect inset) {
10525             inset.left = Math.max(0, inset.left - bounds.left);
10526             inset.top = Math.max(0, inset.top - bounds.top);
10527             inset.right = Math.max(0, bounds.right - displayWidth + inset.right);
10528             inset.bottom = Math.max(0, bounds.bottom - displayHeight + inset.bottom);
10529         }
10530 
10531         void getBoundsByRotation(Rect outBounds, int rotation) {
10532             final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
10533             final int dw = rotated ? mHeight : mWidth;
10534             final int dh = rotated ? mWidth : mHeight;
10535             outBounds.set(0, 0, dw, dh);
10536         }
10537 
10538         void getFrameByOrientation(Rect outBounds, int orientation) {
10539             final int longSide = Math.max(mWidth, mHeight);
10540             final int shortSide = Math.min(mWidth, mHeight);
10541             final boolean isLandscape = orientation == ORIENTATION_LANDSCAPE;
10542             outBounds.set(0, 0, isLandscape ? longSide : shortSide,
10543                     isLandscape ? shortSide : longSide);
10544         }
10545 
10546         // TODO(b/267151420): Explore removing getContainerBounds() from CompatDisplayInsets.
10547         /** Gets the horizontal centered container bounds for size compatibility mode. */
10548         void getContainerBounds(Rect outAppBounds, Rect outBounds, int rotation, int orientation,
10549                 boolean orientationRequested, boolean isFixedToUserRotation) {
10550             getFrameByOrientation(outBounds, orientation);
10551             if (mIsFloating) {
10552                 outAppBounds.set(outBounds);
10553                 return;
10554             }
10555 
10556             getBoundsByRotation(outAppBounds, rotation);
10557             final int dW = outAppBounds.width();
10558             final int dH = outAppBounds.height();
10559             final boolean isOrientationMismatched =
10560                     ((outBounds.width() > outBounds.height()) != (dW > dH));
10561 
10562             if (isOrientationMismatched && isFixedToUserRotation && orientationRequested) {
10563                 // The orientation is mismatched but the display cannot rotate. The bounds will fit
10564                 // to the short side of container.
10565                 if (orientation == ORIENTATION_LANDSCAPE) {
10566                     outBounds.bottom = (int) ((float) dW * dW / dH);
10567                     outBounds.right = dW;
10568                 } else {
10569                     outBounds.bottom = dH;
10570                     outBounds.right = (int) ((float) dH * dH / dW);
10571                 }
10572                 outBounds.offset(getCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
10573             }
10574             outAppBounds.set(outBounds);
10575 
10576             if (isOrientationMismatched) {
10577                 // One side of container is smaller than the requested size, then it will be scaled
10578                 // and the final position will be calculated according to the parent container and
10579                 // scale, so the original size shouldn't be shrunk by insets.
10580                 final Rect insets = mNonDecorInsets[rotation];
10581                 outBounds.offset(insets.left, insets.top);
10582                 outAppBounds.offset(insets.left, insets.top);
10583             } else if (rotation != ROTATION_UNDEFINED) {
10584                 // Ensure the app bounds won't overlap with insets.
10585                 TaskFragment.intersectWithInsetsIfFits(outAppBounds, outBounds,
10586                         mNonDecorInsets[rotation]);
10587             }
10588         }
10589     }
10590 
10591     private static class AppSaturationInfo {
10592         float[] mMatrix = new float[9];
10593         float[] mTranslation = new float[3];
10594 
10595         void setSaturation(@Size(9) float[] matrix, @Size(3) float[] translation) {
10596             System.arraycopy(matrix, 0, mMatrix, 0, mMatrix.length);
10597             System.arraycopy(translation, 0, mTranslation, 0, mTranslation.length);
10598         }
10599     }
10600 
10601     @Override
10602     RemoteAnimationTarget createRemoteAnimationTarget(
10603             RemoteAnimationController.RemoteAnimationRecord record) {
10604         final WindowState mainWindow = findMainWindow();
10605         if (task == null || mainWindow == null) {
10606             return null;
10607         }
10608         final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
10609                 task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect();
10610         InsetUtils.addInsets(insets, getLetterboxInsets());
10611 
10612         final RemoteAnimationTarget target = new RemoteAnimationTarget(task.mTaskId,
10613                 record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(),
10614                 new Rect(), insets,
10615                 getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
10616                 record.mAdapter.mEndBounds, task.getWindowConfiguration(),
10617                 false /*isNotInRecents*/,
10618                 record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
10619                 record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
10620         target.setShowBackdrop(record.mShowBackdrop);
10621         target.setWillShowImeOnTarget(mStartingData != null && mStartingData.hasImeSurface());
10622         target.hasAnimatingParent = record.hasAnimatingParent();
10623         return target;
10624     }
10625 
10626     @Override
10627     boolean canCreateRemoteAnimationTarget() {
10628         return true;
10629     }
10630 
10631     @Override
10632     void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
10633             Rect outSurfaceInsets) {
10634         final WindowState win = findMainWindow();
10635         if (win == null) {
10636             return;
10637         }
10638         win.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
10639     }
10640 
10641     void setPictureInPictureParams(PictureInPictureParams p) {
10642         pictureInPictureArgs.copyOnlySet(p);
10643         adjustPictureInPictureParamsIfNeeded(getBounds());
10644         getTask().getRootTask().onPictureInPictureParamsChanged();
10645     }
10646 
10647     void setShouldDockBigOverlays(boolean shouldDockBigOverlays) {
10648         this.shouldDockBigOverlays = shouldDockBigOverlays;
10649         getTask().getRootTask().onShouldDockBigOverlaysChanged();
10650     }
10651 
10652     @Override
10653     boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
10654         if (!super.isSyncFinished(group)) return false;
10655         if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController
10656                 .isVisibilityUnknown(this)) {
10657             return false;
10658         }
10659         if (!isVisibleRequested()) return true;
10660         if (mPendingRelaunchCount > 0) return false;
10661         // Wait for attach. That is the earliest time where we know if there will be an associated
10662         // display rotation. If we don't wait, the starting-window can finishDrawing first and
10663         // cause the display rotation to end-up in a following transition.
10664         if (!isAttached()) return false;
10665         // If visibleRequested, wait for at-least one visible child.
10666         for (int i = mChildren.size() - 1; i >= 0; --i) {
10667             if (mChildren.get(i).isVisibleRequested()) {
10668                 return true;
10669             }
10670         }
10671         return false;
10672     }
10673 
10674     @Override
10675     void finishSync(Transaction outMergedTransaction, BLASTSyncEngine.SyncGroup group,
10676             boolean cancel) {
10677         // This override is just for getting metrics. allFinished needs to be checked before
10678         // finish because finish resets all the states.
10679         final BLASTSyncEngine.SyncGroup syncGroup = getSyncGroup();
10680         if (syncGroup != null && group != getSyncGroup()) return;
10681         mLastAllReadyAtSync = allSyncFinished();
10682         super.finishSync(outMergedTransaction, group, cancel);
10683     }
10684 
10685     @Nullable
10686     Point getMinDimensions() {
10687         final ActivityInfo.WindowLayout windowLayout = info.windowLayout;
10688         if (windowLayout == null) {
10689             return null;
10690         }
10691         return new Point(windowLayout.minWidth, windowLayout.minHeight);
10692     }
10693 
10694     /**
10695      * Adjust the source rect hint in {@link #pictureInPictureArgs} by window bounds since
10696      * it is relative to its root view (see also b/235599028).
10697      * It is caller's responsibility to make sure this is called exactly once when we update
10698      * {@link #pictureInPictureArgs} to avoid double offset.
10699      */
10700     private void adjustPictureInPictureParamsIfNeeded(Rect windowBounds) {
10701         if (pictureInPictureArgs != null && pictureInPictureArgs.hasSourceBoundsHint()) {
10702             pictureInPictureArgs.getSourceRectHint().offset(windowBounds.left, windowBounds.top);
10703         }
10704     }
10705 
10706     private void applyLocaleOverrideIfNeeded(Configuration resolvedConfig) {
10707         // We always align the locale for ActivityEmbedding apps. System apps or some apps which
10708         // has set known cert apps can embed across different uid activity.
10709         boolean shouldAlignLocale = isEmbedded()
10710                 || (task != null && task.mAlignActivityLocaleWithTask);
10711         if (!shouldAlignLocale) {
10712             return;
10713         }
10714 
10715         boolean differentPackage = task != null
10716                 && task.realActivity != null
10717                 && !task.realActivity.getPackageName().equals(packageName);
10718         if (!differentPackage) {
10719             return;
10720         }
10721 
10722         final ActivityTaskManagerInternal.PackageConfig appConfig =
10723                 mAtmService.mPackageConfigPersister.findPackageConfiguration(
10724                         task.realActivity.getPackageName(), mUserId);
10725         // If package lookup yields locales, set the target activity's locales to match,
10726         // otherwise leave target activity as-is.
10727         if (appConfig != null && appConfig.mLocales != null && !appConfig.mLocales.isEmpty()) {
10728             resolvedConfig.setLocales(appConfig.mLocales);
10729         }
10730     }
10731 
10732     /**
10733      * Whether we should send fake focus when the activity is resumed. This is done because some
10734      * game engines wait to get focus before drawing the content of the app.
10735      */
10736     // TODO(b/263593361): Explore enabling compat fake focus for freeform.
10737     // TODO(b/263592337): Explore enabling compat fake focus for fullscreen, e.g. for when
10738     // covered with bubbles.
10739     boolean shouldSendCompatFakeFocus() {
10740         return mLetterboxUiController.shouldSendFakeFocus() && inMultiWindowMode()
10741                 && !inPinnedWindowingMode() && !inFreeformWindowingMode();
10742     }
10743 
10744     boolean canCaptureSnapshot() {
10745         if (!isSurfaceShowing() || findMainWindow() == null) {
10746             return false;
10747         }
10748         return forAllWindows(
10749                 // Ensure at least one window for the top app is visible before attempting to
10750                 // take a screenshot. Visible here means that the WSA surface is shown and has
10751                 // an alpha greater than 0.
10752                 ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown()
10753                         && ws.mWinAnimator.mLastAlpha > 0f, true  /* traverseTopToBottom */);
10754     }
10755 
10756     void overrideCustomTransition(boolean open, int enterAnim, int exitAnim, int backgroundColor) {
10757         CustomAppTransition transition = getCustomAnimation(open);
10758         if (transition == null) {
10759             transition = new CustomAppTransition();
10760             if (open) {
10761                 mCustomOpenTransition = transition;
10762             } else {
10763                 mCustomCloseTransition = transition;
10764             }
10765         }
10766 
10767         transition.mEnterAnim = enterAnim;
10768         transition.mExitAnim = exitAnim;
10769         transition.mBackgroundColor = backgroundColor;
10770     }
10771 
10772     void clearCustomTransition(boolean open) {
10773         if (open) {
10774             mCustomOpenTransition = null;
10775         } else {
10776             mCustomCloseTransition = null;
10777         }
10778     }
10779 
10780     CustomAppTransition getCustomAnimation(boolean open) {
10781         return open ? mCustomOpenTransition : mCustomCloseTransition;
10782     }
10783 
10784     // Override the WindowAnimation_(Open/Close)(Enter/Exit)Animation
10785     static class CustomAppTransition {
10786         int mEnterAnim;
10787         int mExitAnim;
10788         int mBackgroundColor;
10789     }
10790 
10791     static class Builder {
10792         private final ActivityTaskManagerService mAtmService;
10793         private WindowProcessController mCallerApp;
10794         private int mLaunchedFromPid;
10795         private int mLaunchedFromUid;
10796         private String mLaunchedFromPackage;
10797         private String mLaunchedFromFeature;
10798         private Intent mIntent;
10799         private String mResolvedType;
10800         private ActivityInfo mActivityInfo;
10801         private Configuration mConfiguration;
10802         private ActivityRecord mResultTo;
10803         private String mResultWho;
10804         private int mRequestCode;
10805         private boolean mComponentSpecified;
10806         private boolean mRootVoiceInteraction;
10807         private ActivityOptions mOptions;
10808         private ActivityRecord mSourceRecord;
10809         private PersistableBundle mPersistentState;
10810         private TaskDescription mTaskDescription;
10811         private long mCreateTime;
10812 
10813         Builder(ActivityTaskManagerService service) {
10814             mAtmService = service;
10815         }
10816 
10817         Builder setCaller(@NonNull WindowProcessController caller) {
10818             mCallerApp = caller;
10819             return this;
10820         }
10821 
10822         Builder setLaunchedFromPid(int pid) {
10823             mLaunchedFromPid = pid;
10824             return this;
10825         }
10826 
10827         Builder setLaunchedFromUid(int uid) {
10828             mLaunchedFromUid = uid;
10829             return this;
10830         }
10831 
10832         Builder setLaunchedFromPackage(String fromPackage) {
10833             mLaunchedFromPackage = fromPackage;
10834             return this;
10835         }
10836 
10837         Builder setLaunchedFromFeature(String fromFeature) {
10838             mLaunchedFromFeature = fromFeature;
10839             return this;
10840         }
10841 
10842         Builder setIntent(Intent intent) {
10843             mIntent = intent;
10844             return this;
10845         }
10846 
10847         Builder setResolvedType(String resolvedType) {
10848             mResolvedType = resolvedType;
10849             return this;
10850         }
10851 
10852         Builder setActivityInfo(ActivityInfo activityInfo) {
10853             mActivityInfo = activityInfo;
10854             return this;
10855         }
10856 
10857         Builder setResultTo(ActivityRecord resultTo) {
10858             mResultTo = resultTo;
10859             return this;
10860         }
10861 
10862         Builder setResultWho(String resultWho) {
10863             mResultWho = resultWho;
10864             return this;
10865         }
10866 
10867         Builder setRequestCode(int reqCode) {
10868             mRequestCode = reqCode;
10869             return this;
10870         }
10871 
10872         Builder setComponentSpecified(boolean componentSpecified) {
10873             mComponentSpecified = componentSpecified;
10874             return this;
10875         }
10876 
10877         Builder setRootVoiceInteraction(boolean rootVoiceInteraction) {
10878             mRootVoiceInteraction = rootVoiceInteraction;
10879             return this;
10880         }
10881 
10882         Builder setActivityOptions(ActivityOptions options) {
10883             mOptions = options;
10884             return this;
10885         }
10886 
10887         Builder setConfiguration(Configuration config) {
10888             mConfiguration = config;
10889             return this;
10890         }
10891 
10892         Builder setSourceRecord(ActivityRecord source) {
10893             mSourceRecord = source;
10894             return this;
10895         }
10896 
10897         private Builder setPersistentState(PersistableBundle persistentState) {
10898             mPersistentState = persistentState;
10899             return this;
10900         }
10901 
10902         private Builder setTaskDescription(TaskDescription taskDescription) {
10903             mTaskDescription = taskDescription;
10904             return this;
10905         }
10906 
10907         private Builder setCreateTime(long createTime) {
10908             mCreateTime = createTime;
10909             return this;
10910         }
10911 
10912         ActivityRecord build() {
10913             if (mConfiguration == null) {
10914                 mConfiguration = mAtmService.getConfiguration();
10915             }
10916             return new ActivityRecord(mAtmService, mCallerApp, mLaunchedFromPid,
10917                     mLaunchedFromUid, mLaunchedFromPackage, mLaunchedFromFeature, mIntent,
10918                     mResolvedType, mActivityInfo, mConfiguration, mResultTo, mResultWho,
10919                     mRequestCode, mComponentSpecified, mRootVoiceInteraction,
10920                     mAtmService.mTaskSupervisor, mOptions, mSourceRecord, mPersistentState,
10921                     mTaskDescription, mCreateTime);
10922         }
10923     }
10924 }
10925