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