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