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