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