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