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