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