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