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