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 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) { 5349 if (visible) { 5350 if (!mDisplayContent.isSleeping() || canShowWhenLocked()) { 5351 mTransitionController.onVisibleWithoutCollectingTransition(this, 5352 Debug.getCallers(1, 1)); 5353 } 5354 } else if (!mDisplayContent.isSleeping()) { 5355 Slog.w(TAG, "Set invisible without transition " + this); 5356 } 5357 } 5358 } 5359 } 5360 5361 onChildVisibilityRequested(visible); 5362 5363 final DisplayContent displayContent = getDisplayContent(); 5364 displayContent.mOpeningApps.remove(this); 5365 displayContent.mClosingApps.remove(this); 5366 waitingToShow = false; 5367 setVisibleRequested(visible); 5368 mLastDeferHidingClient = deferHidingClient; 5369 5370 if (!visible) { 5371 // If this activity is about to finish/stopped and now becomes invisible, remove it 5372 // from the unknownApp list in case the activity does not want to draw anything, which 5373 // keep the user waiting for the next transition to start. 5374 if (finishing || isState(STOPPED)) { 5375 displayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this); 5376 } 5377 // Because starting window was transferred, this activity may be a trampoline which has 5378 // been occluded by next activity. If it has added windows, set client visibility 5379 // immediately to avoid the client getting RELAYOUT_RES_FIRST_TIME from relayout and 5380 // drawing an unnecessary frame. 5381 if (startingMoved && !firstWindowDrawn && hasChild()) { 5382 setClientVisible(false); 5383 } 5384 } else { 5385 if (!appTransition.isTransitionSet() 5386 && appTransition.isReady()) { 5387 // Add the app mOpeningApps if transition is unset but ready. This means 5388 // we're doing a screen freeze, and the unfreeze will wait for all opening 5389 // apps to be ready. 5390 displayContent.mOpeningApps.add(this); 5391 } 5392 startingMoved = false; 5393 // If the token is currently hidden (should be the common case), or has been 5394 // stopped, then we need to set up to wait for its windows to be ready. 5395 if (!isVisible() || mAppStopped) { 5396 clearAllDrawn(); 5397 5398 // If the app was already visible, don't reset the waitingToShow state. 5399 if (!isVisible()) { 5400 waitingToShow = true; 5401 5402 // If the client isn't hidden, we don't need to reset the drawing state. 5403 if (!isClientVisible()) { 5404 // Let's reset the draw state in order to prevent the starting window to be 5405 // immediately dismissed when the app still has the surface. 5406 forAllWindows(w -> { 5407 if (w.mWinAnimator.mDrawState == HAS_DRAWN) { 5408 w.mWinAnimator.resetDrawState(); 5409 5410 // Force add to mResizingWindows, so that we are guaranteed to get 5411 // another reportDrawn callback. 5412 w.forceReportingResized(); 5413 } 5414 }, true /* traverseTopToBottom */); 5415 } 5416 } 5417 } 5418 5419 // In the case where we are making an app visible but holding off for a transition, 5420 // we still need to tell the client to make its windows visible so they get drawn. 5421 // Otherwise, we will wait on performing the transition until all windows have been 5422 // drawn, they never will be, and we are sad. 5423 setClientVisible(true); 5424 5425 requestUpdateWallpaperIfNeeded(); 5426 5427 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "No longer Stopped: %s", this); 5428 mAppStopped = false; 5429 5430 transferStartingWindowFromHiddenAboveTokenIfNeeded(); 5431 } 5432 5433 // Defer committing visibility until transition starts. 5434 if (isCollecting) { 5435 // It may be occluded by the activity above that calls convertFromTranslucent(). 5436 if (!visible && mTransitionController.inPlayingTransition(this)) { 5437 mTransitionChangeFlags |= FLAG_IS_OCCLUDED; 5438 } 5439 return; 5440 } 5441 if (inFinishingTransition) { 5442 // Let the finishing transition commit the visibility, but let the controller know 5443 // about it so that we can recover from degenerate cases. 5444 mTransitionController.mValidateCommitVis.add(this); 5445 return; 5446 } 5447 // If we are preparing an app transition, then delay changing 5448 // the visibility of this token until we execute that transition. 5449 if (deferCommitVisibilityChange(visible)) { 5450 return; 5451 } 5452 5453 commitVisibility(visible, true /* performLayout */); 5454 updateReportedVisibilityLocked(); 5455 } 5456 5457 /** 5458 * Returns {@code true} if this activity is either added to opening-apps or closing-apps. 5459 * Then its visibility will be committed until the transition is ready. 5460 */ deferCommitVisibilityChange(boolean visible)5461 private boolean deferCommitVisibilityChange(boolean visible) { 5462 if (mTransitionController.isShellTransitionsEnabled()) { 5463 // Shell transition doesn't use opening/closing sets. 5464 return false; 5465 } 5466 if (!mDisplayContent.mAppTransition.isTransitionSet()) { 5467 // Defer committing visibility for non-home app which is animating by recents. 5468 if (isActivityTypeHome() || !isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) { 5469 return false; 5470 } 5471 } 5472 if (mWaitForEnteringPinnedMode && mVisible == visible) { 5473 // If the visibility is not changed during enter PIP, we don't want to include it in 5474 // app transition to affect the animation theme, because the Pip organizer will 5475 // animate the entering PIP instead. 5476 return false; 5477 } 5478 5479 // The animation will be visible soon so do not skip by screen off. 5480 final boolean ignoreScreenOn = canTurnScreenOn() || mTaskSupervisor.getKeyguardController() 5481 .isKeyguardGoingAway(mDisplayContent.mDisplayId); 5482 // Ignore display frozen so the opening / closing transition type can be updated correctly 5483 // even if the display is frozen. And it's safe since in applyAnimation will still check 5484 // DC#okToAnimate again if the transition animation is fine to apply. 5485 if (!okToAnimate(true /* ignoreFrozen */, ignoreScreenOn)) { 5486 return false; 5487 } 5488 if (visible) { 5489 mDisplayContent.mOpeningApps.add(this); 5490 mEnteringAnimation = true; 5491 } else if (mVisible) { 5492 mDisplayContent.mClosingApps.add(this); 5493 mEnteringAnimation = false; 5494 } 5495 if ((mDisplayContent.mAppTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0) { 5496 // Add the launching-behind activity to mOpeningApps. 5497 final WindowState win = mDisplayContent.findFocusedWindow(); 5498 if (win != null) { 5499 final ActivityRecord focusedActivity = win.mActivityRecord; 5500 if (focusedActivity != null) { 5501 ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, 5502 "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps", 5503 focusedActivity); 5504 // Force animation to be loaded. 5505 mDisplayContent.mOpeningApps.add(focusedActivity); 5506 } 5507 } 5508 } 5509 return true; 5510 } 5511 5512 @Override applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources)5513 boolean applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter, 5514 boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) { 5515 if ((mTransitionChangeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) { 5516 return false; 5517 } 5518 // If it was set to true, reset the last request to force the transition. 5519 mRequestForceTransition = false; 5520 return super.applyAnimation(lp, transit, enter, isVoiceInteraction, sources); 5521 } 5522 5523 /** 5524 * Update visibility to this {@link ActivityRecord}. 5525 * 5526 * <p class="note"><strong>Note: </strong> Unlike {@link #setVisibility}, this immediately 5527 * updates the visibility without starting an app transition. Since this function may start 5528 * animation on {@link WindowState} depending on app transition animation status, an app 5529 * transition animation must be started before calling this function if necessary.</p> 5530 * 5531 * @param visible {@code true} if this {@link ActivityRecord} should become visible, otherwise 5532 * this should become invisible. 5533 * @param performLayout if {@code true}, perform surface placement after committing visibility. 5534 * @param fromTransition {@code true} if this is part of finishing a transition. 5535 */ commitVisibility(boolean visible, boolean performLayout, boolean fromTransition)5536 void commitVisibility(boolean visible, boolean performLayout, boolean fromTransition) { 5537 // Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually 5538 // been set by the app now. 5539 mVisibleSetFromTransferredStartingWindow = false; 5540 if (visible == isVisible()) { 5541 return; 5542 } 5543 5544 final int windowsCount = mChildren.size(); 5545 // With Shell-Transition, the activity will running a transition when it is visible. 5546 // It won't be included when fromTransition is true means the call from finishTransition. 5547 final boolean runningAnimation = sEnableShellTransitions ? visible 5548 : isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION); 5549 for (int i = 0; i < windowsCount; i++) { 5550 mChildren.get(i).onAppVisibilityChanged(visible, runningAnimation); 5551 } 5552 setVisible(visible); 5553 setVisibleRequested(visible); 5554 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "commitVisibility: %s: visible=%b" 5555 + " visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s", 5556 this, isVisible(), mVisibleRequested, isInTransition(), runningAnimation, 5557 Debug.getCallers(5)); 5558 if (!visible) { 5559 stopFreezingScreen(true, true); 5560 } else { 5561 // If we are being set visible, and the starting window is not yet displayed, 5562 // then make sure it doesn't get displayed. 5563 if (mStartingWindow != null && !mStartingWindow.isDrawn() 5564 && (firstWindowDrawn || allDrawn)) { 5565 mStartingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY); 5566 mStartingWindow.mLegacyPolicyVisibilityAfterAnim = false; 5567 } 5568 // We are becoming visible, so better freeze the screen with the windows that are 5569 // getting visible so we also wait for them. 5570 forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true); 5571 } 5572 // dispatchTaskInfoChangedIfNeeded() right after ActivityRecord#setVisibility() can report 5573 // the stale visible state, because the state will be updated after the app transition. 5574 // So tries to report the actual visible state again where the state is changed. 5575 Task task = getOrganizedTask(); 5576 while (task != null) { 5577 task.dispatchTaskInfoChangedIfNeeded(false /* force */); 5578 task = task.getParent().asTask(); 5579 } 5580 final DisplayContent displayContent = getDisplayContent(); 5581 displayContent.getInputMonitor().setUpdateInputWindowsNeededLw(); 5582 if (performLayout) { 5583 mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 5584 false /*updateInputWindows*/); 5585 mWmService.mWindowPlacerLocked.performSurfacePlacement(); 5586 } 5587 displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/); 5588 mTransitionChangeFlags = 0; 5589 5590 postApplyAnimation(visible, fromTransition); 5591 } 5592 commitVisibility(boolean visible, boolean performLayout)5593 void commitVisibility(boolean visible, boolean performLayout) { 5594 commitVisibility(visible, performLayout, false /* fromTransition */); 5595 } 5596 setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation)5597 void setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation) { 5598 mNeedsLetterboxedAnimation = needsLetterboxedAnimation; 5599 } 5600 isNeedsLetterboxedAnimation()5601 boolean isNeedsLetterboxedAnimation() { 5602 return mNeedsLetterboxedAnimation; 5603 } 5604 isInLetterboxAnimation()5605 boolean isInLetterboxAnimation() { 5606 return mNeedsLetterboxedAnimation && isAnimating(); 5607 } 5608 5609 /** 5610 * Post process after applying an app transition animation. 5611 * 5612 * <p class="note"><strong>Note: </strong> This function must be called after the animations 5613 * have been applied and {@link #commitVisibility}.</p> 5614 * 5615 * @param visible {@code true} if this {@link ActivityRecord} has become visible, otherwise 5616 * this has become invisible. 5617 * @param fromTransition {@code true} if this call is part of finishing a transition. This is 5618 * needed because the shell transition is no-longer active by the time 5619 * commitVisibility is called. 5620 */ postApplyAnimation(boolean visible, boolean fromTransition)5621 private void postApplyAnimation(boolean visible, boolean fromTransition) { 5622 final boolean usingShellTransitions = mTransitionController.isShellTransitionsEnabled(); 5623 final boolean delayed = !usingShellTransitions && isAnimating(PARENTS | CHILDREN, 5624 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION 5625 | ANIMATION_TYPE_RECENTS); 5626 if (!delayed && !usingShellTransitions) { 5627 // We aren't delayed anything, but exiting windows rely on the animation finished 5628 // callback being called in case the ActivityRecord was pretending to be delayed, 5629 // which we might have done because we were in closing/opening apps list. 5630 onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, null /* AnimationAdapter */); 5631 if (visible) { 5632 // The token was made immediately visible, there will be no entrance animation. 5633 // We need to inform the client the enter animation was finished. 5634 mEnteringAnimation = true; 5635 mWmService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked( 5636 token); 5637 } 5638 } 5639 5640 // If we're becoming visible, immediately change client visibility as well. there seem 5641 // to be some edge cases where we change our visibility but client visibility never gets 5642 // updated. 5643 // If we're becoming invisible, update the client visibility if we are not running an 5644 // animation and aren't in RESUMED state. Otherwise, we'll update client visibility in 5645 // onAnimationFinished or activityStopped. 5646 if (visible || (mState != RESUMED && (usingShellTransitions || !isAnimating( 5647 PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)))) { 5648 setClientVisible(visible); 5649 } 5650 5651 final DisplayContent displayContent = getDisplayContent(); 5652 if (!visible) { 5653 mImeInsetsFrozenUntilStartInput = true; 5654 } 5655 5656 if (!displayContent.mClosingApps.contains(this) 5657 && !displayContent.mOpeningApps.contains(this) 5658 && !fromTransition) { 5659 // Take the screenshot before possibly hiding the WSA, otherwise the screenshot 5660 // will not be taken. 5661 mWmService.mSnapshotController.notifyAppVisibilityChanged(this, visible); 5662 } 5663 5664 // If we are hidden but there is no delay needed we immediately 5665 // apply the Surface transaction so that the ActivityManager 5666 // can have some guarantee on the Surface state following 5667 // setting the visibility. This captures cases like dismissing 5668 // the docked or root pinned task where there is no app transition. 5669 // 5670 // In the case of a "Null" animation, there will be 5671 // no animation but there will still be a transition set. 5672 // We still need to delay hiding the surface such that it 5673 // can be synchronized with showing the next surface in the transition. 5674 if (!usingShellTransitions && !isVisible() && !delayed 5675 && !displayContent.mAppTransition.isTransitionSet()) { 5676 SurfaceControl.openTransaction(); 5677 try { 5678 forAllWindows(win -> { 5679 win.mWinAnimator.hide(getGlobalTransaction(), "immediately hidden"); 5680 }, true); 5681 } finally { 5682 SurfaceControl.closeTransaction(); 5683 } 5684 } 5685 } 5686 5687 /** Updates draw state and shows drawn windows. */ commitFinishDrawing(SurfaceControl.Transaction t)5688 void commitFinishDrawing(SurfaceControl.Transaction t) { 5689 boolean committed = false; 5690 for (int i = mChildren.size() - 1; i >= 0; i--) { 5691 committed |= mChildren.get(i).commitFinishDrawing(t); 5692 } 5693 if (committed) { 5694 requestUpdateWallpaperIfNeeded(); 5695 } 5696 } 5697 5698 /** 5699 * Check if visibility of this {@link ActivityRecord} should be updated as part of an app 5700 * transition. 5701 * 5702 * <p class="note><strong>Note:</strong> If the visibility of this {@link ActivityRecord} is 5703 * already set to {@link #mVisible}, we don't need to update the visibility. So {@code false} is 5704 * returned.</p> 5705 * 5706 * @param visible {@code true} if this {@link ActivityRecord} should become visible, 5707 * {@code false} if this should become invisible. 5708 * @return {@code true} if visibility of this {@link ActivityRecord} should be updated, and 5709 * an app transition animation should be run. 5710 */ shouldApplyAnimation(boolean visible)5711 boolean shouldApplyAnimation(boolean visible) { 5712 // Allow for state update and animation to be applied if: 5713 // * activity is transitioning visibility state 5714 // * or the activity was marked as hidden and is exiting before we had a chance to play the 5715 // transition animation 5716 return isVisible() != visible || mRequestForceTransition || (!isVisible() && mIsExiting); 5717 } 5718 5719 /** 5720 * See {@link Activity#setRecentsScreenshotEnabled}. 5721 */ setRecentsScreenshotEnabled(boolean enabled)5722 void setRecentsScreenshotEnabled(boolean enabled) { 5723 mEnableRecentsScreenshot = enabled; 5724 } 5725 5726 /** 5727 * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is 5728 * the case when preview screenshots are disabled {@link #setRecentsScreenshotEnabled} or when 5729 * we can't take a snapshot for other reasons, for example, if we have a secure window. 5730 * 5731 * @return True if we need to generate an app theme snapshot, false if we'd like to take a real 5732 * screenshot. 5733 */ shouldUseAppThemeSnapshot()5734 boolean shouldUseAppThemeSnapshot() { 5735 return !mEnableRecentsScreenshot || forAllWindows(WindowState::isSecureLocked, 5736 true /* topToBottom */); 5737 } 5738 5739 /** 5740 * Sets whether the current launch can turn the screen on. 5741 * @see #currentLaunchCanTurnScreenOn() 5742 */ setCurrentLaunchCanTurnScreenOn(boolean currentLaunchCanTurnScreenOn)5743 void setCurrentLaunchCanTurnScreenOn(boolean currentLaunchCanTurnScreenOn) { 5744 mCurrentLaunchCanTurnScreenOn = currentLaunchCanTurnScreenOn; 5745 } 5746 5747 /** 5748 * Indicates whether the current launch can turn the screen on. This is to prevent multiple 5749 * relayouts from turning the screen back on. The screen should only turn on at most 5750 * once per activity resume. 5751 * <p> 5752 * Note this flag is only meaningful when {@link WindowManager.LayoutParams#FLAG_TURN_SCREEN_ON} 5753 * or {@link ActivityRecord#canTurnScreenOn} is set. 5754 * 5755 * @return {@code true} if the activity is ready to turn on the screen. 5756 */ currentLaunchCanTurnScreenOn()5757 boolean currentLaunchCanTurnScreenOn() { 5758 return mCurrentLaunchCanTurnScreenOn; 5759 } 5760 setState(State state, String reason)5761 void setState(State state, String reason) { 5762 ProtoLog.v(WM_DEBUG_STATES, "State movement: %s from:%s to:%s reason:%s", 5763 this, getState(), state, reason); 5764 5765 if (state == mState) { 5766 // No need to do anything if state doesn't change. 5767 ProtoLog.v(WM_DEBUG_STATES, "State unchanged from:%s", state); 5768 return; 5769 } 5770 5771 mState = state; 5772 5773 if (getTaskFragment() != null) { 5774 getTaskFragment().onActivityStateChanged(this, state, reason); 5775 } 5776 5777 // The WindowManager interprets the app stopping signal as 5778 // an indication that the Surface will eventually be destroyed. 5779 // This however isn't necessarily true if we are going to sleep. 5780 if (state == STOPPING && !isSleeping()) { 5781 if (getParent() == null) { 5782 Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: " 5783 + token); 5784 return; 5785 } 5786 } 5787 updateVisibleForServiceConnection(); 5788 if (app != null) { 5789 mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */); 5790 } 5791 5792 switch (state) { 5793 case RESUMED: 5794 mAtmService.updateBatteryStats(this, true); 5795 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED); 5796 // Fall through. 5797 case STARTED: 5798 // Update process info while making an activity from invisible to visible, to make 5799 // sure the process state is updated to foreground. 5800 if (app != null) { 5801 app.updateProcessInfo(false /* updateServiceConnectionActivities */, 5802 true /* activityChange */, true /* updateOomAdj */, 5803 true /* addPendingTopUid */); 5804 } 5805 final ContentCaptureManagerInternal contentCaptureService = 5806 LocalServices.getService(ContentCaptureManagerInternal.class); 5807 if (contentCaptureService != null) { 5808 contentCaptureService.notifyActivityEvent(mUserId, mActivityComponent, 5809 ActivityEvent.TYPE_ACTIVITY_STARTED, 5810 new ActivityId(getTask() != null ? getTask().mTaskId : INVALID_TASK_ID, 5811 shareableActivityToken)); 5812 } 5813 break; 5814 case PAUSED: 5815 mAtmService.updateBatteryStats(this, false); 5816 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED); 5817 break; 5818 case STOPPED: 5819 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED); 5820 break; 5821 case DESTROYED: 5822 if (app != null && (mVisible || mVisibleRequested)) { 5823 // The app may be died while visible (no PAUSED state). 5824 mAtmService.updateBatteryStats(this, false); 5825 } 5826 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED); 5827 // Fall through. 5828 case DESTROYING: 5829 if (app != null && !app.hasActivities()) { 5830 // Update any services we are bound to that might care about whether 5831 // their client may have activities. 5832 // No longer have activities, so update LRU list and oom adj. 5833 app.updateProcessInfo(true /* updateServiceConnectionActivities */, 5834 false /* activityChange */, true /* updateOomAdj */, 5835 false /* addPendingTopUid */); 5836 } 5837 break; 5838 } 5839 } 5840 getState()5841 State getState() { 5842 return mState; 5843 } 5844 5845 /** 5846 * Returns {@code true} if the Activity is in the specified state. 5847 */ isState(State state)5848 boolean isState(State state) { 5849 return state == mState; 5850 } 5851 5852 /** 5853 * Returns {@code true} if the Activity is in one of the specified states. 5854 */ isState(State state1, State state2)5855 boolean isState(State state1, State state2) { 5856 return state1 == mState || state2 == mState; 5857 } 5858 5859 /** 5860 * Returns {@code true} if the Activity is in one of the specified states. 5861 */ isState(State state1, State state2, State state3)5862 boolean isState(State state1, State state2, State state3) { 5863 return state1 == mState || state2 == mState || state3 == mState; 5864 } 5865 5866 /** 5867 * Returns {@code true} if the Activity is in one of the specified states. 5868 */ isState(State state1, State state2, State state3, State state4)5869 boolean isState(State state1, State state2, State state3, State state4) { 5870 return state1 == mState || state2 == mState || state3 == mState || state4 == mState; 5871 } 5872 5873 /** 5874 * Returns {@code true} if the Activity is in one of the specified states. 5875 */ isState(State state1, State state2, State state3, State state4, State state5)5876 boolean isState(State state1, State state2, State state3, State state4, State state5) { 5877 return state1 == mState || state2 == mState || state3 == mState || state4 == mState 5878 || state5 == mState; 5879 } 5880 5881 /** 5882 * Returns {@code true} if the Activity is in one of the specified states. 5883 */ isState(State state1, State state2, State state3, State state4, State state5, State state6)5884 boolean isState(State state1, State state2, State state3, State state4, State state5, 5885 State state6) { 5886 return state1 == mState || state2 == mState || state3 == mState || state4 == mState 5887 || state5 == mState || state6 == mState; 5888 } 5889 destroySurfaces()5890 void destroySurfaces() { 5891 destroySurfaces(false /*cleanupOnResume*/); 5892 } 5893 5894 /** 5895 * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure 5896 * the client has finished with them. 5897 * 5898 * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If 5899 * set to true, destroy only surfaces of removed windows, and clear relevant flags of the 5900 * others so that they are ready to be reused. If set to false (common case), destroy all 5901 * surfaces that's eligible, if the app is already stopped. 5902 */ destroySurfaces(boolean cleanupOnResume)5903 private void destroySurfaces(boolean cleanupOnResume) { 5904 boolean destroyedSomething = false; 5905 5906 // Copying to a different list as multiple children can be removed. 5907 final ArrayList<WindowState> children = new ArrayList<>(mChildren); 5908 for (int i = children.size() - 1; i >= 0; i--) { 5909 final WindowState win = children.get(i); 5910 destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped); 5911 } 5912 if (destroyedSomething) { 5913 final DisplayContent dc = getDisplayContent(); 5914 dc.assignWindowLayers(true /*setLayoutNeeded*/); 5915 updateLetterboxSurface(null); 5916 } 5917 } 5918 notifyAppResumed()5919 void notifyAppResumed() { 5920 if (getParent() == null) { 5921 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token); 5922 return; 5923 } 5924 final boolean wasStopped = mAppStopped; 5925 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppResumed: wasStopped=%b %s", 5926 wasStopped, this); 5927 mAppStopped = false; 5928 // Allow the window to turn the screen on once the app is started and resumed. 5929 if (mAtmService.getActivityStartController().isInExecution()) { 5930 setCurrentLaunchCanTurnScreenOn(true); 5931 } 5932 5933 if (!wasStopped) { 5934 destroySurfaces(true /*cleanupOnResume*/); 5935 } 5936 } 5937 5938 /** 5939 * Suppress transition until the new activity becomes ready, otherwise the keyguard can appear 5940 * for a short amount of time before the new process with the new activity had the ability to 5941 * set its showWhenLocked flags. 5942 */ notifyUnknownVisibilityLaunchedForKeyguardTransition()5943 void notifyUnknownVisibilityLaunchedForKeyguardTransition() { 5944 // No display activities never add a window, so there is no point in waiting them for 5945 // relayout. 5946 if (noDisplay || !isKeyguardLocked()) { 5947 return; 5948 } 5949 5950 mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(this); 5951 } 5952 5953 /** @return {@code true} if this activity should be made visible. */ shouldBeVisible(boolean behindOccludedContainer, boolean ignoringKeyguard)5954 private boolean shouldBeVisible(boolean behindOccludedContainer, boolean ignoringKeyguard) { 5955 updateVisibilityIgnoringKeyguard(behindOccludedContainer); 5956 5957 if (ignoringKeyguard) { 5958 return visibleIgnoringKeyguard; 5959 } 5960 5961 return shouldBeVisibleUnchecked(); 5962 } 5963 shouldBeVisibleUnchecked()5964 boolean shouldBeVisibleUnchecked() { 5965 final Task rootTask = getRootTask(); 5966 if (rootTask == null || !visibleIgnoringKeyguard) { 5967 return false; 5968 } 5969 5970 // Activity in a root pinned task should not be visible if the root task is in force 5971 // hidden state. 5972 // Typically due to the FLAG_FORCE_HIDDEN_FOR_PINNED_TASK set on the root task, which is a 5973 // work around to send onStop before windowing mode change callbacks. 5974 // See also ActivityTaskSupervisor#removePinnedRootTaskInSurfaceTransaction 5975 // TODO: Should we ever be visible if the rootTask/task is invisible? 5976 if (inPinnedWindowingMode() && rootTask.isForceHidden()) { 5977 return false; 5978 } 5979 5980 // Untrusted embedded activity can be visible only if there is no other overlay window. 5981 if (hasOverlayOverUntrustedModeEmbedded()) { 5982 return false; 5983 } 5984 5985 // Check if the activity is on a sleeping display, canTurnScreenOn will also check 5986 // keyguard visibility 5987 if (mDisplayContent.isSleeping()) { 5988 return canTurnScreenOn(); 5989 } else { 5990 return mTaskSupervisor.getKeyguardController().checkKeyguardVisibility(this); 5991 } 5992 } 5993 5994 /** 5995 * Checks if there are any activities or other containers that belong to the same task on top of 5996 * this activity when embedded in untrusted mode. 5997 */ hasOverlayOverUntrustedModeEmbedded()5998 boolean hasOverlayOverUntrustedModeEmbedded() { 5999 if (!isEmbeddedInUntrustedMode() || getTask() == null) { 6000 // The activity is not embedded in untrusted mode. 6001 return false; 6002 } 6003 6004 // Check if there are any activities with different UID over the activity that is embedded 6005 // in untrusted mode. Traverse bottom to top with boundary so that it will only check 6006 // activities above this activity. 6007 final ActivityRecord differentUidOverlayActivity = getTask().getActivity( 6008 a -> !a.finishing && a.getUid() != getUid(), this /* boundary */, 6009 false /* includeBoundary */, false /* traverseTopToBottom */); 6010 return differentUidOverlayActivity != null; 6011 } 6012 updateVisibilityIgnoringKeyguard(boolean behindOccludedContainer)6013 void updateVisibilityIgnoringKeyguard(boolean behindOccludedContainer) { 6014 visibleIgnoringKeyguard = (!behindOccludedContainer || mLaunchTaskBehind) 6015 && showToCurrentUser(); 6016 } 6017 shouldBeVisible()6018 boolean shouldBeVisible() { 6019 final Task task = getTask(); 6020 if (task == null) { 6021 return false; 6022 } 6023 6024 final boolean behindOccludedContainer = !task.shouldBeVisible(null /* starting */) 6025 || task.getOccludingActivityAbove(this) != null; 6026 return shouldBeVisible(behindOccludedContainer, false /* ignoringKeyguard */); 6027 } 6028 makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient)6029 void makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient) { 6030 // This activity is not currently visible, but is running. Tell it to become visible. 6031 if ((mState == RESUMED && mVisibleRequested) || this == starting) { 6032 if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, 6033 "Not making visible, r=" + this + " state=" + mState + " starting=" + starting); 6034 return; 6035 } 6036 6037 // If this activity is paused, tell it to now show its window. 6038 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, 6039 "Making visible and scheduling visibility: " + this); 6040 final Task rootTask = getRootTask(); 6041 try { 6042 if (rootTask.mTranslucentActivityWaiting != null) { 6043 updateOptionsLocked(returningOptions); 6044 rootTask.mUndrawnActivitiesBelowTopTranslucent.add(this); 6045 } 6046 setVisibility(true); 6047 app.postPendingUiCleanMsg(true); 6048 if (reportToClient) { 6049 mClientVisibilityDeferred = false; 6050 makeActiveIfNeeded(starting); 6051 } else { 6052 mClientVisibilityDeferred = true; 6053 } 6054 // The activity may be waiting for stop, but that is no longer appropriate for it. 6055 mTaskSupervisor.mStoppingActivities.remove(this); 6056 } catch (Exception e) { 6057 // Just skip on any failure; we'll make it visible when it next restarts. 6058 Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e); 6059 } 6060 handleAlreadyVisible(); 6061 } 6062 makeInvisible()6063 void makeInvisible() { 6064 if (!mVisibleRequested) { 6065 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this); 6066 return; 6067 } 6068 // Now for any activities that aren't visible to the user, make sure they no longer are 6069 // keeping the screen frozen. 6070 if (DEBUG_VISIBILITY) { 6071 Slog.v(TAG_VISIBILITY, "Making invisible: " + this + ", state=" + getState()); 6072 } 6073 try { 6074 final boolean canEnterPictureInPicture = checkEnterPictureInPictureState( 6075 "makeInvisible", true /* beforeStopping */); 6076 // Defer telling the client it is hidden if it can enter Pip and isn't current paused, 6077 // stopped or stopping. This gives it a chance to enter Pip in onPause(). 6078 final boolean deferHidingClient = canEnterPictureInPicture 6079 && !isState(STARTED, STOPPING, STOPPED, PAUSED); 6080 setDeferHidingClient(deferHidingClient); 6081 setVisibility(false); 6082 6083 switch (getState()) { 6084 case STOPPING: 6085 case STOPPED: 6086 // Reset the flag indicating that an app can enter picture-in-picture once the 6087 // activity is hidden 6088 supportsEnterPipOnTaskSwitch = false; 6089 break; 6090 case RESUMED: 6091 case INITIALIZING: 6092 case PAUSING: 6093 case PAUSED: 6094 case STARTED: 6095 addToStopping(true /* scheduleIdle */, 6096 canEnterPictureInPicture /* idleDelayed */, "makeInvisible"); 6097 break; 6098 6099 default: 6100 break; 6101 } 6102 } catch (Exception e) { 6103 // Just skip on any failure; we'll make it visible when it next restarts. 6104 Slog.w(TAG, "Exception thrown making hidden: " + intent.getComponent(), e); 6105 } 6106 } 6107 6108 /** 6109 * Make activity resumed or paused if needed. 6110 * @param activeActivity an activity that is resumed or just completed pause action. 6111 * We won't change the state of this activity. 6112 */ makeActiveIfNeeded(ActivityRecord activeActivity)6113 boolean makeActiveIfNeeded(ActivityRecord activeActivity) { 6114 if (shouldResumeActivity(activeActivity)) { 6115 if (DEBUG_VISIBILITY) { 6116 Slog.v(TAG_VISIBILITY, "Resume visible activity, " + this); 6117 } 6118 return getRootTask().resumeTopActivityUncheckedLocked(activeActivity /* prev */, 6119 null /* options */); 6120 } else if (shouldPauseActivity(activeActivity)) { 6121 if (DEBUG_VISIBILITY) { 6122 Slog.v(TAG_VISIBILITY, "Pause visible activity, " + this); 6123 } 6124 // An activity must be in the {@link PAUSING} state for the system to validate 6125 // the move to {@link PAUSED}. 6126 setState(PAUSING, "makeActiveIfNeeded"); 6127 EventLogTags.writeWmPauseActivity(mUserId, System.identityHashCode(this), 6128 shortComponentName, "userLeaving=false", "make-active"); 6129 try { 6130 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, 6131 PauseActivityItem.obtain(finishing, false /* userLeaving */, 6132 configChangeFlags, false /* dontReport */, mAutoEnteringPip)); 6133 } catch (Exception e) { 6134 Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e); 6135 } 6136 } else if (shouldStartActivity()) { 6137 if (DEBUG_VISIBILITY) { 6138 Slog.v(TAG_VISIBILITY, "Start visible activity, " + this); 6139 } 6140 setState(STARTED, "makeActiveIfNeeded"); 6141 6142 try { 6143 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, 6144 StartActivityItem.obtain(takeOptions())); 6145 } catch (Exception e) { 6146 Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e); 6147 } 6148 // The activity may be waiting for stop, but that is no longer appropriate if we are 6149 // starting the activity again 6150 mTaskSupervisor.mStoppingActivities.remove(this); 6151 } 6152 return false; 6153 } 6154 6155 /** 6156 * Check if activity should be moved to PAUSED state. The activity: 6157 * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)}) 6158 * - should be non-focusable 6159 * - should not be currently pausing or paused 6160 * @param activeActivity the activity that is active or just completed pause action. We won't 6161 * resume if this activity is active. 6162 */ 6163 @VisibleForTesting shouldPauseActivity(ActivityRecord activeActivity)6164 boolean shouldPauseActivity(ActivityRecord activeActivity) { 6165 return shouldMakeActive(activeActivity) && !isFocusable() && !isState(PAUSING, PAUSED) 6166 // We will only allow pausing if results is null, otherwise it will cause this 6167 // activity to resume before getting result 6168 && (results == null); 6169 } 6170 6171 /** 6172 * Check if activity should be moved to RESUMED state. 6173 * See {@link #shouldBeResumed(ActivityRecord)} 6174 * @param activeActivity the activity that is active or just completed pause action. We won't 6175 * resume if this activity is active. 6176 */ 6177 @VisibleForTesting shouldResumeActivity(ActivityRecord activeActivity)6178 boolean shouldResumeActivity(ActivityRecord activeActivity) { 6179 return shouldBeResumed(activeActivity) && !isState(RESUMED); 6180 } 6181 6182 /** 6183 * Check if activity should be RESUMED now. The activity: 6184 * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)}) 6185 * - should be focusable 6186 */ shouldBeResumed(ActivityRecord activeActivity)6187 private boolean shouldBeResumed(ActivityRecord activeActivity) { 6188 return shouldMakeActive(activeActivity) && isFocusable() 6189 && getTaskFragment().getVisibility(activeActivity) 6190 == TASK_FRAGMENT_VISIBILITY_VISIBLE 6191 && canResumeByCompat(); 6192 } 6193 6194 /** 6195 * Check if activity should be moved to STARTED state. 6196 * NOTE: This will not check if activity should be made paused or resumed first, so it must only 6197 * be called after checking with {@link #shouldResumeActivity(ActivityRecord)} 6198 * and {@link #shouldPauseActivity(ActivityRecord)}. 6199 */ shouldStartActivity()6200 private boolean shouldStartActivity() { 6201 return mVisibleRequested && (isState(STOPPED) || isState(STOPPING)); 6202 } 6203 6204 /** 6205 * Check if activity is eligible to be made active (resumed of paused). The activity: 6206 * - should be paused, stopped or stopping 6207 * - should not be the currently active one or launching behind other tasks 6208 * - should be either the topmost in task, or right below the top activity that is finishing 6209 * If all of these conditions are not met at the same time, the activity cannot be made active. 6210 */ 6211 @VisibleForTesting shouldMakeActive(ActivityRecord activeActivity)6212 boolean shouldMakeActive(ActivityRecord activeActivity) { 6213 // If the activity is stopped, stopping, cycle to an active state. We avoid doing 6214 // this when there is an activity waiting to become translucent as the extra binder 6215 // calls will lead to noticeable jank. A later call to 6216 // Task#ensureActivitiesVisible will bring the activity to a proper 6217 // active state. 6218 if (!isState(STARTED, RESUMED, PAUSED, STOPPED, STOPPING) 6219 // TODO (b/185876784) Check could we remove the check condition 6220 // mTranslucentActivityWaiting != null here 6221 || getRootTask().mTranslucentActivityWaiting != null) { 6222 return false; 6223 } 6224 6225 if (this == activeActivity) { 6226 return false; 6227 } 6228 6229 if (!mTaskSupervisor.readyToResume()) { 6230 // Making active is currently deferred (e.g. because an activity launch is in progress). 6231 return false; 6232 } 6233 6234 if (this.mLaunchTaskBehind) { 6235 // This activity is being launched from behind, which means that it's not intended to be 6236 // presented to user right now, even if it's set to be visible. 6237 return false; 6238 } 6239 6240 // Check if position in task allows to become paused 6241 if (!task.hasChild(this)) { 6242 throw new IllegalStateException("Activity not found in its task"); 6243 } 6244 return getTaskFragment().topRunningActivity() == this; 6245 } 6246 handleAlreadyVisible()6247 void handleAlreadyVisible() { 6248 stopFreezingScreenLocked(false); 6249 try { 6250 if (returningOptions != null) { 6251 app.getThread().scheduleOnNewActivityOptions(token, returningOptions.toBundle()); 6252 } 6253 } catch(RemoteException e) { 6254 } 6255 } 6256 activityResumedLocked(IBinder token, boolean handleSplashScreenExit)6257 static void activityResumedLocked(IBinder token, boolean handleSplashScreenExit) { 6258 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 6259 ProtoLog.i(WM_DEBUG_STATES, "Resumed activity; dropping state of: %s", r); 6260 if (r == null) { 6261 // If an app reports resumed after a long delay, the record on server side might have 6262 // been removed (e.g. destroy timeout), so the token could be null. 6263 return; 6264 } 6265 r.setCustomizeSplashScreenExitAnimation(handleSplashScreenExit); 6266 r.setSavedState(null /* savedState */); 6267 6268 r.mDisplayContent.handleActivitySizeCompatModeIfNeeded(r); 6269 r.mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(r); 6270 } 6271 activityRefreshedLocked(IBinder token)6272 static void activityRefreshedLocked(IBinder token) { 6273 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 6274 ProtoLog.i(WM_DEBUG_STATES, "Refreshed activity: %s", r); 6275 if (r == null) { 6276 // In case the record on server side has been removed (e.g. destroy timeout) 6277 // and the token could be null. 6278 return; 6279 } 6280 if (r.mDisplayContent.mDisplayRotationCompatPolicy != null) { 6281 r.mDisplayContent.mDisplayRotationCompatPolicy.onActivityRefreshed(r); 6282 } 6283 } 6284 splashScreenAttachedLocked(IBinder token)6285 static void splashScreenAttachedLocked(IBinder token) { 6286 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 6287 if (r == null) { 6288 Slog.w(TAG, "splashScreenTransferredLocked cannot find activity"); 6289 return; 6290 } 6291 r.onSplashScreenAttachComplete(); 6292 } 6293 6294 /** 6295 * Once we know that we have asked an application to put an activity in the resumed state 6296 * (either by launching it or explicitly telling it), this function updates the rest of our 6297 * state to match that fact. 6298 */ completeResumeLocked()6299 void completeResumeLocked() { 6300 final boolean wasVisible = mVisibleRequested; 6301 setVisibility(true); 6302 if (!wasVisible) { 6303 // Visibility has changed, so take a note of it so we call the TaskStackChangedListener 6304 mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true; 6305 } 6306 idle = false; 6307 results = null; 6308 if (newIntents != null && newIntents.size() > 0) { 6309 mLastNewIntent = newIntents.get(newIntents.size() - 1); 6310 } 6311 newIntents = null; 6312 6313 if (isActivityTypeHome()) { 6314 mTaskSupervisor.updateHomeProcess(task.getBottomMostActivity().app); 6315 } 6316 6317 if (nowVisible) { 6318 mTaskSupervisor.stopWaitingForActivityVisible(this); 6319 } 6320 6321 // Schedule an idle timeout in case the app doesn't do it for us. 6322 mTaskSupervisor.scheduleIdleTimeout(this); 6323 6324 mTaskSupervisor.reportResumedActivityLocked(this); 6325 6326 resumeKeyDispatchingLocked(); 6327 final Task rootTask = getRootTask(); 6328 mTaskSupervisor.mNoAnimActivities.clear(); 6329 returningOptions = null; 6330 6331 if (canTurnScreenOn()) { 6332 mTaskSupervisor.wakeUp("turnScreenOnFlag"); 6333 } else { 6334 // If the screen is going to turn on because the caller explicitly requested it and 6335 // the keyguard is not showing don't attempt to sleep. Otherwise the Activity will 6336 // pause and then resume again later, which will result in a double life-cycle event. 6337 rootTask.checkReadyForSleep(); 6338 } 6339 } 6340 activityPaused(boolean timeout)6341 void activityPaused(boolean timeout) { 6342 ProtoLog.v(WM_DEBUG_STATES, "Activity paused: token=%s, timeout=%b", token, 6343 timeout); 6344 6345 final TaskFragment taskFragment = getTaskFragment(); 6346 if (taskFragment != null) { 6347 removePauseTimeout(); 6348 6349 final ActivityRecord pausingActivity = taskFragment.getPausingActivity(); 6350 if (pausingActivity == this) { 6351 ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s %s", this, 6352 (timeout ? "(due to timeout)" : " (pause complete)")); 6353 mAtmService.deferWindowLayout(); 6354 try { 6355 taskFragment.completePause(true /* resumeNext */, null /* resumingActivity */); 6356 } finally { 6357 mAtmService.continueWindowLayout(); 6358 } 6359 return; 6360 } else { 6361 EventLogTags.writeWmFailedToPause(mUserId, System.identityHashCode(this), 6362 shortComponentName, pausingActivity != null 6363 ? pausingActivity.shortComponentName : "(none)"); 6364 if (isState(PAUSING)) { 6365 setState(PAUSED, "activityPausedLocked"); 6366 if (finishing) { 6367 ProtoLog.v(WM_DEBUG_STATES, 6368 "Executing finish of failed to pause activity: %s", this); 6369 completeFinishing("activityPausedLocked"); 6370 } 6371 } 6372 } 6373 } 6374 6375 mDisplayContent.handleActivitySizeCompatModeIfNeeded(this); 6376 mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); 6377 } 6378 6379 /** 6380 * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because 6381 * this directly impacts the responsiveness seen by the user. 6382 */ schedulePauseTimeout()6383 void schedulePauseTimeout() { 6384 pauseTime = SystemClock.uptimeMillis(); 6385 mAtmService.mH.postDelayed(mPauseTimeoutRunnable, PAUSE_TIMEOUT); 6386 ProtoLog.v(WM_DEBUG_STATES, "Waiting for pause to complete..."); 6387 } 6388 removePauseTimeout()6389 private void removePauseTimeout() { 6390 mAtmService.mH.removeCallbacks(mPauseTimeoutRunnable); 6391 } 6392 removeDestroyTimeout()6393 private void removeDestroyTimeout() { 6394 mAtmService.mH.removeCallbacks(mDestroyTimeoutRunnable); 6395 } 6396 removeStopTimeout()6397 private void removeStopTimeout() { 6398 mAtmService.mH.removeCallbacks(mStopTimeoutRunnable); 6399 } 6400 removeTimeouts()6401 void removeTimeouts() { 6402 mTaskSupervisor.removeIdleTimeoutForActivity(this); 6403 removePauseTimeout(); 6404 removeStopTimeout(); 6405 removeDestroyTimeout(); 6406 finishLaunchTickingLocked(); 6407 } 6408 stopIfPossible()6409 void stopIfPossible() { 6410 if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this); 6411 final Task rootTask = getRootTask(); 6412 if (isNoHistory()) { 6413 if (!finishing) { 6414 if (!rootTask.shouldSleepActivities()) { 6415 ProtoLog.d(WM_DEBUG_STATES, "no-history finish of %s", this); 6416 if (finishIfPossible("stop-no-history", false /* oomAdj */) 6417 != FINISH_RESULT_CANCELLED) { 6418 resumeKeyDispatchingLocked(); 6419 return; 6420 } 6421 } else { 6422 ProtoLog.d(WM_DEBUG_STATES, "Not finishing noHistory %s on stop " 6423 + "because we're just sleeping", this); 6424 } 6425 } 6426 } 6427 6428 if (!attachedToProcess()) { 6429 return; 6430 } 6431 resumeKeyDispatchingLocked(); 6432 try { 6433 ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPING: %s (stop requested)", this); 6434 6435 setState(STOPPING, "stopIfPossible"); 6436 if (DEBUG_VISIBILITY) { 6437 Slog.v(TAG_VISIBILITY, "Stopping:" + this); 6438 } 6439 EventLogTags.writeWmStopActivity( 6440 mUserId, System.identityHashCode(this), shortComponentName); 6441 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, 6442 StopActivityItem.obtain(configChangeFlags)); 6443 6444 mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT); 6445 } catch (Exception e) { 6446 // Maybe just ignore exceptions here... if the process has crashed, our death 6447 // notification will clean things up. 6448 Slog.w(TAG, "Exception thrown during pause", e); 6449 // Just in case, assume it to be stopped. 6450 mAppStopped = true; 6451 ProtoLog.v(WM_DEBUG_STATES, "Stop failed; moving to STOPPED: %s", this); 6452 setState(STOPPED, "stopIfPossible"); 6453 if (deferRelaunchUntilPaused) { 6454 destroyImmediately("stop-except"); 6455 } 6456 } 6457 } 6458 6459 /** 6460 * Notifies that the activity has stopped, and it is okay to destroy any surfaces which were 6461 * keeping alive in case they were still being used. 6462 */ activityStopped(Bundle newIcicle, PersistableBundle newPersistentState, CharSequence description)6463 void activityStopped(Bundle newIcicle, PersistableBundle newPersistentState, 6464 CharSequence description) { 6465 removeStopTimeout(); 6466 final boolean isStopping = mState == STOPPING; 6467 if (!isStopping && mState != RESTARTING_PROCESS) { 6468 Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this + " " + mState); 6469 return; 6470 } 6471 if (newPersistentState != null) { 6472 mPersistentState = newPersistentState; 6473 mAtmService.notifyTaskPersisterLocked(task, false); 6474 } 6475 6476 if (newIcicle != null) { 6477 // If icicle is null, this is happening due to a timeout, so we haven't really saved 6478 // the state. 6479 setSavedState(newIcicle); 6480 launchCount = 0; 6481 updateTaskDescription(description); 6482 } 6483 ProtoLog.i(WM_DEBUG_STATES, "Saving icicle of %s: %s", this, mIcicle); 6484 6485 if (isStopping) { 6486 ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPED: %s (stop complete)", this); 6487 setState(STOPPED, "activityStopped"); 6488 } 6489 6490 mAppStopped = true; 6491 firstWindowDrawn = false; 6492 // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls 6493 // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787. 6494 // Clear any surface transactions and content overlay in this case. 6495 if (task.mLastRecentsAnimationTransaction != null) { 6496 task.clearLastRecentsAnimationTransaction(true /* forceRemoveOverlay */); 6497 } 6498 // Reset the last saved PiP snap fraction on app stop. 6499 mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent); 6500 mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this); 6501 if (isClientVisible()) { 6502 // Though this is usually unlikely to happen, still make sure the client is invisible. 6503 setClientVisible(false); 6504 } 6505 destroySurfaces(); 6506 // Remove any starting window that was added for this app if they are still around. 6507 removeStartingWindow(); 6508 6509 if (finishing) { 6510 abortAndClearOptionsAnimation(); 6511 } else { 6512 if (deferRelaunchUntilPaused) { 6513 destroyImmediately("stop-config"); 6514 mRootWindowContainer.resumeFocusedTasksTopActivities(); 6515 } else { 6516 mAtmService.updatePreviousProcess(this); 6517 } 6518 } 6519 mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */); 6520 } 6521 addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason)6522 void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) { 6523 if (!mTaskSupervisor.mStoppingActivities.contains(this)) { 6524 EventLogTags.writeWmAddToStopping(mUserId, System.identityHashCode(this), 6525 shortComponentName, reason); 6526 mTaskSupervisor.mStoppingActivities.add(this); 6527 } 6528 6529 final Task rootTask = getRootTask(); 6530 // If we already have a few activities waiting to stop, then give up on things going idle 6531 // and start clearing them out. Or if r is the last of activity of the last task the root 6532 // task will be empty and must be cleared immediately. 6533 boolean forceIdle = mTaskSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE 6534 || (isRootOfTask() && rootTask.getChildCount() <= 1); 6535 if (scheduleIdle || forceIdle) { 6536 ProtoLog.v(WM_DEBUG_STATES, 6537 "Scheduling idle now: forceIdle=%b immediate=%b", forceIdle, !idleDelayed); 6538 6539 if (!idleDelayed) { 6540 mTaskSupervisor.scheduleIdle(); 6541 } else { 6542 mTaskSupervisor.scheduleIdleTimeout(this); 6543 } 6544 } else { 6545 rootTask.checkReadyForSleep(); 6546 } 6547 } 6548 startLaunchTickingLocked()6549 void startLaunchTickingLocked() { 6550 if (Build.IS_USER) { 6551 return; 6552 } 6553 if (launchTickTime == 0) { 6554 launchTickTime = SystemClock.uptimeMillis(); 6555 continueLaunchTicking(); 6556 } 6557 } 6558 continueLaunchTicking()6559 private boolean continueLaunchTicking() { 6560 if (launchTickTime == 0) { 6561 return false; 6562 } 6563 6564 final Task rootTask = getRootTask(); 6565 if (rootTask == null) { 6566 return false; 6567 } 6568 6569 rootTask.removeLaunchTickMessages(); 6570 mAtmService.mH.postDelayed(mLaunchTickRunnable, LAUNCH_TICK); 6571 return true; 6572 } 6573 removeLaunchTickRunnable()6574 void removeLaunchTickRunnable() { 6575 mAtmService.mH.removeCallbacks(mLaunchTickRunnable); 6576 } 6577 finishLaunchTickingLocked()6578 void finishLaunchTickingLocked() { 6579 launchTickTime = 0; 6580 final Task rootTask = getRootTask(); 6581 if (rootTask == null) { 6582 return; 6583 } 6584 rootTask.removeLaunchTickMessages(); 6585 } 6586 mayFreezeScreenLocked()6587 boolean mayFreezeScreenLocked() { 6588 return mayFreezeScreenLocked(app); 6589 } 6590 mayFreezeScreenLocked(WindowProcessController app)6591 private boolean mayFreezeScreenLocked(WindowProcessController app) { 6592 // Only freeze the screen if this activity is currently attached to 6593 // an application, and that application is not blocked or unresponding. 6594 // In any other case, we can't count on getting the screen unfrozen, 6595 // so it is best to leave as-is. 6596 return hasProcess() && !app.isCrashing() && !app.isNotResponding(); 6597 } 6598 startFreezingScreenLocked(int configChanges)6599 void startFreezingScreenLocked(int configChanges) { 6600 startFreezingScreenLocked(app, configChanges); 6601 } 6602 startFreezingScreenLocked(WindowProcessController app, int configChanges)6603 void startFreezingScreenLocked(WindowProcessController app, int configChanges) { 6604 if (mayFreezeScreenLocked(app)) { 6605 if (getParent() == null) { 6606 Slog.w(TAG_WM, 6607 "Attempted to freeze screen with non-existing app token: " + token); 6608 return; 6609 } 6610 6611 // Window configuration changes only effect windows, so don't require a screen freeze. 6612 int freezableConfigChanges = configChanges & ~(CONFIG_WINDOW_CONFIGURATION); 6613 if (freezableConfigChanges == 0 && okToDisplay()) { 6614 ProtoLog.v(WM_DEBUG_ORIENTATION, "Skipping set freeze of %s", token); 6615 return; 6616 } 6617 6618 startFreezingScreen(); 6619 } 6620 } 6621 startFreezingScreen()6622 void startFreezingScreen() { 6623 startFreezingScreen(ROTATION_UNDEFINED /* overrideOriginalDisplayRotation */); 6624 } 6625 startFreezingScreen(int overrideOriginalDisplayRotation)6626 void startFreezingScreen(int overrideOriginalDisplayRotation) { 6627 if (mTransitionController.isShellTransitionsEnabled()) { 6628 return; 6629 } 6630 ProtoLog.i(WM_DEBUG_ORIENTATION, 6631 "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", 6632 token, isVisible(), mFreezingScreen, mVisibleRequested, 6633 new RuntimeException().fillInStackTrace()); 6634 if (!mVisibleRequested) { 6635 return; 6636 } 6637 6638 // If the override is given, the rotation of display doesn't change but we still want to 6639 // cover the activity whose configuration is changing by freezing the display and running 6640 // the rotation animation. 6641 final boolean forceRotation = overrideOriginalDisplayRotation != ROTATION_UNDEFINED; 6642 if (!mFreezingScreen) { 6643 mFreezingScreen = true; 6644 mWmService.registerAppFreezeListener(this); 6645 mWmService.mAppsFreezingScreen++; 6646 if (mWmService.mAppsFreezingScreen == 1) { 6647 if (forceRotation) { 6648 // Make sure normal rotation animation will be applied. 6649 mDisplayContent.getDisplayRotation().cancelSeamlessRotation(); 6650 } 6651 mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, 6652 mDisplayContent, overrideOriginalDisplayRotation); 6653 mWmService.mH.removeMessages(H.APP_FREEZE_TIMEOUT); 6654 mWmService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000); 6655 } 6656 } 6657 if (forceRotation) { 6658 // The rotation of the real display won't change, so in order to unfreeze the screen 6659 // via {@link #checkAppWindowsReadyToShow}, the windows have to be able to call 6660 // {@link WindowState#reportResized} (it is skipped if the window is freezing) to update 6661 // the drawn state. 6662 return; 6663 } 6664 final int count = mChildren.size(); 6665 for (int i = 0; i < count; i++) { 6666 final WindowState w = mChildren.get(i); 6667 w.onStartFreezingScreen(); 6668 } 6669 } 6670 isFreezingScreen()6671 boolean isFreezingScreen() { 6672 return mFreezingScreen; 6673 } 6674 6675 @Override onAppFreezeTimeout()6676 public void onAppFreezeTimeout() { 6677 Slog.w(TAG_WM, "Force clearing freeze: " + this); 6678 stopFreezingScreen(true, true); 6679 } 6680 stopFreezingScreenLocked(boolean force)6681 void stopFreezingScreenLocked(boolean force) { 6682 if (force || frozenBeforeDestroy) { 6683 frozenBeforeDestroy = false; 6684 if (getParent() == null) { 6685 return; 6686 } 6687 ProtoLog.v(WM_DEBUG_ORIENTATION, 6688 "Clear freezing of %s: visible=%b freezing=%b", token, 6689 isVisible(), isFreezingScreen()); 6690 stopFreezingScreen(true, force); 6691 } 6692 } 6693 stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force)6694 void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) { 6695 if (!mFreezingScreen) { 6696 return; 6697 } 6698 ProtoLog.v(WM_DEBUG_ORIENTATION, 6699 "Clear freezing of %s force=%b", this, force); 6700 final int count = mChildren.size(); 6701 boolean unfrozeWindows = false; 6702 for (int i = 0; i < count; i++) { 6703 final WindowState w = mChildren.get(i); 6704 unfrozeWindows |= w.onStopFreezingScreen(); 6705 } 6706 if (force || unfrozeWindows) { 6707 ProtoLog.v(WM_DEBUG_ORIENTATION, "No longer freezing: %s", this); 6708 mFreezingScreen = false; 6709 mWmService.unregisterAppFreezeListener(this); 6710 mWmService.mAppsFreezingScreen--; 6711 mWmService.mLastFinishedFreezeSource = this; 6712 } 6713 if (unfreezeSurfaceNow) { 6714 if (unfrozeWindows) { 6715 mWmService.mWindowPlacerLocked.performSurfacePlacement(); 6716 } 6717 mWmService.stopFreezingDisplayLocked(); 6718 } 6719 } 6720 onFirstWindowDrawn(WindowState win)6721 void onFirstWindowDrawn(WindowState win) { 6722 firstWindowDrawn = true; 6723 // stop tracking 6724 mSplashScreenStyleSolidColor = true; 6725 6726 if (mStartingWindow != null) { 6727 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s" 6728 + ": first real window is shown, no animation", win.mToken); 6729 // If this initial window is animating, stop it -- we will do an animation to reveal 6730 // it from behind the starting window, so there is no need for it to also be doing its 6731 // own stuff. 6732 win.cancelAnimation(); 6733 } 6734 6735 // Remove starting window directly if is in a pure task. Otherwise if it is associated with 6736 // a task (e.g. nested task fragment), then remove only if all visible windows in the task 6737 // are drawn. 6738 final Task associatedTask = task.mSharedStartingData != null ? task : null; 6739 if (associatedTask == null) { 6740 removeStartingWindow(); 6741 } else if (associatedTask.getActivity( 6742 r -> r.isVisibleRequested() && !r.firstWindowDrawn) == null) { 6743 // The last drawn activity may not be the one that owns the starting window. 6744 final ActivityRecord r = associatedTask.topActivityContainsStartingWindow(); 6745 if (r != null) { 6746 r.removeStartingWindow(); 6747 } 6748 } 6749 updateReportedVisibilityLocked(); 6750 } 6751 6752 /** 6753 * Sets whether something has been visible in the task and returns {@code true} if the state 6754 * is changed from invisible to visible. 6755 */ setTaskHasBeenVisible()6756 private boolean setTaskHasBeenVisible() { 6757 final boolean wasTaskVisible = task.getHasBeenVisible(); 6758 if (wasTaskVisible) { 6759 return false; 6760 } 6761 if (inTransition()) { 6762 // The deferring will be canceled until transition is ready so it won't dispatch 6763 // intermediate states to organizer. 6764 task.setDeferTaskAppear(true); 6765 } 6766 task.setHasBeenVisible(true); 6767 return true; 6768 } 6769 onStartingWindowDrawn()6770 void onStartingWindowDrawn() { 6771 boolean wasTaskVisible = false; 6772 if (task != null) { 6773 mSplashScreenStyleSolidColor = true; 6774 wasTaskVisible = !setTaskHasBeenVisible(); 6775 } 6776 6777 // The transition may not be executed if the starting process hasn't attached. But if the 6778 // starting window is drawn, the transition can start earlier. Exclude finishing and bubble 6779 // because it may be a trampoline. 6780 if (!wasTaskVisible && mStartingData != null && !finishing && !mLaunchedFromBubble 6781 && mVisibleRequested && !mDisplayContent.mAppTransition.isReady() 6782 && !mDisplayContent.mAppTransition.isRunning() 6783 && mDisplayContent.isNextTransitionForward()) { 6784 // The pending transition state will be cleared after the transition is started, so 6785 // save the state for launching the client later (used by LaunchActivityItem). 6786 mStartingData.mIsTransitionForward = true; 6787 // Ensure that the transition can run with the latest orientation. 6788 if (this != mDisplayContent.getLastOrientationSource()) { 6789 mDisplayContent.updateOrientation(); 6790 } 6791 mDisplayContent.executeAppTransition(); 6792 } 6793 } 6794 6795 /** Called when the windows associated app window container are drawn. */ onWindowsDrawn()6796 private void onWindowsDrawn() { 6797 final TransitionInfoSnapshot info = mTaskSupervisor 6798 .getActivityMetricsLogger().notifyWindowsDrawn(this); 6799 final boolean validInfo = info != null; 6800 final int windowsDrawnDelayMs = validInfo ? info.windowsDrawnDelayMs : INVALID_DELAY; 6801 final @WaitResult.LaunchState int launchState = 6802 validInfo ? info.getLaunchState() : WaitResult.LAUNCH_STATE_UNKNOWN; 6803 // The activity may have been requested to be invisible (another activity has been launched) 6804 // so there is no valid info. But if it is the current top activity (e.g. sleeping), the 6805 // invalid state is still reported to make sure the waiting result is notified. 6806 if (validInfo || this == getDisplayArea().topRunningActivity()) { 6807 mTaskSupervisor.reportActivityLaunched(false /* timeout */, this, 6808 windowsDrawnDelayMs, launchState); 6809 } 6810 finishLaunchTickingLocked(); 6811 if (task != null) { 6812 setTaskHasBeenVisible(); 6813 } 6814 // Clear indicated launch root task because there's no trampoline activity to expect after 6815 // the windows are drawn. 6816 mLaunchRootTask = null; 6817 } 6818 6819 /** Called when the windows associated app window container are visible. */ onWindowsVisible()6820 void onWindowsVisible() { 6821 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in " + token); 6822 mTaskSupervisor.stopWaitingForActivityVisible(this); 6823 if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this); 6824 if (!nowVisible) { 6825 nowVisible = true; 6826 lastVisibleTime = SystemClock.uptimeMillis(); 6827 mAtmService.scheduleAppGcsLocked(); 6828 // The nowVisible may be false in onAnimationFinished because the transition animation 6829 // was started by starting window but the main window hasn't drawn so the procedure 6830 // didn't schedule. Hence also check when nowVisible becomes true (drawn) to avoid the 6831 // closing activity having to wait until idle timeout to be stopped or destroyed if the 6832 // next activity won't report idle (e.g. repeated view animation). 6833 mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded(); 6834 6835 // If the activity is visible, but no windows are eligible to start input, unfreeze 6836 // to avoid permanently frozen IME insets. 6837 if (mImeInsetsFrozenUntilStartInput && getWindow( 6838 win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags)) 6839 == null) { 6840 mImeInsetsFrozenUntilStartInput = false; 6841 } 6842 } 6843 } 6844 6845 /** Called when the windows associated app window container are no longer visible. */ onWindowsGone()6846 void onWindowsGone() { 6847 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in " + token); 6848 if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this); 6849 nowVisible = false; 6850 } 6851 6852 @Override checkAppWindowsReadyToShow()6853 void checkAppWindowsReadyToShow() { 6854 if (allDrawn == mLastAllDrawn) { 6855 return; 6856 } 6857 6858 mLastAllDrawn = allDrawn; 6859 if (!allDrawn) { 6860 return; 6861 } 6862 6863 // The token has now changed state to having all windows shown... what to do, what to do? 6864 if (mFreezingScreen) { 6865 showAllWindowsLocked(); 6866 stopFreezingScreen(false, true); 6867 ProtoLog.i(WM_DEBUG_ORIENTATION, 6868 "Setting mOrientationChangeComplete=true because wtoken %s " 6869 + "numInteresting=%d numDrawn=%d", 6870 this, mNumInterestingWindows, mNumDrawnWindows); 6871 // This will set mOrientationChangeComplete and cause a pass through layout. 6872 setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER, 6873 "checkAppWindowsReadyToShow: freezingScreen"); 6874 } else { 6875 setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow"); 6876 6877 // We can now show all of the drawn windows! 6878 if (!getDisplayContent().mOpeningApps.contains(this) && canShowWindows()) { 6879 showAllWindowsLocked(); 6880 } 6881 } 6882 } 6883 6884 /** 6885 * This must be called while inside a transaction. 6886 */ showAllWindowsLocked()6887 void showAllWindowsLocked() { 6888 forAllWindows(windowState -> { 6889 if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState); 6890 windowState.performShowLocked(); 6891 }, false /* traverseTopToBottom */); 6892 } 6893 updateReportedVisibilityLocked()6894 void updateReportedVisibilityLocked() { 6895 if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this); 6896 final int count = mChildren.size(); 6897 6898 mReportedVisibilityResults.reset(); 6899 6900 for (int i = 0; i < count; i++) { 6901 final WindowState win = mChildren.get(i); 6902 win.updateReportedVisibility(mReportedVisibilityResults); 6903 } 6904 6905 int numInteresting = mReportedVisibilityResults.numInteresting; 6906 int numVisible = mReportedVisibilityResults.numVisible; 6907 int numDrawn = mReportedVisibilityResults.numDrawn; 6908 boolean nowGone = mReportedVisibilityResults.nowGone; 6909 6910 boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting; 6911 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && isVisible(); 6912 if (!nowGone) { 6913 // If the app is not yet gone, then it can only become visible/drawn. 6914 if (!nowDrawn) { 6915 nowDrawn = mReportedDrawn; 6916 } 6917 if (!nowVisible) { 6918 nowVisible = reportedVisible; 6919 } 6920 } 6921 if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting=" 6922 + numInteresting + " visible=" + numVisible); 6923 if (nowDrawn != mReportedDrawn) { 6924 if (nowDrawn) { 6925 onWindowsDrawn(); 6926 } 6927 mReportedDrawn = nowDrawn; 6928 } 6929 if (nowVisible != reportedVisible) { 6930 if (DEBUG_VISIBILITY) Slog.v(TAG, 6931 "Visibility changed in " + this + ": vis=" + nowVisible); 6932 reportedVisible = nowVisible; 6933 if (nowVisible) { 6934 onWindowsVisible(); 6935 } else { 6936 onWindowsGone(); 6937 } 6938 } 6939 } 6940 isReportedDrawn()6941 boolean isReportedDrawn() { 6942 return mReportedDrawn; 6943 } 6944 6945 @Override setClientVisible(boolean clientVisible)6946 void setClientVisible(boolean clientVisible) { 6947 // TODO(shell-transitions): Remove mDeferHidingClient once everything is shell-transitions. 6948 // pip activities should just remain in clientVisible. 6949 if (!clientVisible && mDeferHidingClient) return; 6950 super.setClientVisible(clientVisible); 6951 } 6952 6953 /** 6954 * Updated this app token tracking states for interesting and drawn windows based on the window. 6955 * 6956 * @return Returns true if the input window is considered interesting and drawn while all the 6957 * windows in this app token where not considered drawn as of the last pass. 6958 */ updateDrawnWindowStates(WindowState w)6959 boolean updateDrawnWindowStates(WindowState w) { 6960 w.setDrawnStateEvaluated(true /*evaluated*/); 6961 6962 if (DEBUG_STARTING_WINDOW_VERBOSE && w == mStartingWindow) { 6963 Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen() 6964 + " allDrawn=" + allDrawn + " freezingScreen=" + mFreezingScreen); 6965 } 6966 6967 if (allDrawn && !mFreezingScreen) { 6968 return false; 6969 } 6970 6971 if (mLastTransactionSequence != mWmService.mTransactionSequence) { 6972 mLastTransactionSequence = mWmService.mTransactionSequence; 6973 mNumDrawnWindows = 0; 6974 6975 // There is the main base application window, even if it is exiting, wait for it 6976 mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0; 6977 } 6978 6979 final WindowStateAnimator winAnimator = w.mWinAnimator; 6980 6981 boolean isInterestingAndDrawn = false; 6982 6983 if (!allDrawn && w.mightAffectAllDrawn()) { 6984 if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) { 6985 final boolean isAnimationSet = isAnimating(TRANSITION | PARENTS, 6986 ANIMATION_TYPE_APP_TRANSITION); 6987 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawn() 6988 + ", isAnimationSet=" + isAnimationSet); 6989 if (!w.isDrawn()) { 6990 Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController 6991 + " pv=" + w.isVisibleByPolicy() 6992 + " mDrawState=" + winAnimator.drawStateToString() 6993 + " ph=" + w.isParentWindowHidden() + " th=" + mVisibleRequested 6994 + " a=" + isAnimationSet); 6995 } 6996 } 6997 6998 if (w != mStartingWindow) { 6999 if (w.isInteresting()) { 7000 // Add non-main window as interesting since the main app has already been added 7001 if (findMainWindow(false /* includeStartingApp */) != w) { 7002 mNumInterestingWindows++; 7003 } 7004 if (w.isDrawn()) { 7005 mNumDrawnWindows++; 7006 7007 if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) { 7008 Slog.v(TAG, "tokenMayBeDrawn: " 7009 + this + " w=" + w + " numInteresting=" + mNumInterestingWindows 7010 + " freezingScreen=" + mFreezingScreen 7011 + " mAppFreezing=" + w.mAppFreezing); 7012 } 7013 7014 isInterestingAndDrawn = true; 7015 } 7016 } 7017 } else if (mStartingData != null && w.isDrawn()) { 7018 // The starting window for this container is drawn. 7019 mStartingData.mIsDisplayed = true; 7020 } 7021 } 7022 7023 return isInterestingAndDrawn; 7024 } 7025 7026 /** 7027 * Called when the input dispatching to a window associated with the app window container 7028 * timed-out. 7029 * 7030 * @param reason The reason for input dispatching time out. 7031 * @param windowPid The pid of the window input dispatching timed out on. 7032 * @return True if input dispatching should be aborted. 7033 */ inputDispatchingTimedOut(TimeoutRecord timeoutRecord, int windowPid)7034 public boolean inputDispatchingTimedOut(TimeoutRecord timeoutRecord, int windowPid) { 7035 try { 7036 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, 7037 "ActivityRecord#inputDispatchingTimedOut()"); 7038 ActivityRecord anrActivity; 7039 WindowProcessController anrApp; 7040 boolean blameActivityProcess; 7041 timeoutRecord.mLatencyTracker.waitingOnGlobalLockStarted(); 7042 synchronized (mAtmService.mGlobalLock) { 7043 timeoutRecord.mLatencyTracker.waitingOnGlobalLockEnded(); 7044 anrActivity = getWaitingHistoryRecordLocked(); 7045 anrApp = app; 7046 blameActivityProcess = hasProcess() 7047 && (app.getPid() == windowPid || windowPid == INVALID_PID); 7048 } 7049 7050 if (blameActivityProcess) { 7051 return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner, 7052 anrActivity.shortComponentName, anrActivity.info.applicationInfo, 7053 shortComponentName, app, false, timeoutRecord); 7054 } else { 7055 // In this case another process added windows using this activity token. 7056 // So, we call the generic service input dispatch timed out method so 7057 // that the right process is blamed. 7058 long timeoutMillis = mAtmService.mAmInternal.inputDispatchingTimedOut( 7059 windowPid, false /* aboveSystem */, timeoutRecord); 7060 return timeoutMillis <= 0; 7061 } 7062 } finally { 7063 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 7064 } 7065 7066 } 7067 getWaitingHistoryRecordLocked()7068 private ActivityRecord getWaitingHistoryRecordLocked() { 7069 // First find the real culprit... if this activity has stopped, then the key dispatching 7070 // timeout should not be caused by this. 7071 if (mAppStopped) { 7072 final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); 7073 if (rootTask == null) { 7074 return this; 7075 } 7076 // Try to use the one which is closest to top. 7077 ActivityRecord r = rootTask.getTopResumedActivity(); 7078 if (r == null) { 7079 r = rootTask.getTopPausingActivity(); 7080 } 7081 if (r != null) { 7082 return r; 7083 } 7084 } 7085 return this; 7086 } 7087 canBeTopRunning()7088 boolean canBeTopRunning() { 7089 return !finishing && showToCurrentUser(); 7090 } 7091 7092 /** 7093 * This method will return true if the activity is either visible, is becoming visible, is 7094 * currently pausing, or is resumed. 7095 */ isInterestingToUserLocked()7096 public boolean isInterestingToUserLocked() { 7097 return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED; 7098 } 7099 getTaskForActivityLocked(IBinder token, boolean onlyRoot)7100 static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) { 7101 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 7102 if (r == null || r.getParent() == null) { 7103 return INVALID_TASK_ID; 7104 } 7105 return getTaskForActivityLocked(r, onlyRoot); 7106 } 7107 getTaskForActivityLocked(ActivityRecord r, boolean onlyRoot)7108 static int getTaskForActivityLocked(ActivityRecord r, boolean onlyRoot) { 7109 final Task task = r.task; 7110 if (onlyRoot && r.compareTo(task.getRootActivity( 7111 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)) > 0) { 7112 return INVALID_TASK_ID; 7113 } 7114 return task.mTaskId; 7115 } 7116 isInRootTaskLocked(IBinder token)7117 static ActivityRecord isInRootTaskLocked(IBinder token) { 7118 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 7119 return (r != null) ? r.getRootTask().isInTask(r) : null; 7120 } 7121 getRootTask(IBinder token)7122 static Task getRootTask(IBinder token) { 7123 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 7124 if (r != null) { 7125 return r.getRootTask(); 7126 } 7127 return null; 7128 } 7129 7130 @Nullable isInAnyTask(IBinder token)7131 static ActivityRecord isInAnyTask(IBinder token) { 7132 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 7133 return (r != null && r.isAttached()) ? r : null; 7134 } 7135 7136 /** 7137 * @return display id to which this record is attached, 7138 * {@link android.view.Display#INVALID_DISPLAY} if not attached. 7139 */ getDisplayId()7140 int getDisplayId() { 7141 return task != null && task.mDisplayContent != null 7142 ? task.mDisplayContent.mDisplayId : INVALID_DISPLAY; 7143 } 7144 isDestroyable()7145 final boolean isDestroyable() { 7146 if (finishing || !hasProcess()) { 7147 // This would be redundant. 7148 return false; 7149 } 7150 if (isState(RESUMED) || getRootTask() == null 7151 || this == getTaskFragment().getPausingActivity() 7152 || !mHaveState || !mAppStopped) { 7153 // We're not ready for this kind of thing. 7154 return false; 7155 } 7156 if (mVisibleRequested) { 7157 // The user would notice this! 7158 return false; 7159 } 7160 return true; 7161 } 7162 createImageFilename(long createTime, int taskId)7163 private static String createImageFilename(long createTime, int taskId) { 7164 return String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + createTime + 7165 IMAGE_EXTENSION; 7166 } 7167 setTaskDescription(TaskDescription _taskDescription)7168 void setTaskDescription(TaskDescription _taskDescription) { 7169 Bitmap icon; 7170 if (_taskDescription.getIconFilename() == null && 7171 (icon = _taskDescription.getIcon()) != null) { 7172 final String iconFilename = createImageFilename(createTime, task.mTaskId); 7173 final File iconFile = new File(TaskPersister.getUserImagesDir(task.mUserId), 7174 iconFilename); 7175 final String iconFilePath = iconFile.getAbsolutePath(); 7176 mAtmService.getRecentTasks().saveImage(icon, iconFilePath); 7177 _taskDescription.setIconFilename(iconFilePath); 7178 } 7179 taskDescription = _taskDescription; 7180 getTask().updateTaskDescription(); 7181 } 7182 setLocusId(LocusId locusId)7183 void setLocusId(LocusId locusId) { 7184 if (Objects.equals(locusId, mLocusId)) return; 7185 mLocusId = locusId; 7186 final Task task = getTask(); 7187 if (task != null) getTask().dispatchTaskInfoChangedIfNeeded(false /* force */); 7188 } 7189 getLocusId()7190 LocusId getLocusId() { 7191 return mLocusId; 7192 } 7193 reportScreenCaptured()7194 public void reportScreenCaptured() { 7195 if (mCaptureCallbacks != null) { 7196 final int n = mCaptureCallbacks.beginBroadcast(); 7197 for (int i = 0; i < n; i++) { 7198 IScreenCaptureObserver obs = mCaptureCallbacks.getBroadcastItem(i); 7199 try { 7200 obs.onScreenCaptured(); 7201 } catch (RemoteException e) { 7202 } 7203 } 7204 mCaptureCallbacks.finishBroadcast(); 7205 } 7206 } 7207 registerCaptureObserver(IScreenCaptureObserver observer)7208 public void registerCaptureObserver(IScreenCaptureObserver observer) { 7209 synchronized (mWmService.mGlobalLock) { 7210 if (mCaptureCallbacks == null) { 7211 mCaptureCallbacks = new RemoteCallbackList<IScreenCaptureObserver>(); 7212 } 7213 mCaptureCallbacks.register(observer); 7214 } 7215 } 7216 unregisterCaptureObserver(IScreenCaptureObserver observer)7217 public void unregisterCaptureObserver(IScreenCaptureObserver observer) { 7218 synchronized (mWmService.mGlobalLock) { 7219 if (mCaptureCallbacks != null) { 7220 mCaptureCallbacks.unregister(observer); 7221 } 7222 } 7223 } 7224 isRegisteredForScreenCaptureCallback()7225 boolean isRegisteredForScreenCaptureCallback() { 7226 return mCaptureCallbacks != null && mCaptureCallbacks.getRegisteredCallbackCount() > 0; 7227 } 7228 setVoiceSessionLocked(IVoiceInteractionSession session)7229 void setVoiceSessionLocked(IVoiceInteractionSession session) { 7230 voiceSession = session; 7231 pendingVoiceInteractionStart = false; 7232 } 7233 clearVoiceSessionLocked()7234 void clearVoiceSessionLocked() { 7235 voiceSession = null; 7236 pendingVoiceInteractionStart = false; 7237 } 7238 showStartingWindow(boolean taskSwitch)7239 void showStartingWindow(boolean taskSwitch) { 7240 showStartingWindow(null /* prev */, false /* newTask */, taskSwitch, 7241 false /* startActivity */, null); 7242 } 7243 7244 /** 7245 * Search for the candidate launching activity from currently visible activities. 7246 * 7247 * This activity could be launched from service, so we need to check whether there is existing a 7248 * foreground activity from the same process or same package. 7249 * 7250 */ searchCandidateLaunchingActivity()7251 private ActivityRecord searchCandidateLaunchingActivity() { 7252 // Get previous activity below self 7253 ActivityRecord below = task.getActivityBelow(this); 7254 if (below == null) { 7255 below = task.getParent().getActivityBelow(this); 7256 } 7257 7258 if (below == null || below.isActivityTypeHome()) { 7259 return null; 7260 } 7261 final WindowProcessController myProcess = app != null 7262 ? app : mAtmService.mProcessNames.get(processName, info.applicationInfo.uid); 7263 final WindowProcessController candidateProcess = below.app != null 7264 ? below.app 7265 : mAtmService.mProcessNames.get(below.processName, 7266 below.info.applicationInfo.uid); 7267 // same process or same package 7268 if (candidateProcess == myProcess 7269 || mActivityComponent.getPackageName() 7270 .equals(below.mActivityComponent.getPackageName())) { 7271 return below; 7272 } 7273 return null; 7274 } 7275 isIconStylePreferred(int theme)7276 private boolean isIconStylePreferred(int theme) { 7277 if (theme == 0) { 7278 return false; 7279 } 7280 final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, theme, 7281 R.styleable.Window, mWmService.mCurrentUserId); 7282 if (ent != null) { 7283 if (ent.array.hasValue(R.styleable.Window_windowSplashScreenBehavior)) { 7284 return ent.array.getInt(R.styleable.Window_windowSplashScreenBehavior, 7285 SPLASH_SCREEN_BEHAVIOR_DEFAULT) 7286 == SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED; 7287 } 7288 } 7289 return false; 7290 } shouldUseSolidColorSplashScreen(ActivityRecord sourceRecord, boolean startActivity, ActivityOptions options, int resolvedTheme)7291 private boolean shouldUseSolidColorSplashScreen(ActivityRecord sourceRecord, 7292 boolean startActivity, ActivityOptions options, int resolvedTheme) { 7293 if (sourceRecord == null && !startActivity) { 7294 // Use simple style if this activity is not top activity. This could happen when adding 7295 // a splash screen window to the warm start activity which is re-create because top is 7296 // finishing. 7297 final ActivityRecord above = task.getActivityAbove(this); 7298 if (above != null) { 7299 return true; 7300 } 7301 } 7302 7303 // setSplashScreenStyle decide in priority of windowSplashScreenBehavior. 7304 if (options != null) { 7305 final int optionsStyle = options.getSplashScreenStyle(); 7306 if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR) { 7307 return true; 7308 } else if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_ICON 7309 || isIconStylePreferred(resolvedTheme)) { 7310 return false; 7311 } 7312 // Choose the default behavior for Launcher and SystemUI when the SplashScreen style is 7313 // not specified in the ActivityOptions. 7314 if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME 7315 || launchedFromUid == Process.SHELL_UID) { 7316 return false; 7317 } else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) { 7318 return true; 7319 } 7320 } else if (isIconStylePreferred(resolvedTheme)) { 7321 return false; 7322 } 7323 if (sourceRecord == null) { 7324 sourceRecord = searchCandidateLaunchingActivity(); 7325 } 7326 7327 if (sourceRecord != null && !sourceRecord.isActivityTypeHome()) { 7328 return sourceRecord.mSplashScreenStyleSolidColor; 7329 } 7330 7331 // If this activity was launched from Launcher or System for first start, never use a 7332 // solid color splash screen. 7333 // Need to check sourceRecord before in case this activity is launched from service. 7334 return !startActivity || !(mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEM 7335 || mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME 7336 || launchedFromUid == Process.SHELL_UID); 7337 } 7338 getSplashscreenTheme(ActivityOptions options)7339 private int getSplashscreenTheme(ActivityOptions options) { 7340 // Find the splash screen theme. User can override the persisted theme by 7341 // ActivityOptions. 7342 String splashScreenThemeResName = options != null 7343 ? options.getSplashScreenThemeResName() : null; 7344 if (splashScreenThemeResName == null || splashScreenThemeResName.isEmpty()) { 7345 try { 7346 splashScreenThemeResName = mAtmService.getPackageManager() 7347 .getSplashScreenTheme(packageName, mUserId); 7348 } catch (RemoteException ignore) { 7349 // Just use the default theme 7350 } 7351 } 7352 int splashScreenThemeResId = 0; 7353 if (splashScreenThemeResName != null && !splashScreenThemeResName.isEmpty()) { 7354 try { 7355 final Context packageContext = mAtmService.mContext 7356 .createPackageContext(packageName, 0); 7357 splashScreenThemeResId = packageContext.getResources() 7358 .getIdentifier(splashScreenThemeResName, null, null); 7359 } catch (PackageManager.NameNotFoundException 7360 | Resources.NotFoundException ignore) { 7361 // Just use the default theme 7362 } 7363 } 7364 return splashScreenThemeResId; 7365 } 7366 showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, boolean startActivity, ActivityRecord sourceRecord)7367 void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, 7368 boolean startActivity, ActivityRecord sourceRecord) { 7369 showStartingWindow(prev, newTask, taskSwitch, isProcessRunning(), startActivity, 7370 sourceRecord, null /* candidateOptions */); 7371 } 7372 7373 /** 7374 * @param prev Previous activity which contains a starting window. 7375 * @param processRunning Whether the client process is running. 7376 * @param startActivity Whether this activity is just created from starter. 7377 * @param sourceRecord The source activity which start this activity. 7378 * @param candidateOptions The options for the style of starting window. 7379 */ showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, boolean processRunning, boolean startActivity, ActivityRecord sourceRecord, ActivityOptions candidateOptions)7380 void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, 7381 boolean processRunning, boolean startActivity, ActivityRecord sourceRecord, 7382 ActivityOptions candidateOptions) { 7383 if (mTaskOverlay) { 7384 // We don't show starting window for overlay activities. 7385 return; 7386 } 7387 final ActivityOptions startOptions = candidateOptions != null 7388 ? candidateOptions : mPendingOptions; 7389 if (startOptions != null 7390 && startOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { 7391 // Don't show starting window when using shared element transition. 7392 return; 7393 } 7394 7395 final int splashScreenTheme = startActivity ? getSplashscreenTheme(startOptions) : 0; 7396 final int resolvedTheme = evaluateStartingWindowTheme(prev, packageName, theme, 7397 splashScreenTheme); 7398 7399 mSplashScreenStyleSolidColor = shouldUseSolidColorSplashScreen(sourceRecord, startActivity, 7400 startOptions, resolvedTheme); 7401 7402 final boolean activityCreated = 7403 mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal(); 7404 // If this activity is just created and all activities below are finish, treat this 7405 // scenario as warm launch. 7406 final boolean newSingleActivity = !newTask && !activityCreated 7407 && task.getActivity((r) -> !r.finishing && r != this) == null; 7408 7409 final boolean scheduled = addStartingWindow(packageName, resolvedTheme, 7410 prev, newTask || newSingleActivity, taskSwitch, processRunning, 7411 allowTaskSnapshot(), activityCreated, mSplashScreenStyleSolidColor, allDrawn); 7412 if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) { 7413 Slog.d(TAG, "Scheduled starting window for " + this); 7414 } 7415 } 7416 7417 /** 7418 * If any activities below the top running one are in the INITIALIZING state and they have a 7419 * starting window displayed then remove that starting window. It is possible that the activity 7420 * in this state will never resumed in which case that starting window will be orphaned. 7421 * <p> 7422 * It should only be called if this activity is behind other fullscreen activity. 7423 */ cancelInitializing()7424 void cancelInitializing() { 7425 if (mStartingData != null) { 7426 // Remove orphaned starting window. 7427 if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this); 7428 removeStartingWindowAnimation(false /* prepareAnimation */); 7429 } 7430 if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) { 7431 // Remove the unknown visibility record because an invisible activity shouldn't block 7432 // the keyguard transition. 7433 mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this); 7434 } 7435 } 7436 postWindowRemoveStartingWindowCleanup()7437 void postWindowRemoveStartingWindowCleanup() { 7438 if (mChildren.size() == 0 && mVisibleSetFromTransferredStartingWindow) { 7439 // We set the visible state to true for the token from a transferred starting 7440 // window. We now reset it back to false since the starting window was the last 7441 // window in the token. 7442 setVisible(false); 7443 } 7444 } 7445 requestUpdateWallpaperIfNeeded()7446 void requestUpdateWallpaperIfNeeded() { 7447 for (int i = mChildren.size() - 1; i >= 0; i--) { 7448 final WindowState w = mChildren.get(i); 7449 w.requestUpdateWallpaperIfNeeded(); 7450 } 7451 } 7452 7453 /** 7454 * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns 7455 * true and isn't fully transparent. 7456 */ getTopFullscreenOpaqueWindow()7457 WindowState getTopFullscreenOpaqueWindow() { 7458 for (int i = mChildren.size() - 1; i >= 0; i--) { 7459 final WindowState win = mChildren.get(i); 7460 if (win != null && win.mAttrs.isFullscreen() && !win.isFullyTransparent()) { 7461 return win; 7462 } 7463 } 7464 return null; 7465 } 7466 findMainWindow()7467 WindowState findMainWindow() { 7468 return findMainWindow(true); 7469 } 7470 7471 /** 7472 * Finds the main window that either has type base application or application starting if 7473 * requested. 7474 * 7475 * @param includeStartingApp Allow to search application-starting windows to also be returned. 7476 * @return The main window of type base application or application starting if requested. 7477 */ findMainWindow(boolean includeStartingApp)7478 WindowState findMainWindow(boolean includeStartingApp) { 7479 WindowState candidate = null; 7480 for (int j = mChildren.size() - 1; j >= 0; --j) { 7481 final WindowState win = mChildren.get(j); 7482 final int type = win.mAttrs.type; 7483 // No need to loop through child window as base application and starting types can't be 7484 // child windows. 7485 if (type == TYPE_BASE_APPLICATION 7486 || (includeStartingApp && type == TYPE_APPLICATION_STARTING)) { 7487 // In cases where there are multiple windows, we prefer the non-exiting window. This 7488 // happens for example when replacing windows during an activity relaunch. When 7489 // constructing the animation, we want the new window, not the exiting one. 7490 if (win.mAnimatingExit) { 7491 candidate = win; 7492 } else { 7493 return win; 7494 } 7495 } 7496 } 7497 return candidate; 7498 } 7499 7500 @Override needsZBoost()7501 boolean needsZBoost() { 7502 return mNeedsZBoost || super.needsZBoost(); 7503 } 7504 7505 @Override getAnimationLeashParent()7506 public SurfaceControl getAnimationLeashParent() { 7507 // For transitions in the root pinned task (menu activity) we just let them occur as a child 7508 // of the root pinned task. 7509 // All normal app transitions take place in an animation layer which is below the root 7510 // pinned task but may be above the parent tasks of the given animating apps by default. 7511 // When a new hierarchical animation is enabled, we just let them occur as a child of the 7512 // parent task, i.e. the hierarchy of the surfaces is unchanged. 7513 if (inPinnedWindowingMode()) { 7514 return getRootTask().getSurfaceControl(); 7515 } else { 7516 return super.getAnimationLeashParent(); 7517 } 7518 } 7519 7520 @VisibleForTesting shouldAnimate()7521 boolean shouldAnimate() { 7522 return task == null || task.shouldAnimate(); 7523 } 7524 7525 /** 7526 * Creates a layer to apply crop to an animation. 7527 */ createAnimationBoundsLayer(Transaction t)7528 private SurfaceControl createAnimationBoundsLayer(Transaction t) { 7529 ProtoLog.i(WM_DEBUG_APP_TRANSITIONS_ANIM, "Creating animation bounds layer"); 7530 final SurfaceControl.Builder builder = makeAnimationLeash() 7531 .setParent(getAnimationLeashParent()) 7532 .setName(getSurfaceControl() + " - animation-bounds") 7533 .setCallsite("ActivityRecord.createAnimationBoundsLayer"); 7534 if (mNeedsLetterboxedAnimation) { 7535 // Needs to be an effect layer to support rounded corners 7536 builder.setEffectLayer(); 7537 } 7538 final SurfaceControl boundsLayer = builder.build(); 7539 t.show(boundsLayer); 7540 return boundsLayer; 7541 } 7542 7543 @Override shouldDeferAnimationFinish(Runnable endDeferFinishCallback)7544 public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { 7545 return mAnimatingActivityRegistry != null 7546 && mAnimatingActivityRegistry.notifyAboutToFinish( 7547 this, endDeferFinishCallback); 7548 } 7549 7550 @Override isWaitingForTransitionStart()7551 boolean isWaitingForTransitionStart() { 7552 final DisplayContent dc = getDisplayContent(); 7553 return dc != null && dc.mAppTransition.isTransitionSet() 7554 && (dc.mOpeningApps.contains(this) 7555 || dc.mClosingApps.contains(this) 7556 || dc.mChangingContainers.contains(this)); 7557 } 7558 isTransitionForward()7559 boolean isTransitionForward() { 7560 return (mStartingData != null && mStartingData.mIsTransitionForward) 7561 || mDisplayContent.isNextTransitionForward(); 7562 } 7563 7564 @Override resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t)7565 void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) { 7566 // Noop as Activity may be offset for letterbox 7567 } 7568 7569 @Override onLeashAnimationStarting(Transaction t, SurfaceControl leash)7570 public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) { 7571 if (mAnimatingActivityRegistry != null) { 7572 mAnimatingActivityRegistry.notifyStarting(this); 7573 } 7574 7575 if (mNeedsLetterboxedAnimation) { 7576 updateLetterboxSurface(findMainWindow(), t); 7577 mNeedsAnimationBoundsLayer = true; 7578 } 7579 7580 // If the animation needs to be cropped then an animation bounds layer is created as a 7581 // child of the root pinned task or animation layer. The leash is then reparented to this 7582 // new layer. 7583 if (mNeedsAnimationBoundsLayer) { 7584 mTmpRect.setEmpty(); 7585 if (getDisplayContent().mAppTransitionController.isTransitWithinTask( 7586 getTransit(), task)) { 7587 task.getBounds(mTmpRect); 7588 } else { 7589 final Task rootTask = getRootTask(); 7590 if (rootTask == null) { 7591 return; 7592 } 7593 // Set clip rect to root task bounds. 7594 rootTask.getBounds(mTmpRect); 7595 } 7596 mAnimationBoundsLayer = createAnimationBoundsLayer(t); 7597 7598 // Crop to root task bounds. 7599 t.setLayer(leash, 0); 7600 t.setLayer(mAnimationBoundsLayer, getLastLayer()); 7601 7602 if (mNeedsLetterboxedAnimation) { 7603 final int cornerRadius = mLetterboxUiController 7604 .getRoundedCornersRadius(findMainWindow()); 7605 7606 final Rect letterboxInnerBounds = new Rect(); 7607 getLetterboxInnerBounds(letterboxInnerBounds); 7608 7609 t.setCornerRadius(mAnimationBoundsLayer, cornerRadius) 7610 .setCrop(mAnimationBoundsLayer, letterboxInnerBounds); 7611 } 7612 7613 // Reparent leash to animation bounds layer. 7614 t.reparent(leash, mAnimationBoundsLayer); 7615 } 7616 } 7617 7618 @Override showSurfaceOnCreation()7619 boolean showSurfaceOnCreation() { 7620 return false; 7621 } 7622 7623 @Override prepareSurfaces()7624 void prepareSurfaces() { 7625 final boolean show = isVisible() || isAnimating(PARENTS, 7626 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS 7627 | ANIMATION_TYPE_PREDICT_BACK); 7628 7629 if (mSurfaceControl != null) { 7630 if (show && !mLastSurfaceShowing) { 7631 getSyncTransaction().show(mSurfaceControl); 7632 } else if (!show && mLastSurfaceShowing) { 7633 getSyncTransaction().hide(mSurfaceControl); 7634 } 7635 // Input sink surface is not a part of animation, so just apply in a steady state 7636 // (non-sync) with pending transaction. 7637 if (show && mSyncState == SYNC_STATE_NONE) { 7638 mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getPendingTransaction()); 7639 } 7640 } 7641 if (mThumbnail != null) { 7642 mThumbnail.setShowing(getPendingTransaction(), show); 7643 } 7644 mLastSurfaceShowing = show; 7645 super.prepareSurfaces(); 7646 } 7647 7648 /** 7649 * @return Whether our {@link #getSurfaceControl} is currently showing. 7650 */ isSurfaceShowing()7651 boolean isSurfaceShowing() { 7652 return mLastSurfaceShowing; 7653 } 7654 attachThumbnailAnimation()7655 void attachThumbnailAnimation() { 7656 if (!isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) { 7657 return; 7658 } 7659 final HardwareBuffer thumbnailHeader = 7660 getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(task); 7661 if (thumbnailHeader == null) { 7662 ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", task); 7663 return; 7664 } 7665 clearThumbnail(); 7666 final Transaction transaction = getAnimatingContainer().getPendingTransaction(); 7667 mThumbnail = new WindowContainerThumbnail(transaction, getAnimatingContainer(), 7668 thumbnailHeader); 7669 mThumbnail.startAnimation(transaction, loadThumbnailAnimation(thumbnailHeader)); 7670 } 7671 7672 /** 7673 * Attaches a surface with a thumbnail for the 7674 * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation. 7675 */ attachCrossProfileAppsThumbnailAnimation()7676 void attachCrossProfileAppsThumbnailAnimation() { 7677 if (!isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) { 7678 return; 7679 } 7680 clearThumbnail(); 7681 7682 final WindowState win = findMainWindow(); 7683 if (win == null) { 7684 return; 7685 } 7686 final Rect frame = win.getRelativeFrame(); 7687 final Drawable thumbnailDrawable = task.mUserId == mWmService.mCurrentUserId 7688 ? mAtmService.getUiContext().getDrawable(R.drawable.ic_account_circle) 7689 : mEnterpriseThumbnailDrawable; 7690 final HardwareBuffer thumbnail = getDisplayContent().mAppTransition 7691 .createCrossProfileAppsThumbnail(thumbnailDrawable, frame); 7692 if (thumbnail == null) { 7693 return; 7694 } 7695 final Transaction transaction = getPendingTransaction(); 7696 mThumbnail = new WindowContainerThumbnail(transaction, getTask(), thumbnail); 7697 final Animation animation = 7698 getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked( 7699 frame); 7700 mThumbnail.startAnimation(transaction, animation, new Point(frame.left, frame.top)); 7701 } 7702 loadThumbnailAnimation(HardwareBuffer thumbnailHeader)7703 private Animation loadThumbnailAnimation(HardwareBuffer thumbnailHeader) { 7704 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); 7705 7706 // If this is a multi-window scenario, we use the windows frame as 7707 // destination of the thumbnail header animation. If this is a full screen 7708 // window scenario, we use the whole display as the target. 7709 WindowState win = findMainWindow(); 7710 Rect insets; 7711 Rect appRect; 7712 if (win != null) { 7713 insets = win.getInsetsStateWithVisibilityOverride().calculateInsets( 7714 win.getFrame(), Type.systemBars(), false /* ignoreVisibility */).toRect(); 7715 appRect = new Rect(win.getFrame()); 7716 appRect.inset(insets); 7717 } else { 7718 insets = null; 7719 appRect = new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight); 7720 } 7721 final Configuration displayConfig = mDisplayContent.getConfiguration(); 7722 return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked( 7723 appRect, insets, thumbnailHeader, task, displayConfig.orientation); 7724 } 7725 7726 @Override onAnimationLeashLost(Transaction t)7727 public void onAnimationLeashLost(Transaction t) { 7728 super.onAnimationLeashLost(t); 7729 if (mAnimationBoundsLayer != null) { 7730 t.remove(mAnimationBoundsLayer); 7731 mAnimationBoundsLayer = null; 7732 } 7733 7734 mNeedsAnimationBoundsLayer = false; 7735 if (mNeedsLetterboxedAnimation) { 7736 mNeedsLetterboxedAnimation = false; 7737 updateLetterboxSurface(findMainWindow(), t); 7738 } 7739 7740 if (mAnimatingActivityRegistry != null) { 7741 mAnimatingActivityRegistry.notifyFinished(this); 7742 } 7743 } 7744 7745 @Override onAnimationFinished(@nimationType int type, AnimationAdapter anim)7746 protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { 7747 super.onAnimationFinished(type, anim); 7748 7749 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished"); 7750 mTransit = TRANSIT_OLD_UNSET; 7751 mTransitFlags = 0; 7752 7753 setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER, 7754 "ActivityRecord"); 7755 7756 clearThumbnail(); 7757 setClientVisible(isVisible() || mVisibleRequested); 7758 7759 getDisplayContent().computeImeTargetIfNeeded(this); 7760 7761 ProtoLog.v(WM_DEBUG_ANIM, "Animation done in %s" 7762 + ": reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b", 7763 this, reportedVisible, okToDisplay(), okToAnimate(), 7764 isStartingWindowDisplayed()); 7765 7766 // clean up thumbnail window 7767 if (mThumbnail != null) { 7768 mThumbnail.destroy(); 7769 mThumbnail = null; 7770 } 7771 7772 // WindowState.onExitAnimationDone might modify the children list, so make a copy and then 7773 // traverse the copy. 7774 final ArrayList<WindowState> children = new ArrayList<>(mChildren); 7775 children.forEach(WindowState::onExitAnimationDone); 7776 // The starting window could transfer to another activity after app transition started, in 7777 // that case the latest top activity might not receive exit animation done callback if the 7778 // starting window didn't applied exit animation success. Notify animation finish to the 7779 // starting window if needed. 7780 if (task != null && startingMoved) { 7781 final WindowState transferredStarting = task.getWindow(w -> 7782 w.mAttrs.type == TYPE_APPLICATION_STARTING); 7783 if (transferredStarting != null && transferredStarting.mAnimatingExit 7784 && !transferredStarting.isSelfAnimating(0 /* flags */, 7785 ANIMATION_TYPE_WINDOW_ANIMATION)) { 7786 transferredStarting.onExitAnimationDone(); 7787 } 7788 } 7789 7790 getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token); 7791 scheduleAnimation(); 7792 7793 // Schedule to handle the stopping and finishing activities which the animation is done 7794 // because the activities which were animating have not been stopped yet. 7795 mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded(); 7796 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 7797 } 7798 clearAnimatingFlags()7799 void clearAnimatingFlags() { 7800 boolean wallpaperMightChange = false; 7801 for (int i = mChildren.size() - 1; i >= 0; i--) { 7802 final WindowState win = mChildren.get(i); 7803 wallpaperMightChange |= win.clearAnimatingFlags(); 7804 } 7805 if (wallpaperMightChange) { 7806 requestUpdateWallpaperIfNeeded(); 7807 } 7808 } 7809 7810 @Override cancelAnimation()7811 void cancelAnimation() { 7812 super.cancelAnimation(); 7813 clearThumbnail(); 7814 } 7815 clearThumbnail()7816 private void clearThumbnail() { 7817 if (mThumbnail == null) { 7818 return; 7819 } 7820 mThumbnail.destroy(); 7821 mThumbnail = null; 7822 } 7823 getTransit()7824 public @TransitionOldType int getTransit() { 7825 return mTransit; 7826 } 7827 7828 registerRemoteAnimations(RemoteAnimationDefinition definition)7829 void registerRemoteAnimations(RemoteAnimationDefinition definition) { 7830 mRemoteAnimationDefinition = definition; 7831 if (definition != null) { 7832 definition.linkToDeath(this::unregisterRemoteAnimations); 7833 } 7834 } 7835 unregisterRemoteAnimations()7836 void unregisterRemoteAnimations() { 7837 mRemoteAnimationDefinition = null; 7838 } 7839 7840 @Override getRemoteAnimationDefinition()7841 RemoteAnimationDefinition getRemoteAnimationDefinition() { 7842 return mRemoteAnimationDefinition; 7843 } 7844 7845 @Override applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, Configuration config)7846 void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, 7847 Configuration config) { 7848 super.applyFixedRotationTransform(info, displayFrames, config); 7849 ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); 7850 } 7851 7852 /** 7853 * Returns the requested {@link Configuration.Orientation} for the current activity. 7854 */ 7855 @Configuration.Orientation 7856 @Override getRequestedConfigurationOrientation(boolean forDisplay)7857 int getRequestedConfigurationOrientation(boolean forDisplay) { 7858 return getRequestedConfigurationOrientation(forDisplay, getOverrideOrientation()); 7859 } 7860 7861 /** 7862 * Returns the requested {@link Configuration.Orientation} for the requested 7863 * {@link ActivityInfo.ScreenOrientation}. 7864 * 7865 * <p>When the current screen orientation is set to {@link SCREEN_ORIENTATION_BEHIND} it returns 7866 * the requested orientation for the activity below which is the first activity with an explicit 7867 * (different from {@link SCREEN_ORIENTATION_UNSET}) orientation which is not {@link 7868 * SCREEN_ORIENTATION_BEHIND}. 7869 */ 7870 @Configuration.Orientation getRequestedConfigurationOrientation(boolean forDisplay, @ActivityInfo.ScreenOrientation int requestedOrientation)7871 int getRequestedConfigurationOrientation(boolean forDisplay, 7872 @ActivityInfo.ScreenOrientation int requestedOrientation) { 7873 if (mLetterboxUiController.hasInheritedOrientation()) { 7874 final RootDisplayArea root = getRootDisplayArea(); 7875 if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) { 7876 return reverseConfigurationOrientation( 7877 mLetterboxUiController.getInheritedOrientation()); 7878 } else { 7879 return mLetterboxUiController.getInheritedOrientation(); 7880 } 7881 } 7882 if (task != null && requestedOrientation == SCREEN_ORIENTATION_BEHIND) { 7883 // We use Task here because we want to be consistent with what happens in 7884 // multi-window mode where other tasks orientations are ignored. 7885 final ActivityRecord belowCandidate = task.getActivity( 7886 a -> a.canDefineOrientationForActivitiesAbove() /* callback */, 7887 this /* boundary */, false /* includeBoundary */, 7888 true /* traverseTopToBottom */); 7889 if (belowCandidate != null) { 7890 return belowCandidate.getRequestedConfigurationOrientation(forDisplay); 7891 } 7892 } 7893 return super.getRequestedConfigurationOrientation(forDisplay, requestedOrientation); 7894 } 7895 7896 /** 7897 * Returns the reversed configuration orientation. 7898 * @hide 7899 */ 7900 @Configuration.Orientation reverseConfigurationOrientation(@onfiguration.Orientation int orientation)7901 public static int reverseConfigurationOrientation(@Configuration.Orientation int orientation) { 7902 switch (orientation) { 7903 case ORIENTATION_LANDSCAPE: 7904 return ORIENTATION_PORTRAIT; 7905 case ORIENTATION_PORTRAIT: 7906 return ORIENTATION_LANDSCAPE; 7907 default: 7908 return orientation; 7909 } 7910 } 7911 7912 /** 7913 * Whether this activity can be used as an orientation source for activities above with 7914 * {@link SCREEN_ORIENTATION_BEHIND}. 7915 */ canDefineOrientationForActivitiesAbove()7916 boolean canDefineOrientationForActivitiesAbove() { 7917 if (finishing) { 7918 return false; 7919 } 7920 final int overrideOrientation = getOverrideOrientation(); 7921 return overrideOrientation != SCREEN_ORIENTATION_UNSET 7922 && overrideOrientation != SCREEN_ORIENTATION_BEHIND; 7923 } 7924 7925 @Override onCancelFixedRotationTransform(int originalDisplayRotation)7926 void onCancelFixedRotationTransform(int originalDisplayRotation) { 7927 if (this != mDisplayContent.getLastOrientationSource()) { 7928 // This activity doesn't affect display rotation. 7929 return; 7930 } 7931 final int requestedOrientation = getRequestedConfigurationOrientation(); 7932 if (requestedOrientation != ORIENTATION_UNDEFINED 7933 && requestedOrientation != mDisplayContent.getConfiguration().orientation) { 7934 // Only need to handle the activity that can be rotated with display or the activity 7935 // has requested the same orientation. 7936 return; 7937 } 7938 7939 mDisplayContent.mPinnedTaskController.onCancelFixedRotationTransform(); 7940 // Perform rotation animation according to the rotation of this activity. 7941 startFreezingScreen(originalDisplayRotation); 7942 // This activity may relaunch or perform configuration change so once it has reported drawn, 7943 // the screen can be unfrozen. 7944 ensureActivityConfiguration(0 /* globalChanges */, !PRESERVE_WINDOWS); 7945 if (mTransitionController.isCollecting(this)) { 7946 // In case the task was changed from PiP but still keeps old transform. 7947 task.resetSurfaceControlTransforms(); 7948 } 7949 } 7950 setRequestedOrientation(@ctivityInfo.ScreenOrientation int requestedOrientation)7951 void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) { 7952 if (mLetterboxUiController.shouldIgnoreRequestedOrientation(requestedOrientation)) { 7953 return; 7954 } 7955 // This is necessary in order to avoid going into size compat mode when the orientation 7956 // change request comes from the app 7957 if (getRequestedConfigurationOrientation(false, requestedOrientation) 7958 != getRequestedConfigurationOrientation(false /*forDisplay */)) { 7959 // Do not change the requested configuration now, because this will be done when setting 7960 // the orientation below with the new mCompatDisplayInsets 7961 clearSizeCompatModeAttributes(); 7962 } 7963 ProtoLog.v(WM_DEBUG_ORIENTATION, 7964 "Setting requested orientation %s for %s", 7965 ActivityInfo.screenOrientationToString(requestedOrientation), this); 7966 setOrientation(requestedOrientation, this); 7967 7968 // Push the new configuration to the requested app in case where it's not pushed, e.g. when 7969 // the request is handled at task level with letterbox. 7970 if (!getMergedOverrideConfiguration().equals( 7971 mLastReportedConfiguration.getMergedConfiguration())) { 7972 ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */, 7973 false /* ignoreVisibility */, true /* isRequestedOrientationChanged */); 7974 if (mTransitionController.inPlayingTransition(this)) { 7975 mTransitionController.mValidateActivityCompat.add(this); 7976 } 7977 } 7978 7979 mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( 7980 task.mTaskId, requestedOrientation); 7981 7982 mDisplayContent.getDisplayRotation().onSetRequestedOrientation(); 7983 } 7984 7985 /* 7986 * Called from {@link RootWindowContainer#ensureVisibilityAndConfig} to make sure the 7987 * orientation is updated before the app becomes visible. 7988 */ reportDescendantOrientationChangeIfNeeded()7989 void reportDescendantOrientationChangeIfNeeded() { 7990 // Orientation request is exposed only when we're visible. Therefore visibility change 7991 // will change requested orientation. Notify upward the hierarchy ladder to adjust 7992 // configuration. This is important to cases where activities with incompatible 7993 // orientations launch, or user goes back from an activity of bi-orientation to an 7994 // activity with specified orientation. 7995 if (onDescendantOrientationChanged(this)) { 7996 // WM Shell can show additional UI elements, e.g. a restart button for size compat mode 7997 // so ensure that WM Shell is called when an activity becomes visible. 7998 task.dispatchTaskInfoChangedIfNeeded(/* force= */ true); 7999 } 8000 } 8001 8002 /** 8003 * Ignores the activity orientation request if the App is fixed-orientation portrait and has 8004 * ActivityEmbedding enabled and is currently running on large screen display. Or the display 8005 * could be rotated to portrait and not having large enough width for app to split. 8006 */ 8007 @VisibleForTesting shouldIgnoreOrientationRequests()8008 boolean shouldIgnoreOrientationRequests() { 8009 if (!mAppActivityEmbeddingSplitsEnabled 8010 || !ActivityInfo.isFixedOrientationPortrait(getOverrideOrientation()) 8011 || task.inMultiWindowMode()) { 8012 return false; 8013 } 8014 8015 return getTask().getConfiguration().smallestScreenWidthDp 8016 >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; 8017 } 8018 8019 /** 8020 * We override because this class doesn't want its children affecting its reported orientation 8021 * in anyway. 8022 */ 8023 @Override getOrientation(int candidate)8024 int getOrientation(int candidate) { 8025 if (shouldIgnoreOrientationRequests()) { 8026 return SCREEN_ORIENTATION_UNSET; 8027 } 8028 8029 if (candidate == SCREEN_ORIENTATION_BEHIND) { 8030 // Allow app to specify orientation regardless of its visibility state if the current 8031 // candidate want us to use orientation behind. I.e. the visible app on-top of this one 8032 // wants us to use the orientation of the app behind it. 8033 return getOverrideOrientation(); 8034 } 8035 8036 // The {@link ActivityRecord} should only specify an orientation when it is not closing. 8037 // Allowing closing {@link ActivityRecord} to participate can lead to an Activity in another 8038 // task being started in the wrong orientation during the transition. 8039 if (!getDisplayContent().mClosingApps.contains(this) 8040 && (isVisibleRequested() || getDisplayContent().mOpeningApps.contains(this))) { 8041 return getOverrideOrientation(); 8042 } 8043 8044 return SCREEN_ORIENTATION_UNSET; 8045 } 8046 8047 /** 8048 * Returns the app's preferred orientation regardless of its current visibility state taking 8049 * into account orientation per-app overrides applied by the device manufacturers. 8050 */ 8051 @Override getOverrideOrientation()8052 protected int getOverrideOrientation() { 8053 return mLetterboxUiController.overrideOrientationIfNeeded(super.getOverrideOrientation()); 8054 } 8055 8056 /** 8057 * Returns the app's preferred orientation regardless of its currently visibility state. This 8058 * is used to return a requested value to an app if they call {@link 8059 * android.app.Activity#getRequestedOrientation} since {@link #getOverrideOrientation} value 8060 * with override can confuse an app if it's different from what they requested with {@link 8061 * android.app.Activity#setRequestedOrientation}. 8062 */ 8063 @ActivityInfo.ScreenOrientation getRequestedOrientation()8064 int getRequestedOrientation() { 8065 return super.getOverrideOrientation(); 8066 } 8067 8068 /** 8069 * Set the last reported global configuration to the client. Should be called whenever a new 8070 * global configuration is sent to the client for this activity. 8071 */ setLastReportedGlobalConfiguration(@onNull Configuration config)8072 void setLastReportedGlobalConfiguration(@NonNull Configuration config) { 8073 mLastReportedConfiguration.setGlobalConfiguration(config); 8074 } 8075 8076 /** 8077 * Set the last reported configuration to the client. Should be called whenever 8078 * a new merged configuration is sent to the client for this activity. 8079 */ setLastReportedConfiguration(@onNull MergedConfiguration config)8080 void setLastReportedConfiguration(@NonNull MergedConfiguration config) { 8081 setLastReportedConfiguration(config.getGlobalConfiguration(), 8082 config.getOverrideConfiguration()); 8083 } 8084 setLastReportedConfiguration(Configuration global, Configuration override)8085 private void setLastReportedConfiguration(Configuration global, Configuration override) { 8086 mLastReportedConfiguration.setConfiguration(global, override); 8087 } 8088 8089 @Nullable getCompatDisplayInsets()8090 CompatDisplayInsets getCompatDisplayInsets() { 8091 if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { 8092 return mLetterboxUiController.getInheritedCompatDisplayInsets(); 8093 } 8094 return mCompatDisplayInsets; 8095 } 8096 8097 /** 8098 * @return The {@code true} if the current instance has {@link mCompatDisplayInsets} without 8099 * considering the inheritance implemented in {@link #getCompatDisplayInsets()} 8100 */ hasCompatDisplayInsetsWithoutInheritance()8101 boolean hasCompatDisplayInsetsWithoutInheritance() { 8102 return mCompatDisplayInsets != null; 8103 } 8104 8105 /** 8106 * @return {@code true} if this activity is in size compatibility mode that uses the different 8107 * density than its parent or its bounds don't fit in parent naturally. 8108 */ inSizeCompatMode()8109 boolean inSizeCompatMode() { 8110 if (mInSizeCompatModeForBounds) { 8111 return true; 8112 } 8113 if (getCompatDisplayInsets() == null || !shouldCreateCompatDisplayInsets() 8114 // The orientation is different from parent when transforming. 8115 || isFixedRotationTransforming()) { 8116 return false; 8117 } 8118 final Rect appBounds = getConfiguration().windowConfiguration.getAppBounds(); 8119 if (appBounds == null) { 8120 // The app bounds hasn't been computed yet. 8121 return false; 8122 } 8123 final WindowContainer parent = getParent(); 8124 if (parent == null) { 8125 // The parent of detached Activity can be null. 8126 return false; 8127 } 8128 final Configuration parentConfig = parent.getConfiguration(); 8129 // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these 8130 // fields should be changed with density and bounds, so here only compares the most 8131 // significant field. 8132 return parentConfig.densityDpi != getConfiguration().densityDpi; 8133 } 8134 8135 /** 8136 * Indicates the activity will keep the bounds and screen configuration when it was first 8137 * launched, no matter how its parent changes. 8138 * 8139 * <p>If {@true}, then {@link CompatDisplayInsets} will be created in {@link 8140 * #resolveOverrideConfiguration} to "freeze" activity bounds and insets. 8141 * 8142 * @return {@code true} if this activity is declared as non-resizable and fixed orientation or 8143 * aspect ratio. 8144 */ shouldCreateCompatDisplayInsets()8145 boolean shouldCreateCompatDisplayInsets() { 8146 switch (supportsSizeChanges()) { 8147 case SIZE_CHANGES_SUPPORTED_METADATA: 8148 case SIZE_CHANGES_SUPPORTED_OVERRIDE: 8149 return false; 8150 case SIZE_CHANGES_UNSUPPORTED_OVERRIDE: 8151 return true; 8152 default: 8153 // Fall through 8154 } 8155 if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) { 8156 final ActivityRecord root = task != null ? task.getRootActivity() : null; 8157 if (root != null && root != this && !root.shouldCreateCompatDisplayInsets()) { 8158 // If the root activity doesn't use size compatibility mode, the activities above 8159 // are forced to be the same for consistent visual appearance. 8160 return false; 8161 } 8162 } 8163 return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio()) 8164 // The configuration of non-standard type should be enforced by system. 8165 // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is 8166 // added to a task, but this function is called when resolving the launch params, at 8167 // which point, the activity type is still undefined if it will be standard. 8168 // For other non-standard types, the type is set in the constructor, so this should 8169 // not be a problem. 8170 && isActivityTypeStandardOrUndefined(); 8171 } 8172 8173 /** 8174 * Returns whether the activity supports size changes. 8175 */ 8176 @ActivityInfo.SizeChangesSupportMode supportsSizeChanges()8177 private int supportsSizeChanges() { 8178 if (mLetterboxUiController.shouldOverrideForceNonResizeApp()) { 8179 return SIZE_CHANGES_UNSUPPORTED_OVERRIDE; 8180 } 8181 8182 if (info.supportsSizeChanges) { 8183 return SIZE_CHANGES_SUPPORTED_METADATA; 8184 } 8185 8186 if (mLetterboxUiController.shouldOverrideForceResizeApp()) { 8187 return SIZE_CHANGES_SUPPORTED_OVERRIDE; 8188 } 8189 8190 return SIZE_CHANGES_UNSUPPORTED_METADATA; 8191 } 8192 8193 @Override hasSizeCompatBounds()8194 boolean hasSizeCompatBounds() { 8195 return mSizeCompatBounds != null; 8196 } 8197 8198 // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. updateCompatDisplayInsets()8199 private void updateCompatDisplayInsets() { 8200 if (getCompatDisplayInsets() != null || !shouldCreateCompatDisplayInsets()) { 8201 // The override configuration is set only once in size compatibility mode. 8202 return; 8203 } 8204 8205 Configuration overrideConfig = getRequestedOverrideConfiguration(); 8206 final Configuration fullConfig = getConfiguration(); 8207 8208 // Ensure the screen related fields are set. It is used to prevent activity relaunch 8209 // when moving between displays. For screenWidthDp and screenWidthDp, because they 8210 // are relative to bounds and density, they will be calculated in 8211 // {@link Task#computeConfigResourceOverrides} and the result will also be 8212 // relatively fixed. 8213 overrideConfig.colorMode = fullConfig.colorMode; 8214 overrideConfig.densityDpi = fullConfig.densityDpi; 8215 // The smallest screen width is the short side of screen bounds. Because the bounds 8216 // and density won't be changed, smallestScreenWidthDp is also fixed. 8217 overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp; 8218 if (ActivityInfo.isFixedOrientation(getOverrideOrientation())) { 8219 // lock rotation too. When in size-compat, onConfigurationChanged will watch for and 8220 // apply runtime rotation changes. 8221 overrideConfig.windowConfiguration.setRotation( 8222 fullConfig.windowConfiguration.getRotation()); 8223 } 8224 8225 // The role of CompatDisplayInsets is like the override bounds. 8226 mCompatDisplayInsets = 8227 new CompatDisplayInsets( 8228 mDisplayContent, this, mLetterboxBoundsForFixedOrientationAndAspectRatio); 8229 } 8230 clearSizeCompatModeAttributes()8231 private void clearSizeCompatModeAttributes() { 8232 mInSizeCompatModeForBounds = false; 8233 mSizeCompatScale = 1f; 8234 mSizeCompatBounds = null; 8235 mCompatDisplayInsets = null; 8236 mLetterboxUiController.clearInheritedCompatDisplayInsets(); 8237 } 8238 8239 @VisibleForTesting clearSizeCompatMode()8240 void clearSizeCompatMode() { 8241 final float lastSizeCompatScale = mSizeCompatScale; 8242 clearSizeCompatModeAttributes(); 8243 if (mSizeCompatScale != lastSizeCompatScale) { 8244 forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */); 8245 } 8246 // Clear config override in #updateCompatDisplayInsets(). 8247 final int activityType = getActivityType(); 8248 final Configuration overrideConfig = getRequestedOverrideConfiguration(); 8249 overrideConfig.unset(); 8250 // Keep the activity type which was set when attaching to a task to prevent leaving it 8251 // undefined. 8252 overrideConfig.windowConfiguration.setActivityType(activityType); 8253 onRequestedOverrideConfigurationChanged(overrideConfig); 8254 } 8255 8256 @Override matchParentBounds()8257 public boolean matchParentBounds() { 8258 final Rect overrideBounds = getResolvedOverrideBounds(); 8259 if (overrideBounds.isEmpty()) { 8260 return true; 8261 } 8262 // An activity in size compatibility mode may have override bounds which equals to its 8263 // parent bounds, so the exact bounds should also be checked to allow IME window to attach 8264 // to the activity. See {@link DisplayContent#shouldImeAttachedToApp}. 8265 final WindowContainer parent = getParent(); 8266 return parent == null || parent.getBounds().equals(overrideBounds); 8267 } 8268 8269 @Override getCompatScale()8270 float getCompatScale() { 8271 return hasSizeCompatBounds() ? mSizeCompatScale : super.getCompatScale(); 8272 } 8273 8274 @Override resolveOverrideConfiguration(Configuration newParentConfiguration)8275 void resolveOverrideConfiguration(Configuration newParentConfiguration) { 8276 final Configuration requestedOverrideConfig = getRequestedOverrideConfiguration(); 8277 if (requestedOverrideConfig.assetsSeq != ASSETS_SEQ_UNDEFINED 8278 && newParentConfiguration.assetsSeq > requestedOverrideConfig.assetsSeq) { 8279 requestedOverrideConfig.assetsSeq = ASSETS_SEQ_UNDEFINED; 8280 } 8281 super.resolveOverrideConfiguration(newParentConfiguration); 8282 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 8283 8284 applyLocaleOverrideIfNeeded(resolvedConfig); 8285 8286 if (isFixedRotationTransforming()) { 8287 // The resolved configuration is applied with rotated display configuration. If this 8288 // activity matches its parent (the following resolving procedures are no-op), then it 8289 // can use the resolved configuration directly. Otherwise (e.g. fixed aspect ratio), 8290 // the rotated configuration is used as parent configuration to compute the actual 8291 // resolved configuration. It is like putting the activity in a rotated container. 8292 mTmpConfig.setTo(newParentConfiguration); 8293 mTmpConfig.updateFrom(resolvedConfig); 8294 newParentConfiguration = mTmpConfig; 8295 } 8296 8297 mIsAspectRatioApplied = false; 8298 mIsEligibleForFixedOrientationLetterbox = false; 8299 mLetterboxBoundsForFixedOrientationAndAspectRatio = null; 8300 8301 // Can't use resolvedConfig.windowConfiguration.getWindowingMode() because it can be 8302 // different from windowing mode of the task (PiP) during transition from fullscreen to PiP 8303 // and back which can cause visible issues (see b/184078928). 8304 final int parentWindowingMode = 8305 newParentConfiguration.windowConfiguration.getWindowingMode(); 8306 final boolean isFixedOrientationLetterboxAllowed = 8307 parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW 8308 || parentWindowingMode == WINDOWING_MODE_FULLSCREEN 8309 // When starting to switch between PiP and fullscreen, the task is pinned 8310 // and the activity is fullscreen. But only allow to apply letterbox if the 8311 // activity is exiting PiP because an entered PiP should fill the task. 8312 || (!mWaitForEnteringPinnedMode 8313 && parentWindowingMode == WINDOWING_MODE_PINNED 8314 && resolvedConfig.windowConfiguration.getWindowingMode() 8315 == WINDOWING_MODE_FULLSCREEN); 8316 // TODO(b/181207944): Consider removing the if condition and always run 8317 // resolveFixedOrientationConfiguration() since this should be applied for all cases. 8318 if (isFixedOrientationLetterboxAllowed) { 8319 resolveFixedOrientationConfiguration(newParentConfiguration); 8320 } 8321 final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets(); 8322 if (compatDisplayInsets != null) { 8323 resolveSizeCompatModeConfiguration(newParentConfiguration, compatDisplayInsets); 8324 } else if (inMultiWindowMode() && !isFixedOrientationLetterboxAllowed) { 8325 // We ignore activities' requested orientation in multi-window modes. They may be 8326 // taken into consideration in resolveFixedOrientationConfiguration call above. 8327 resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED; 8328 // If the activity has requested override bounds, the configuration needs to be 8329 // computed accordingly. 8330 if (!matchParentBounds()) { 8331 getTaskFragment().computeConfigResourceOverrides(resolvedConfig, 8332 newParentConfiguration); 8333 } 8334 // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds 8335 // are already calculated in resolveFixedOrientationConfiguration. 8336 } else if (!isLetterboxedForFixedOrientationAndAspectRatio()) { 8337 resolveAspectRatioRestriction(newParentConfiguration); 8338 } 8339 8340 if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null 8341 // In fullscreen, can be letterboxed for aspect ratio. 8342 || !inMultiWindowMode()) { 8343 updateResolvedBoundsPosition(newParentConfiguration); 8344 } 8345 8346 boolean isIgnoreOrientationRequest = mDisplayContent != null 8347 && mDisplayContent.getIgnoreOrientationRequest(); 8348 if (compatDisplayInsets == null 8349 // for size compat mode set in updateCompatDisplayInsets 8350 // Fixed orientation letterboxing is possible on both large screen devices 8351 // with ignoreOrientationRequest enabled and on phones in split screen even with 8352 // ignoreOrientationRequest disabled. 8353 && (mLetterboxBoundsForFixedOrientationAndAspectRatio != null 8354 // Limiting check for aspect ratio letterboxing to devices with enabled 8355 // ignoreOrientationRequest. This avoids affecting phones where apps may 8356 // not expect the change of smallestScreenWidthDp after rotation which is 8357 // possible with this logic. Not having smallestScreenWidthDp completely 8358 // accurate on phones shouldn't make the big difference and is expected 8359 // to be already well-tested by apps. 8360 || (isIgnoreOrientationRequest && mIsAspectRatioApplied))) { 8361 // TODO(b/264034555): Use mDisplayContent to calculate smallestScreenWidthDp from all 8362 // rotations and only re-calculate if parent bounds have non-orientation size change. 8363 resolvedConfig.smallestScreenWidthDp = 8364 Math.min(resolvedConfig.screenWidthDp, resolvedConfig.screenHeightDp); 8365 } 8366 8367 // Assign configuration sequence number into hierarchy because there is a different way than 8368 // ensureActivityConfiguration() in this class that uses configuration in WindowState during 8369 // layout traversals. 8370 mConfigurationSeq = Math.max(++mConfigurationSeq, 1); 8371 getResolvedOverrideConfiguration().seq = mConfigurationSeq; 8372 8373 // Sandbox max bounds by setting it to the activity bounds, if activity is letterboxed, or 8374 // has or will have mCompatDisplayInsets for size compat. Also forces an activity to be 8375 // sandboxed or not depending upon the configuration settings. 8376 if (providesMaxBounds()) { 8377 mTmpBounds.set(resolvedConfig.windowConfiguration.getBounds()); 8378 if (mTmpBounds.isEmpty()) { 8379 // When there is no override bounds, the activity will inherit the bounds from 8380 // parent. 8381 mTmpBounds.set(newParentConfiguration.windowConfiguration.getBounds()); 8382 } 8383 if (DEBUG_CONFIGURATION) { 8384 ProtoLog.d(WM_DEBUG_CONFIGURATION, "Sandbox max bounds for uid %s to bounds %s. " 8385 + "config to never sandbox = %s, " 8386 + "config to always sandbox = %s, " 8387 + "letterboxing from mismatch with parent bounds = %s, " 8388 + "has mCompatDisplayInsets = %s, " 8389 + "should create compatDisplayInsets = %s", 8390 getUid(), 8391 mTmpBounds, 8392 info.neverSandboxDisplayApis(sConstrainDisplayApisConfig), 8393 info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig), 8394 !matchParentBounds(), 8395 compatDisplayInsets != null, 8396 shouldCreateCompatDisplayInsets()); 8397 } 8398 resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds); 8399 } 8400 8401 logAppCompatState(); 8402 } 8403 8404 /** 8405 * @return The orientation to use to understand if reachability is enabled. 8406 */ 8407 @Configuration.Orientation getOrientationForReachability()8408 int getOrientationForReachability() { 8409 return mLetterboxUiController.hasInheritedLetterboxBehavior() 8410 ? mLetterboxUiController.getInheritedOrientation() 8411 : getRequestedConfigurationOrientation(); 8412 } 8413 8414 /** 8415 * Returns whether activity bounds are letterboxed. 8416 * 8417 * <p>Note that letterbox UI may not be shown even when this returns {@code true}. See {@link 8418 * LetterboxUiController#shouldShowLetterboxUi} for more context. 8419 */ areBoundsLetterboxed()8420 boolean areBoundsLetterboxed() { 8421 return getAppCompatState(/* ignoreVisibility= */ true) 8422 != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED; 8423 } 8424 8425 /** 8426 * Logs the current App Compat state via {@link ActivityMetricsLogger#logAppCompatState}. 8427 */ logAppCompatState()8428 private void logAppCompatState() { 8429 mTaskSupervisor.getActivityMetricsLogger().logAppCompatState(this); 8430 } 8431 8432 /** 8433 * Returns the current App Compat state of this activity. 8434 * 8435 * <p>The App Compat state indicates whether the activity is visible and letterboxed, and if so 8436 * what is the reason for letterboxing. The state is used for logging the time spent in 8437 * letterbox (sliced by the reason) vs non-letterbox per app. 8438 */ getAppCompatState()8439 int getAppCompatState() { 8440 return getAppCompatState(/* ignoreVisibility= */ false); 8441 } 8442 8443 /** 8444 * Same as {@link #getAppCompatState()} except when {@code ignoreVisibility} the visibility 8445 * of the activity is ignored. 8446 * 8447 * @param ignoreVisibility whether to ignore the visibility of the activity and not return 8448 * NOT_VISIBLE if {@code mVisibleRequested} is false. 8449 */ getAppCompatState(boolean ignoreVisibility)8450 private int getAppCompatState(boolean ignoreVisibility) { 8451 if (!ignoreVisibility && !mVisibleRequested) { 8452 return APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE; 8453 } 8454 // TODO(b/256564921): Investigate if we need new metrics for translucent activities 8455 if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { 8456 return mLetterboxUiController.getInheritedAppCompatState(); 8457 } 8458 if (mInSizeCompatModeForBounds) { 8459 return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE; 8460 } 8461 // Letterbox for fixed orientation. This check returns true only when an activity is 8462 // letterboxed for fixed orientation. Aspect ratio restrictions are also applied if 8463 // present. But this doesn't return true when the activity is letterboxed only because 8464 // of aspect ratio restrictions. 8465 if (isLetterboxedForFixedOrientationAndAspectRatio()) { 8466 return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION; 8467 } 8468 // Letterbox for limited aspect ratio. 8469 if (mIsAspectRatioApplied) { 8470 return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO; 8471 } 8472 8473 return APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED; 8474 } 8475 8476 /** 8477 * Adjusts position of resolved bounds if they don't fill the parent using gravity 8478 * requested in the config or via an ADB command. For more context see {@link 8479 * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)} and 8480 * {@link LetterboxUiController#getVerticalPositionMultiplier(Configuration)} 8481 * <p> 8482 * Note that this is the final step that can change the resolved bounds. After this method 8483 * is called, the position of the bounds will be moved to app space as sandboxing if the 8484 * activity has a size compat scale. 8485 */ updateResolvedBoundsPosition(Configuration newParentConfiguration)8486 private void updateResolvedBoundsPosition(Configuration newParentConfiguration) { 8487 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 8488 final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); 8489 if (resolvedBounds.isEmpty()) { 8490 return; 8491 } 8492 final Rect screenResolvedBounds = 8493 mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds; 8494 final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds(); 8495 final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds(); 8496 final float screenResolvedBoundsWidth = screenResolvedBounds.width(); 8497 final float parentAppBoundsWidth = parentAppBounds.width(); 8498 // Horizontal position 8499 int offsetX = 0; 8500 if (parentBounds.width() != screenResolvedBoundsWidth) { 8501 if (screenResolvedBoundsWidth <= parentAppBoundsWidth) { 8502 float positionMultiplier = mLetterboxUiController.getHorizontalPositionMultiplier( 8503 newParentConfiguration); 8504 offsetX = Math.max(0, (int) Math.ceil((parentAppBoundsWidth 8505 - screenResolvedBoundsWidth) * positionMultiplier) 8506 // This is added to make sure that insets added inside 8507 // CompatDisplayInsets#getContainerBounds() do not break the alignment 8508 // provided by the positionMultiplier 8509 - screenResolvedBounds.left + parentAppBounds.left); 8510 } 8511 } 8512 8513 final float parentAppBoundsHeight = parentAppBounds.height(); 8514 final float parentBoundsHeight = parentBounds.height(); 8515 final float screenResolvedBoundsHeight = screenResolvedBounds.height(); 8516 // Vertical position 8517 int offsetY = 0; 8518 if (parentBoundsHeight != screenResolvedBoundsHeight) { 8519 if (screenResolvedBoundsHeight <= parentAppBoundsHeight) { 8520 float positionMultiplier = mLetterboxUiController.getVerticalPositionMultiplier( 8521 newParentConfiguration); 8522 // If in immersive mode, always align to bottom and overlap bottom insets (nav bar, 8523 // task bar) as they are transient and hidden. This removes awkward bottom spacing. 8524 final float newHeight = mDisplayContent.getDisplayPolicy().isImmersiveMode() 8525 ? parentBoundsHeight : parentAppBoundsHeight; 8526 offsetY = Math.max(0, (int) Math.ceil((newHeight 8527 - screenResolvedBoundsHeight) * positionMultiplier) 8528 // This is added to make sure that insets added inside 8529 // CompatDisplayInsets#getContainerBounds() do not break the alignment 8530 // provided by the positionMultiplier 8531 - screenResolvedBounds.top + parentAppBounds.top); 8532 } 8533 } 8534 8535 if (mSizeCompatBounds != null) { 8536 mSizeCompatBounds.offset(offsetX , offsetY); 8537 final int dy = mSizeCompatBounds.top - resolvedBounds.top; 8538 final int dx = mSizeCompatBounds.left - resolvedBounds.left; 8539 offsetBounds(resolvedConfig, dx, dy); 8540 } else { 8541 offsetBounds(resolvedConfig, offsetX, offsetY); 8542 } 8543 8544 // If the top is aligned with parentAppBounds add the vertical insets back so that the app 8545 // content aligns with the status bar 8546 if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top) { 8547 resolvedConfig.windowConfiguration.getBounds().top = parentBounds.top; 8548 if (mSizeCompatBounds != null) { 8549 mSizeCompatBounds.top = parentBounds.top; 8550 } 8551 } 8552 8553 // Since bounds has changed, the configuration needs to be computed accordingly. 8554 getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration); 8555 8556 // The position of configuration bounds were calculated in screen space because that is 8557 // easier to resolve the relative position in parent container. However, if the activity is 8558 // scaled, the position should follow the scale because the configuration will be sent to 8559 // the client which is expected to be in a scaled environment. 8560 if (mSizeCompatScale != 1f) { 8561 final int screenPosX = resolvedBounds.left; 8562 final int screenPosY = resolvedBounds.top; 8563 final int dx = (int) (screenPosX / mSizeCompatScale + 0.5f) - screenPosX; 8564 final int dy = (int) (screenPosY / mSizeCompatScale + 0.5f) - screenPosY; 8565 offsetBounds(resolvedConfig, dx, dy); 8566 } 8567 } 8568 getScreenResolvedBounds()8569 @NonNull Rect getScreenResolvedBounds() { 8570 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 8571 final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); 8572 return mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds; 8573 } 8574 recomputeConfiguration()8575 void recomputeConfiguration() { 8576 // We check if the current activity is transparent. In that case we need to 8577 // recomputeConfiguration of the first opaque activity beneath, to allow a 8578 // proper computation of the new bounds. 8579 if (!mLetterboxUiController.applyOnOpaqueActivityBelow( 8580 ActivityRecord::recomputeConfiguration)) { 8581 onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration()); 8582 } 8583 } 8584 isInTransition()8585 boolean isInTransition() { 8586 return inTransitionSelfOrParent(); 8587 } 8588 isDisplaySleepingAndSwapping()8589 boolean isDisplaySleepingAndSwapping() { 8590 for (int i = mDisplayContent.mAllSleepTokens.size() - 1; i >= 0; i--) { 8591 RootWindowContainer.SleepToken sleepToken = mDisplayContent.mAllSleepTokens.get(i); 8592 if (sleepToken.isDisplaySwapping()) { 8593 return true; 8594 } 8595 } 8596 return false; 8597 } 8598 8599 /** 8600 * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed 8601 * orientation then aspect ratio restrictions are also already respected. 8602 * 8603 * <p>This happens when an activity has fixed orientation which doesn't match orientation of the 8604 * parent because a display setting 'ignoreOrientationRequest' is set to true. See {@link 8605 * WindowManagerService#getIgnoreOrientationRequest} for more context. 8606 */ isLetterboxedForFixedOrientationAndAspectRatio()8607 boolean isLetterboxedForFixedOrientationAndAspectRatio() { 8608 return mLetterboxBoundsForFixedOrientationAndAspectRatio != null; 8609 } 8610 isAspectRatioApplied()8611 boolean isAspectRatioApplied() { 8612 return mIsAspectRatioApplied; 8613 } 8614 8615 /** 8616 * Whether this activity is eligible for letterbox eduction. 8617 * 8618 * <p>Conditions that need to be met: 8619 * 8620 * <ul> 8621 * <li>{@link LetterboxConfiguration#getIsEducationEnabled} is true. 8622 * <li>The activity is eligible for fixed orientation letterbox. 8623 * <li>The activity is in fullscreen. 8624 * <li>The activity is portrait-only. 8625 * <li>The activity doesn't have a starting window (education should only be displayed 8626 * once the starting window is removed in {@link #removeStartingWindow}). 8627 * </ul> 8628 */ isEligibleForLetterboxEducation()8629 boolean isEligibleForLetterboxEducation() { 8630 return mWmService.mLetterboxConfiguration.getIsEducationEnabled() 8631 && mIsEligibleForFixedOrientationLetterbox 8632 && getWindowingMode() == WINDOWING_MODE_FULLSCREEN 8633 && getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT 8634 && mStartingWindow == null; 8635 } 8636 8637 /** 8638 * In some cases, applying insets to bounds changes the orientation. For example, if a 8639 * close-to-square display rotates to portrait to respect a portrait orientation activity, after 8640 * insets such as the status and nav bars are applied, the activity may actually have a 8641 * landscape orientation. This method checks whether the orientations of the activity window 8642 * with and without insets match or if the orientation with insets already matches the 8643 * requested orientation. If not, it may be necessary to letterbox the window. 8644 * @param parentBounds are the new parent bounds passed down to the activity and should be used 8645 * to compute the stable bounds. 8646 * @param outStableBounds will store the stable bounds, which are the bounds with insets 8647 * applied, if orientation is not respected when insets are applied. 8648 * Otherwise outStableBounds will be empty. Stable bounds should be used 8649 * to compute letterboxed bounds if orientation is not respected when 8650 * insets are applied. 8651 */ orientationRespectedWithInsets(Rect parentBounds, Rect outStableBounds)8652 private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outStableBounds) { 8653 outStableBounds.setEmpty(); 8654 if (mDisplayContent == null) { 8655 return true; 8656 } 8657 // Only need to make changes if activity sets an orientation 8658 final int requestedOrientation = getRequestedConfigurationOrientation(); 8659 if (requestedOrientation == ORIENTATION_UNDEFINED) { 8660 return true; 8661 } 8662 // Compute parent orientation from bounds 8663 final int orientation = parentBounds.height() >= parentBounds.width() 8664 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; 8665 // Compute orientation from stable parent bounds (= parent bounds with insets applied) 8666 final DisplayInfo di = isFixedRotationTransforming() 8667 ? getFixedRotationTransformDisplayInfo() 8668 : mDisplayContent.getDisplayInfo(); 8669 final Task task = getTask(); 8670 task.calculateInsetFrames(mTmpBounds /* outNonDecorBounds */, 8671 outStableBounds /* outStableBounds */, parentBounds /* bounds */, di); 8672 final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width() 8673 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; 8674 // If orientation does not match the orientation with insets applied, then a 8675 // display rotation will not be enough to respect orientation. However, even if they do 8676 // not match but the orientation with insets applied matches the requested orientation, then 8677 // there is no need to modify the bounds because when insets are applied, the activity will 8678 // have the desired orientation. 8679 final boolean orientationRespectedWithInsets = orientation == orientationWithInsets 8680 || orientationWithInsets == requestedOrientation; 8681 if (orientationRespectedWithInsets) { 8682 outStableBounds.setEmpty(); 8683 } 8684 return orientationRespectedWithInsets; 8685 } 8686 8687 @Override handlesOrientationChangeFromDescendant(int orientation)8688 boolean handlesOrientationChangeFromDescendant(int orientation) { 8689 if (shouldIgnoreOrientationRequests()) { 8690 return false; 8691 } 8692 return super.handlesOrientationChangeFromDescendant(orientation); 8693 } 8694 8695 /** 8696 * Computes bounds (letterbox or pillarbox) when either: 8697 * 1. The parent doesn't handle the orientation change and the requested orientation is 8698 * different from the parent (see {@link DisplayContent#setIgnoreOrientationRequest()}. 8699 * 2. The parent handling the orientation is not enough. This occurs when the display rotation 8700 * may not be enough to respect orientation requests (see {@link 8701 * ActivityRecord#orientationRespectedWithInsets}). 8702 * 8703 * <p>If letterboxed due to fixed orientation then aspect ratio restrictions are also applied 8704 * in this method. 8705 */ resolveFixedOrientationConfiguration(@onNull Configuration newParentConfig)8706 private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig) { 8707 final Rect parentBounds = newParentConfig.windowConfiguration.getBounds(); 8708 final Rect stableBounds = new Rect(); 8709 // If orientation is respected when insets are applied, then stableBounds will be empty. 8710 boolean orientationRespectedWithInsets = 8711 orientationRespectedWithInsets(parentBounds, stableBounds); 8712 if (orientationRespectedWithInsets && handlesOrientationChangeFromDescendant( 8713 getOverrideOrientation())) { 8714 // No need to letterbox because of fixed orientation. Display will handle 8715 // fixed-orientation requests and a display rotation is enough to respect requested 8716 // orientation with insets applied. 8717 return; 8718 } 8719 // TODO(b/232898850): always respect fixed-orientation request. 8720 // Ignore orientation request for activity in ActivityEmbedding split. 8721 final TaskFragment organizedTf = getOrganizedTaskFragment(); 8722 if (organizedTf != null && !organizedTf.fillsParent()) { 8723 return; 8724 } 8725 8726 final Rect resolvedBounds = 8727 getResolvedOverrideConfiguration().windowConfiguration.getBounds(); 8728 final int parentOrientation = newParentConfig.orientation; 8729 8730 // If the activity requires a different orientation (either by override or activityInfo), 8731 // make it fit the available bounds by scaling down its bounds. 8732 final int forcedOrientation = getRequestedConfigurationOrientation(); 8733 8734 mIsEligibleForFixedOrientationLetterbox = forcedOrientation != ORIENTATION_UNDEFINED 8735 && forcedOrientation != parentOrientation; 8736 8737 if (!mIsEligibleForFixedOrientationLetterbox && (forcedOrientation == ORIENTATION_UNDEFINED 8738 || orientationRespectedWithInsets)) { 8739 return; 8740 } 8741 final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets(); 8742 8743 if (compatDisplayInsets != null && !compatDisplayInsets.mIsInFixedOrientationLetterbox) { 8744 // App prefers to keep its original size. 8745 // If the size compat is from previous fixed orientation letterboxing, we may want to 8746 // have fixed orientation letterbox again, otherwise it will show the size compat 8747 // restart button even if the restart bounds will be the same. 8748 return; 8749 } 8750 8751 // TODO(b/182268157): Explore using only one type of parentBoundsWithInsets, either app 8752 // bounds or stable bounds to unify aspect ratio logic. 8753 final Rect parentBoundsWithInsets = orientationRespectedWithInsets 8754 ? newParentConfig.windowConfiguration.getAppBounds() : stableBounds; 8755 final Rect containingBounds = new Rect(); 8756 final Rect containingBoundsWithInsets = new Rect(); 8757 // Need to shrink the containing bounds into a square because the parent orientation 8758 // does not match the activity requested orientation. 8759 if (forcedOrientation == ORIENTATION_LANDSCAPE) { 8760 // Landscape is defined as width > height. Make the container respect landscape 8761 // orientation by shrinking height to one less than width. Landscape activity will be 8762 // vertically centered within parent bounds with insets, so position vertical bounds 8763 // within parent bounds with insets to prevent insets from unnecessarily trimming 8764 // vertical bounds. 8765 final int bottom = Math.min(parentBoundsWithInsets.top + parentBounds.width() - 1, 8766 parentBoundsWithInsets.bottom); 8767 containingBounds.set(parentBounds.left, parentBoundsWithInsets.top, parentBounds.right, 8768 bottom); 8769 containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top, 8770 parentBoundsWithInsets.right, bottom); 8771 } else { 8772 // Portrait is defined as width <= height. Make the container respect portrait 8773 // orientation by shrinking width to match height. Portrait activity will be 8774 // horizontally centered within parent bounds with insets, so position horizontal bounds 8775 // within parent bounds with insets to prevent insets from unnecessarily trimming 8776 // horizontal bounds. 8777 final int right = Math.min(parentBoundsWithInsets.left + parentBounds.height(), 8778 parentBoundsWithInsets.right); 8779 containingBounds.set(parentBoundsWithInsets.left, parentBounds.top, right, 8780 parentBounds.bottom); 8781 containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top, 8782 right, parentBoundsWithInsets.bottom); 8783 } 8784 8785 // Store the current bounds to be able to revert to size compat mode values below if needed. 8786 final Rect prevResolvedBounds = new Rect(resolvedBounds); 8787 resolvedBounds.set(containingBounds); 8788 8789 final float letterboxAspectRatioOverride = 8790 mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig); 8791 8792 // Aspect ratio as suggested by the system. Apps requested mix/max aspect ratio will 8793 // be respected in #applyAspectRatio. 8794 final float desiredAspectRatio; 8795 if (isDefaultMultiWindowLetterboxAspectRatioDesired(newParentConfig)) { 8796 desiredAspectRatio = DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW; 8797 } else if (letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) { 8798 desiredAspectRatio = letterboxAspectRatioOverride; 8799 } else { 8800 desiredAspectRatio = computeAspectRatio(parentBounds); 8801 } 8802 8803 // Apply aspect ratio to resolved bounds 8804 mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets, 8805 containingBounds, desiredAspectRatio); 8806 8807 if (compatDisplayInsets != null) { 8808 compatDisplayInsets.getBoundsByRotation(mTmpBounds, 8809 newParentConfig.windowConfiguration.getRotation()); 8810 if (resolvedBounds.width() != mTmpBounds.width() 8811 || resolvedBounds.height() != mTmpBounds.height()) { 8812 // The app shouldn't be resized, we only do fixed orientation letterboxing if the 8813 // compat bounds are also from the same fixed orientation letterbox. Otherwise, 8814 // clear the fixed orientation bounds to show app in size compat mode. 8815 resolvedBounds.set(prevResolvedBounds); 8816 return; 8817 } 8818 } 8819 8820 // Calculate app bounds using fixed orientation bounds because they will be needed later 8821 // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}. 8822 getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(), 8823 newParentConfig, compatDisplayInsets); 8824 mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds); 8825 } 8826 8827 /** 8828 * Returns {@code true} if the default aspect ratio for a letterboxed app in multi-window mode 8829 * should be used. 8830 */ isDefaultMultiWindowLetterboxAspectRatioDesired( @onNull Configuration parentConfig)8831 private boolean isDefaultMultiWindowLetterboxAspectRatioDesired( 8832 @NonNull Configuration parentConfig) { 8833 if (mDisplayContent == null) { 8834 return false; 8835 } 8836 final int windowingMode = parentConfig.windowConfiguration.getWindowingMode(); 8837 return WindowConfiguration.inMultiWindowMode(windowingMode) 8838 && !mDisplayContent.getIgnoreOrientationRequest(); 8839 } 8840 8841 /** 8842 * Resolves aspect ratio restrictions for an activity. If the bounds are restricted by 8843 * aspect ratio, the position will be adjusted later in {@link #updateResolvedBoundsPosition 8844 * within parent's app bounds to balance the visual appearance. The policy of aspect ratio has 8845 * higher priority than the requested override bounds. 8846 */ resolveAspectRatioRestriction(Configuration newParentConfiguration)8847 private void resolveAspectRatioRestriction(Configuration newParentConfiguration) { 8848 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 8849 final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds(); 8850 final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds(); 8851 final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); 8852 // Use tmp bounds to calculate aspect ratio so we can know whether the activity should use 8853 // restricted size (resolved bounds may be the requested override bounds). 8854 mTmpBounds.setEmpty(); 8855 mIsAspectRatioApplied = applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds); 8856 // If the out bounds is not empty, it means the activity cannot fill parent's app bounds, 8857 // then they should be aligned later in #updateResolvedBoundsPosition() 8858 if (!mTmpBounds.isEmpty()) { 8859 resolvedBounds.set(mTmpBounds); 8860 } 8861 if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) { 8862 // Compute the configuration based on the resolved bounds. If aspect ratio doesn't 8863 // restrict, the bounds should be the requested override bounds. 8864 getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, 8865 getFixedRotationTransformDisplayInfo()); 8866 } 8867 } 8868 8869 /** 8870 * Resolves consistent screen configuration for orientation and rotation changes without 8871 * inheriting the parent bounds. 8872 */ resolveSizeCompatModeConfiguration(Configuration newParentConfiguration, @NonNull CompatDisplayInsets compatDisplayInsets)8873 private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration, 8874 @NonNull CompatDisplayInsets compatDisplayInsets) { 8875 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 8876 final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); 8877 8878 // When an activity needs to be letterboxed because of fixed orientation, use fixed 8879 // orientation bounds (stored in resolved bounds) instead of parent bounds since the 8880 // activity will be displayed within them even if it is in size compat mode. They should be 8881 // saved here before resolved bounds are overridden below. 8882 final Rect containerBounds = isLetterboxedForFixedOrientationAndAspectRatio() 8883 ? new Rect(resolvedBounds) 8884 : newParentConfiguration.windowConfiguration.getBounds(); 8885 final Rect containerAppBounds = isLetterboxedForFixedOrientationAndAspectRatio() 8886 ? new Rect(getResolvedOverrideConfiguration().windowConfiguration.getAppBounds()) 8887 : newParentConfiguration.windowConfiguration.getAppBounds(); 8888 8889 final int requestedOrientation = getRequestedConfigurationOrientation(); 8890 final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED; 8891 final int orientation = orientationRequested 8892 ? requestedOrientation 8893 // We should use the original orientation of the activity when possible to avoid 8894 // forcing the activity in the opposite orientation. 8895 : compatDisplayInsets.mOriginalRequestedOrientation != ORIENTATION_UNDEFINED 8896 ? compatDisplayInsets.mOriginalRequestedOrientation 8897 : newParentConfiguration.orientation; 8898 int rotation = newParentConfiguration.windowConfiguration.getRotation(); 8899 final boolean isFixedToUserRotation = mDisplayContent == null 8900 || mDisplayContent.getDisplayRotation().isFixedToUserRotation(); 8901 if (!isFixedToUserRotation && !compatDisplayInsets.mIsFloating) { 8902 // Use parent rotation because the original display can be rotated. 8903 resolvedConfig.windowConfiguration.setRotation(rotation); 8904 } else { 8905 final int overrideRotation = resolvedConfig.windowConfiguration.getRotation(); 8906 if (overrideRotation != ROTATION_UNDEFINED) { 8907 rotation = overrideRotation; 8908 } 8909 } 8910 8911 // Use compat insets to lock width and height. We should not use the parent width and height 8912 // because apps in compat mode should have a constant width and height. The compat insets 8913 // are locked when the app is first launched and are never changed after that, so we can 8914 // rely on them to contain the original and unchanging width and height of the app. 8915 final Rect containingAppBounds = new Rect(); 8916 final Rect containingBounds = mTmpBounds; 8917 compatDisplayInsets.getContainerBounds(containingAppBounds, containingBounds, rotation, 8918 orientation, orientationRequested, isFixedToUserRotation); 8919 resolvedBounds.set(containingBounds); 8920 // The size of floating task is fixed (only swap), so the aspect ratio is already correct. 8921 if (!compatDisplayInsets.mIsFloating) { 8922 mIsAspectRatioApplied = 8923 applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds); 8924 } 8925 8926 // Use resolvedBounds to compute other override configurations such as appBounds. The bounds 8927 // are calculated in compat container space. The actual position on screen will be applied 8928 // later, so the calculation is simpler that doesn't need to involve offset from parent. 8929 getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, 8930 compatDisplayInsets); 8931 // Use current screen layout as source because the size of app is independent to parent. 8932 resolvedConfig.screenLayout = computeScreenLayout( 8933 getConfiguration().screenLayout, resolvedConfig.screenWidthDp, 8934 resolvedConfig.screenHeightDp); 8935 8936 // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside 8937 // the parent bounds appropriately. 8938 if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) { 8939 resolvedConfig.orientation = newParentConfiguration.orientation; 8940 } 8941 8942 // Below figure is an example that puts an activity which was launched in a larger container 8943 // into a smaller container. 8944 // The outermost rectangle is the real display bounds. 8945 // "@" is the container app bounds (parent bounds or fixed orientation bounds) 8946 // "#" is the {@code resolvedBounds} that applies to application. 8947 // "*" is the {@code mSizeCompatBounds} that used to show on screen if scaled. 8948 // ------------------------------ 8949 // | | 8950 // | @@@@*********@@@@### | 8951 // | @ * * @ # | 8952 // | @ * * @ # | 8953 // | @ * * @ # | 8954 // | @@@@*********@@@@ # | 8955 // ---------#--------------#----- 8956 // # # 8957 // ################ 8958 // The application is still layouted in "#" since it was launched, and it will be visually 8959 // scaled and positioned to "*". 8960 8961 final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds(); 8962 8963 // Calculates the scale the size compatibility bounds into the region which is available 8964 // to application. 8965 final float lastSizeCompatScale = mSizeCompatScale; 8966 updateSizeCompatScale(resolvedAppBounds, containerAppBounds); 8967 8968 final int containerTopInset = containerAppBounds.top - containerBounds.top; 8969 final boolean topNotAligned = 8970 containerTopInset != resolvedAppBounds.top - resolvedBounds.top; 8971 if (mSizeCompatScale != 1f || topNotAligned) { 8972 if (mSizeCompatBounds == null) { 8973 mSizeCompatBounds = new Rect(); 8974 } 8975 mSizeCompatBounds.set(resolvedAppBounds); 8976 mSizeCompatBounds.offsetTo(0, 0); 8977 mSizeCompatBounds.scale(mSizeCompatScale); 8978 // The insets are included in height, e.g. the area of real cutout shouldn't be scaled. 8979 mSizeCompatBounds.bottom += containerTopInset; 8980 } else { 8981 mSizeCompatBounds = null; 8982 } 8983 if (mSizeCompatScale != lastSizeCompatScale) { 8984 forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */); 8985 } 8986 8987 // The position will be later adjusted in updateResolvedBoundsPosition. 8988 // Above coordinates are in "@" space, now place "*" and "#" to screen space. 8989 final boolean fillContainer = resolvedBounds.equals(containingBounds); 8990 final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left; 8991 final int screenPosY = fillContainer ? containerBounds.top : containerAppBounds.top; 8992 8993 if (screenPosX != 0 || screenPosY != 0) { 8994 if (mSizeCompatBounds != null) { 8995 mSizeCompatBounds.offset(screenPosX, screenPosY); 8996 } 8997 // Add the global coordinates and remove the local coordinates. 8998 final int dx = screenPosX - resolvedBounds.left; 8999 final int dy = screenPosY - resolvedBounds.top; 9000 offsetBounds(resolvedConfig, dx, dy); 9001 } 9002 9003 mInSizeCompatModeForBounds = 9004 isInSizeCompatModeForBounds(resolvedAppBounds, containerAppBounds); 9005 } 9006 updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds)9007 void updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds) { 9008 // Only allow to scale down. 9009 mSizeCompatScale = mLetterboxUiController.findOpaqueNotFinishingActivityBelow() 9010 .map(activityRecord -> activityRecord.mSizeCompatScale) 9011 .orElseGet(() -> { 9012 final int contentW = resolvedAppBounds.width(); 9013 final int contentH = resolvedAppBounds.height(); 9014 final int viewportW = containerAppBounds.width(); 9015 final int viewportH = containerAppBounds.height(); 9016 return (contentW <= viewportW && contentH <= viewportH) ? 1f : Math.min( 9017 (float) viewportW / contentW, (float) viewportH / contentH); 9018 }); 9019 } 9020 isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds)9021 private boolean isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds) { 9022 if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { 9023 // To avoid wrong app behaviour, we decided to disable SCM when a translucent activity 9024 // is letterboxed. 9025 return false; 9026 } 9027 final int appWidth = appBounds.width(); 9028 final int appHeight = appBounds.height(); 9029 final int containerAppWidth = containerBounds.width(); 9030 final int containerAppHeight = containerBounds.height(); 9031 9032 if (containerAppWidth == appWidth && containerAppHeight == appHeight) { 9033 // Matched the container bounds. 9034 return false; 9035 } 9036 if (containerAppWidth > appWidth && containerAppHeight > appHeight) { 9037 // Both sides are smaller than the container. 9038 return true; 9039 } 9040 if (containerAppWidth < appWidth || containerAppHeight < appHeight) { 9041 // One side is larger than the container. 9042 return true; 9043 } 9044 9045 // The rest of the condition is that only one side is smaller than the container, but it 9046 // still needs to exclude the cases where the size is limited by the fixed aspect ratio. 9047 final float maxAspectRatio = getMaxAspectRatio(); 9048 if (maxAspectRatio > 0) { 9049 final float aspectRatio = (0.5f + Math.max(appWidth, appHeight)) 9050 / Math.min(appWidth, appHeight); 9051 if (aspectRatio >= maxAspectRatio) { 9052 // The current size has reached the max aspect ratio. 9053 return false; 9054 } 9055 } 9056 final float minAspectRatio = getMinAspectRatio(); 9057 if (minAspectRatio > 0) { 9058 // The activity should have at least the min aspect ratio, so this checks if the 9059 // container still has available space to provide larger aspect ratio. 9060 final float containerAspectRatio = 9061 (0.5f + Math.max(containerAppWidth, containerAppHeight)) 9062 / Math.min(containerAppWidth, containerAppHeight); 9063 if (containerAspectRatio <= minAspectRatio) { 9064 // The long side has reached the parent. 9065 return false; 9066 } 9067 } 9068 return true; 9069 } 9070 9071 /** @return The horizontal / vertical offset of putting the content in the center of viewport.*/ getCenterOffset(int viewportDim, int contentDim)9072 private static int getCenterOffset(int viewportDim, int contentDim) { 9073 return (int) ((viewportDim - contentDim + 1) * 0.5f); 9074 } 9075 offsetBounds(Configuration inOutConfig, int offsetX, int offsetY)9076 private static void offsetBounds(Configuration inOutConfig, int offsetX, int offsetY) { 9077 inOutConfig.windowConfiguration.getBounds().offset(offsetX, offsetY); 9078 inOutConfig.windowConfiguration.getAppBounds().offset(offsetX, offsetY); 9079 } 9080 9081 @Override getBounds()9082 public Rect getBounds() { 9083 // TODO(b/268458693): Refactor configuration inheritance in case of translucent activities 9084 final Rect superBounds = super.getBounds(); 9085 return mLetterboxUiController.findOpaqueNotFinishingActivityBelow() 9086 .map(ActivityRecord::getBounds) 9087 .orElseGet(() -> { 9088 if (mSizeCompatBounds != null) { 9089 return mSizeCompatBounds; 9090 } 9091 return superBounds; 9092 }); 9093 } 9094 9095 @Override 9096 public boolean providesMaxBounds() { 9097 // System should always be able to access the DisplayArea bounds, so do not provide it with 9098 // compat max window bounds. 9099 if (getUid() == SYSTEM_UID) { 9100 return false; 9101 } 9102 // Do not sandbox to activity window bounds if the feature is disabled. 9103 if (mDisplayContent != null && !mDisplayContent.sandboxDisplayApis()) { 9104 return false; 9105 } 9106 // Never apply sandboxing to an app that should be explicitly excluded from the config. 9107 if (info.neverSandboxDisplayApis(sConstrainDisplayApisConfig)) { 9108 return false; 9109 } 9110 // Always apply sandboxing to an app that should be explicitly included from the config. 9111 if (info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig)) { 9112 return true; 9113 } 9114 // Max bounds should be sandboxed when an activity should have compatDisplayInsets, and it 9115 // will keep the same bounds and screen configuration when it was first launched regardless 9116 // how its parent window changes, so that the sandbox API will provide a consistent result. 9117 if (getCompatDisplayInsets() != null || shouldCreateCompatDisplayInsets()) { 9118 return true; 9119 } 9120 9121 // No need to sandbox for resizable apps in (including in multi-window) because 9122 // resizableActivity=true indicates that they support multi-window. Likewise, do not sandbox 9123 // for activities in letterbox since the activity has declared it can handle resizing. 9124 return false; 9125 } 9126 9127 @VisibleForTesting 9128 @Override 9129 Rect getAnimationBounds(int appRootTaskClipMode) { 9130 // Use TaskFragment-bounds if available so that activity-level letterbox (maxAspectRatio) is 9131 // included in the animation. 9132 final TaskFragment taskFragment = getTaskFragment(); 9133 return taskFragment != null ? taskFragment.getBounds() : getBounds(); 9134 } 9135 9136 @Override 9137 void getAnimationPosition(Point outPosition) { 9138 // Always animate from zero because if the activity doesn't fill the task, the letterbox 9139 // will fill the remaining area that should be included in the animation. 9140 outPosition.set(0, 0); 9141 } 9142 9143 @Override 9144 public void onConfigurationChanged(Configuration newParentConfig) { 9145 // We want to collect the ActivityRecord if the windowing mode is changed, so that it will 9146 // dispatch app transition finished event correctly at the end. 9147 // Check #isVisible() because we don't want to animate for activity that stays invisible. 9148 // Activity with #isVisibleRequested() changed should be collected when that is requested. 9149 if (mTransitionController.isShellTransitionsEnabled() && isVisible() 9150 && isVisibleRequested()) { 9151 final int projectedWindowingMode = 9152 getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED 9153 ? newParentConfig.windowConfiguration.getWindowingMode() 9154 : getRequestedOverrideWindowingMode(); 9155 if (getWindowingMode() != projectedWindowingMode) { 9156 mTransitionController.collect(this); 9157 } 9158 } 9159 if (getCompatDisplayInsets() != null) { 9160 Configuration overrideConfig = getRequestedOverrideConfiguration(); 9161 // Adapt to changes in orientation locking. The app is still non-resizable, but 9162 // it can change which orientation is fixed. If the fixed orientation changes, 9163 // update the rotation used on the "compat" display 9164 boolean wasFixedOrient = 9165 overrideConfig.windowConfiguration.getRotation() != ROTATION_UNDEFINED; 9166 int requestedOrient = getRequestedConfigurationOrientation(); 9167 if (requestedOrient != ORIENTATION_UNDEFINED 9168 && requestedOrient != getConfiguration().orientation 9169 // The task orientation depends on the top activity orientation, so it 9170 // should match. If it doesn't, just wait until it does. 9171 && requestedOrient == getParent().getConfiguration().orientation 9172 && (overrideConfig.windowConfiguration.getRotation() 9173 != getParent().getWindowConfiguration().getRotation())) { 9174 overrideConfig.windowConfiguration.setRotation( 9175 getParent().getWindowConfiguration().getRotation()); 9176 onRequestedOverrideConfigurationChanged(overrideConfig); 9177 return; 9178 } else if (wasFixedOrient && requestedOrient == ORIENTATION_UNDEFINED 9179 && (overrideConfig.windowConfiguration.getRotation() 9180 != ROTATION_UNDEFINED)) { 9181 overrideConfig.windowConfiguration.setRotation(ROTATION_UNDEFINED); 9182 onRequestedOverrideConfigurationChanged(overrideConfig); 9183 return; 9184 } 9185 } 9186 9187 final boolean wasInPictureInPicture = inPinnedWindowingMode(); 9188 final DisplayContent display = mDisplayContent; 9189 final int activityType = getActivityType(); 9190 if (wasInPictureInPicture && attachedToProcess() && display != null) { 9191 // If the PIP activity is changing to fullscreen with display orientation change, the 9192 // fixed rotation will take effect that requires to send fixed rotation adjustments 9193 // before the process configuration (if the process is a configuration listener of the 9194 // activity). So when performing process configuration on client side, it can apply 9195 // the adjustments (see WindowToken#onFixedRotationStatePrepared). 9196 try { 9197 app.pauseConfigurationDispatch(); 9198 super.onConfigurationChanged(newParentConfig); 9199 if (mVisibleRequested && !inMultiWindowMode()) { 9200 final int rotation = display.rotationForActivityInDifferentOrientation(this); 9201 if (rotation != ROTATION_UNDEFINED) { 9202 app.resumeConfigurationDispatch(); 9203 display.setFixedRotationLaunchingApp(this, rotation); 9204 } 9205 } 9206 } finally { 9207 if (app.resumeConfigurationDispatch()) { 9208 app.dispatchConfiguration(app.getConfiguration()); 9209 } 9210 } 9211 } else { 9212 super.onConfigurationChanged(newParentConfig); 9213 } 9214 if (activityType != ACTIVITY_TYPE_UNDEFINED 9215 && activityType != getActivityType()) { 9216 final String errorMessage = "Can't change activity type once set: " + this 9217 + " activityType=" + activityTypeToString(getActivityType()) + ", was " 9218 + activityTypeToString(activityType); 9219 if (Build.IS_DEBUGGABLE) { 9220 throw new IllegalStateException(errorMessage); 9221 } 9222 Slog.w(TAG, errorMessage); 9223 } 9224 9225 // Configuration's equality doesn't consider seq so if only seq number changes in resolved 9226 // override configuration. Therefore ConfigurationContainer doesn't change merged override 9227 // configuration, but it's used to push configuration changes so explicitly update that. 9228 if (getMergedOverrideConfiguration().seq != getResolvedOverrideConfiguration().seq) { 9229 onMergedOverrideConfigurationChanged(); 9230 } 9231 9232 // Before PiP animation is done, th windowing mode of the activity is still the previous 9233 // mode (see RootWindowContainer#moveActivityToPinnedRootTask). So once the windowing mode 9234 // of activity is changed, it is the signal of the last step to update the PiP states. 9235 if (!wasInPictureInPicture && inPinnedWindowingMode() && task != null) { 9236 mWaitForEnteringPinnedMode = false; 9237 mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, task.getBounds()); 9238 } 9239 9240 if (display == null) { 9241 return; 9242 } 9243 if (mVisibleRequested) { 9244 // It may toggle the UI for user to restart the size compatibility mode activity. 9245 display.handleActivitySizeCompatModeIfNeeded(this); 9246 } else if (getCompatDisplayInsets() != null && !visibleIgnoringKeyguard 9247 && (app == null || !app.hasVisibleActivities())) { 9248 // visibleIgnoringKeyguard is checked to avoid clearing mCompatDisplayInsets during 9249 // displays change. Displays are turned off during the change so mVisibleRequested 9250 // can be false. 9251 // The override changes can only be obtained from display, because we don't have the 9252 // difference of full configuration in each hierarchy. 9253 final int displayChanges = display.getCurrentOverrideConfigurationChanges(); 9254 final int orientationChanges = CONFIG_WINDOW_CONFIGURATION 9255 | CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION; 9256 final boolean hasNonOrienSizeChanged = hasResizeChange(displayChanges) 9257 // Filter out the case of simple orientation change. 9258 && (displayChanges & orientationChanges) != orientationChanges; 9259 // For background activity that uses size compatibility mode, if the size or density of 9260 // the display is changed, then reset the override configuration and kill the activity's 9261 // process if its process state is not important to user. 9262 if (hasNonOrienSizeChanged || (displayChanges & ActivityInfo.CONFIG_DENSITY) != 0) { 9263 restartProcessIfVisible(); 9264 } 9265 } 9266 } 9267 9268 private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds, 9269 Rect containingBounds) { 9270 return applyAspectRatio(outBounds, containingAppBounds, containingBounds, 9271 0 /* desiredAspectRatio */); 9272 } 9273 9274 /** 9275 * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is 9276 * made to outBounds. 9277 * 9278 * @return {@code true} if aspect ratio restrictions were applied. 9279 */ 9280 // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. 9281 private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds, 9282 Rect containingBounds, float desiredAspectRatio) { 9283 final float maxAspectRatio = getMaxAspectRatio(); 9284 final Task rootTask = getRootTask(); 9285 final float minAspectRatio = getMinAspectRatio(); 9286 final TaskFragment organizedTf = getOrganizedTaskFragment(); 9287 if (task == null || rootTask == null 9288 || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1) 9289 // Don't set aspect ratio if we are in VR mode. 9290 || isInVrUiMode(getConfiguration()) 9291 // TODO(b/232898850): Always respect aspect ratio requests. 9292 // Don't set aspect ratio for activity in ActivityEmbedding split. 9293 || (organizedTf != null && !organizedTf.fillsParent())) { 9294 return false; 9295 } 9296 9297 final int containingAppWidth = containingAppBounds.width(); 9298 final int containingAppHeight = containingAppBounds.height(); 9299 final float containingRatio = computeAspectRatio(containingAppBounds); 9300 9301 if (desiredAspectRatio < 1) { 9302 desiredAspectRatio = containingRatio; 9303 } 9304 9305 if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) { 9306 desiredAspectRatio = maxAspectRatio; 9307 } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) { 9308 desiredAspectRatio = minAspectRatio; 9309 } 9310 9311 int activityWidth = containingAppWidth; 9312 int activityHeight = containingAppHeight; 9313 9314 if (containingRatio - desiredAspectRatio > ASPECT_RATIO_ROUNDING_TOLERANCE) { 9315 if (containingAppWidth < containingAppHeight) { 9316 // Width is the shorter side, so we use that to figure-out what the max. height 9317 // should be given the aspect ratio. 9318 activityHeight = (int) ((activityWidth * desiredAspectRatio) + 0.5f); 9319 } else { 9320 // Height is the shorter side, so we use that to figure-out what the max. width 9321 // should be given the aspect ratio. 9322 activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f); 9323 } 9324 } else if (desiredAspectRatio - containingRatio > ASPECT_RATIO_ROUNDING_TOLERANCE) { 9325 boolean adjustWidth; 9326 switch (getRequestedConfigurationOrientation()) { 9327 case ORIENTATION_LANDSCAPE: 9328 // Width should be the longer side for this landscape app, so we use the width 9329 // to figure-out what the max. height should be given the aspect ratio. 9330 adjustWidth = false; 9331 break; 9332 case ORIENTATION_PORTRAIT: 9333 // Height should be the longer side for this portrait app, so we use the height 9334 // to figure-out what the max. width should be given the aspect ratio. 9335 adjustWidth = true; 9336 break; 9337 default: 9338 // This app doesn't have a preferred orientation, so we keep the length of the 9339 // longer side, and use it to figure-out the length of the shorter side. 9340 if (containingAppWidth < containingAppHeight) { 9341 // Width is the shorter side, so we use the height to figure-out what the 9342 // max. width should be given the aspect ratio. 9343 adjustWidth = true; 9344 } else { 9345 // Height is the shorter side, so we use the width to figure-out what the 9346 // max. height should be given the aspect ratio. 9347 adjustWidth = false; 9348 } 9349 break; 9350 } 9351 if (adjustWidth) { 9352 activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f); 9353 } else { 9354 activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f); 9355 } 9356 } 9357 9358 if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) { 9359 // The display matches or is less than the activity aspect ratio, so nothing else to do. 9360 return false; 9361 } 9362 9363 // Compute configuration based on max or min supported width and height. 9364 // Also account for the insets (e.g. display cutouts, navigation bar), which will be 9365 // clipped away later in {@link Task#computeConfigResourceOverrides()}, i.e., the out 9366 // bounds are the app bounds restricted by aspect ratio + clippable insets. Otherwise, 9367 // the app bounds would end up too small. To achieve this we will also add clippable insets 9368 // when the corresponding dimension fully fills the parent 9369 9370 int right = activityWidth + containingAppBounds.left; 9371 int left = containingAppBounds.left; 9372 if (right >= containingAppBounds.right) { 9373 right = containingBounds.right; 9374 left = containingBounds.left; 9375 } 9376 int bottom = activityHeight + containingAppBounds.top; 9377 int top = containingAppBounds.top; 9378 if (bottom >= containingAppBounds.bottom) { 9379 bottom = containingBounds.bottom; 9380 top = containingBounds.top; 9381 } 9382 outBounds.set(left, top, right, bottom); 9383 return true; 9384 } 9385 9386 /** 9387 * Returns the min aspect ratio of this activity. 9388 */ 9389 float getMinAspectRatio() { 9390 if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { 9391 return mLetterboxUiController.getInheritedMinAspectRatio(); 9392 } 9393 if (info.applicationInfo == null) { 9394 return info.getMinAspectRatio(); 9395 } 9396 if (mLetterboxUiController.shouldApplyUserMinAspectRatioOverride()) { 9397 return mLetterboxUiController.getUserMinAspectRatio(); 9398 } 9399 if (!mLetterboxUiController.shouldOverrideMinAspectRatio()) { 9400 return info.getMinAspectRatio(); 9401 } 9402 9403 if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY) 9404 && !ActivityInfo.isFixedOrientationPortrait( 9405 getOverrideOrientation())) { 9406 return info.getMinAspectRatio(); 9407 } 9408 9409 if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN) 9410 && isParentFullscreenPortrait()) { 9411 // We are using the parent configuration here as this is the most recent one that gets 9412 // passed to onConfigurationChanged when a relevant change takes place 9413 return info.getMinAspectRatio(); 9414 } 9415 9416 if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN)) { 9417 return Math.max(mLetterboxUiController.getSplitScreenAspectRatio(), 9418 info.getMinAspectRatio()); 9419 } 9420 9421 if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) { 9422 return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, 9423 info.getMinAspectRatio()); 9424 } 9425 9426 if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) { 9427 return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, 9428 info.getMinAspectRatio()); 9429 } 9430 return info.getMinAspectRatio(); 9431 } 9432 9433 private boolean isParentFullscreenPortrait() { 9434 final WindowContainer parent = getParent(); 9435 return parent != null 9436 && parent.getConfiguration().orientation == ORIENTATION_PORTRAIT 9437 && parent.getWindowConfiguration().getWindowingMode() == WINDOWING_MODE_FULLSCREEN; 9438 } 9439 9440 float getMaxAspectRatio() { 9441 if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { 9442 return mLetterboxUiController.getInheritedMaxAspectRatio(); 9443 } 9444 return info.getMaxAspectRatio(); 9445 } 9446 9447 /** 9448 * Returns true if the activity has maximum or minimum aspect ratio. 9449 */ 9450 private boolean hasFixedAspectRatio() { 9451 return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0; 9452 } 9453 9454 /** 9455 * Returns the aspect ratio of the given {@code rect}. 9456 */ 9457 static float computeAspectRatio(Rect rect) { 9458 final int width = rect.width(); 9459 final int height = rect.height(); 9460 if (width == 0 || height == 0) { 9461 return 0; 9462 } 9463 return Math.max(width, height) / (float) Math.min(width, height); 9464 } 9465 9466 /** 9467 * @return {@code true} if this activity was reparented to another display but 9468 * {@link #ensureActivityConfiguration} is not called. 9469 */ 9470 boolean shouldUpdateConfigForDisplayChanged() { 9471 return mLastReportedDisplayId != getDisplayId(); 9472 } 9473 9474 boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) { 9475 return ensureActivityConfiguration(globalChanges, preserveWindow, 9476 false /* ignoreVisibility */, false /* isRequestedOrientationChanged */); 9477 } 9478 9479 boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow, 9480 boolean ignoreVisibility) { 9481 return ensureActivityConfiguration(globalChanges, preserveWindow, ignoreVisibility, 9482 false /* isRequestedOrientationChanged */); 9483 } 9484 9485 /** 9486 * Make sure the given activity matches the current configuration. Ensures the HistoryRecord 9487 * is updated with the correct configuration and all other bookkeeping is handled. 9488 * 9489 * @param globalChanges The changes to the global configuration. 9490 * @param preserveWindow If the activity window should be preserved on screen if the activity 9491 * is relaunched. 9492 * @param ignoreVisibility If we should try to relaunch the activity even if it is invisible 9493 * (stopped state). This is useful for the case where we know the 9494 * activity will be visible soon and we want to ensure its configuration 9495 * before we make it visible. 9496 * @param isRequestedOrientationChanged whether this is triggered in response to an app calling 9497 * {@link android.app.Activity#setRequestedOrientation}. 9498 * @return False if the activity was relaunched and true if it wasn't relaunched because we 9499 * can't or the app handles the specific configuration that is changing. 9500 */ 9501 boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow, 9502 boolean ignoreVisibility, boolean isRequestedOrientationChanged) { 9503 final Task rootTask = getRootTask(); 9504 if (rootTask.mConfigWillChange) { 9505 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check " 9506 + "(will change): %s", this); 9507 return true; 9508 } 9509 9510 // We don't worry about activities that are finishing. 9511 if (finishing) { 9512 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter " 9513 + "in finishing %s", this); 9514 stopFreezingScreenLocked(false); 9515 return true; 9516 } 9517 9518 if (isState(DESTROYED)) { 9519 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check " 9520 + "in destroyed state %s", this); 9521 return true; 9522 } 9523 9524 if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) { 9525 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check " 9526 + "invisible: %s", this); 9527 return true; 9528 } 9529 9530 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Ensuring correct " 9531 + "configuration: %s", this); 9532 9533 final int newDisplayId = getDisplayId(); 9534 final boolean displayChanged = mLastReportedDisplayId != newDisplayId; 9535 if (displayChanged) { 9536 mLastReportedDisplayId = newDisplayId; 9537 } 9538 9539 // Calling from here rather than from onConfigurationChanged because it's possible that 9540 // onConfigurationChanged was called before mVisibleRequested became true and 9541 // mCompatDisplayInsets may not be called again when mVisibleRequested changes. And we 9542 // don't want to save mCompatDisplayInsets in onConfigurationChanged without visibility 9543 // check to avoid remembering obsolete configuration which can lead to unnecessary 9544 // size-compat mode. 9545 if (mVisibleRequested) { 9546 // Calling from here rather than resolveOverrideConfiguration to ensure that this is 9547 // called after full config is updated in ConfigurationContainer#onConfigurationChanged. 9548 updateCompatDisplayInsets(); 9549 } 9550 9551 // Short circuit: if the two full configurations are equal (the common case), then there is 9552 // nothing to do. We test the full configuration instead of the global and merged override 9553 // configurations because there are cases (like moving a task to the root pinned task) where 9554 // the combine configurations are equal, but would otherwise differ in the override config 9555 mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration()); 9556 if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) { 9557 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display " 9558 + "unchanged in %s", this); 9559 return true; 9560 } 9561 9562 // Okay we now are going to make this activity have the new config. 9563 // But then we need to figure out how it needs to deal with that. 9564 9565 // Find changes between last reported merged configuration and the current one. This is used 9566 // to decide whether to relaunch an activity or just report a configuration change. 9567 final int changes = getConfigurationChanges(mTmpConfig); 9568 9569 // Update last reported values. 9570 final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration(); 9571 9572 setLastReportedConfiguration(getProcessGlobalConfiguration(), newMergedOverrideConfig); 9573 9574 if (mState == INITIALIZING) { 9575 // No need to relaunch or schedule new config for activity that hasn't been launched 9576 // yet. We do, however, return after applying the config to activity record, so that 9577 // it will use it for launch transaction. 9578 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check for " 9579 + "initializing activity: %s", this); 9580 return true; 9581 } 9582 9583 if (changes == 0 && !forceNewConfig) { 9584 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration no differences in %s", 9585 this); 9586 // There are no significant differences, so we won't relaunch but should still deliver 9587 // the new configuration to the client process. 9588 if (displayChanged) { 9589 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); 9590 } else { 9591 scheduleConfigurationChanged(newMergedOverrideConfig); 9592 } 9593 notifyDisplayCompatPolicyAboutConfigurationChange( 9594 mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig); 9595 return true; 9596 } 9597 9598 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration changes for %s, " 9599 + "allChanges=%s", this, Configuration.configurationDiffToString(changes)); 9600 9601 // If the activity isn't currently running, just leave the new configuration and it will 9602 // pick that up next time it starts. 9603 if (!attachedToProcess()) { 9604 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter not running %s", this); 9605 stopFreezingScreenLocked(false); 9606 forceNewConfig = false; 9607 return true; 9608 } 9609 9610 // Figure out how to handle the changes between the configurations. 9611 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=0x%s, " 9612 + "handles=0x%s, mLastReportedConfiguration=%s", info.name, 9613 Integer.toHexString(changes), Integer.toHexString(info.getRealConfigChanged()), 9614 mLastReportedConfiguration); 9615 9616 if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) { 9617 // Aha, the activity isn't handling the change, so DIE DIE DIE. 9618 configChangeFlags |= changes; 9619 startFreezingScreenLocked(globalChanges); 9620 forceNewConfig = false; 9621 // Do not preserve window if it is freezing screen because the original window won't be 9622 // able to update drawn state that causes freeze timeout. 9623 preserveWindow &= isResizeOnlyChange(changes) && !mFreezingScreen; 9624 final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged()); 9625 if (hasResizeChange) { 9626 final boolean isDragResizing = task.isDragResizing(); 9627 mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE 9628 : RELAUNCH_REASON_WINDOWING_MODE_RESIZE; 9629 } else { 9630 mRelaunchReason = RELAUNCH_REASON_NONE; 9631 } 9632 if (isRequestedOrientationChanged) { 9633 mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(true); 9634 } 9635 if (mState == PAUSING) { 9636 // A little annoying: we are waiting for this activity to finish pausing. Let's not 9637 // do anything now, but just flag that it needs to be restarted when done pausing. 9638 ProtoLog.v(WM_DEBUG_CONFIGURATION, 9639 "Config is skipping already pausing %s", this); 9640 deferRelaunchUntilPaused = true; 9641 preserveWindowOnDeferredRelaunch = preserveWindow; 9642 return true; 9643 } else { 9644 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s", 9645 this); 9646 if (!mVisibleRequested) { 9647 ProtoLog.v(WM_DEBUG_STATES, "Config is relaunching invisible " 9648 + "activity %s called by %s", this, Debug.getCallers(4)); 9649 } 9650 relaunchActivityLocked(preserveWindow); 9651 } 9652 9653 // All done... tell the caller we weren't able to keep this activity around. 9654 return false; 9655 } 9656 9657 // Default case: the activity can handle this new configuration, so hand it over. 9658 // NOTE: We only forward the override configuration as the system level configuration 9659 // changes is always sent to all processes when they happen so it can just use whatever 9660 // system level configuration it last got. 9661 if (displayChanged) { 9662 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); 9663 } else { 9664 scheduleConfigurationChanged(newMergedOverrideConfig); 9665 } 9666 notifyDisplayCompatPolicyAboutConfigurationChange( 9667 mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig); 9668 9669 stopFreezingScreenLocked(false); 9670 9671 return true; 9672 } 9673 9674 private void notifyDisplayCompatPolicyAboutConfigurationChange( 9675 Configuration newConfig, Configuration lastReportedConfig) { 9676 if (mDisplayContent.mDisplayRotationCompatPolicy == null 9677 || !shouldBeResumed(/* activeActivity */ null)) { 9678 return; 9679 } 9680 mDisplayContent.mDisplayRotationCompatPolicy.onActivityConfigurationChanging( 9681 this, newConfig, lastReportedConfig); 9682 } 9683 9684 /** Get process configuration, or global config if the process is not set. */ 9685 private Configuration getProcessGlobalConfiguration() { 9686 return app != null ? app.getConfiguration() : mAtmService.getGlobalConfiguration(); 9687 } 9688 9689 /** 9690 * When assessing a configuration change, decide if the changes flags and the new configurations 9691 * should cause the Activity to relaunch. 9692 * 9693 * @param changes the changes due to the given configuration. 9694 * @param changesConfig the configuration that was used to calculate the given changes via a 9695 * call to getConfigurationChanges. 9696 */ 9697 private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) { 9698 int configChanged = info.getRealConfigChanged(); 9699 boolean onlyVrUiModeChanged = onlyVrUiModeChanged(changes, changesConfig); 9700 9701 // Override for apps targeting pre-O sdks 9702 // If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode 9703 // to the config change. 9704 // For O and later, apps will be required to add configChanges="uimode" to their manifest. 9705 if (info.applicationInfo.targetSdkVersion < O 9706 && requestedVrComponent != null 9707 && onlyVrUiModeChanged) { 9708 configChanged |= CONFIG_UI_MODE; 9709 } 9710 9711 // TODO(b/274944389): remove workaround after long-term solution is implemented 9712 // Don't restart due to desk mode change if the app does not have desk resources. 9713 if (mWmService.mSkipActivityRelaunchWhenDocking && onlyDeskInUiModeChanged(changesConfig) 9714 && !hasDeskResources()) { 9715 configChanged |= CONFIG_UI_MODE; 9716 } 9717 9718 return (changes & (~configChanged)) != 0; 9719 } 9720 9721 /** 9722 * Returns true if the configuration change is solely due to the UI mode switching into or out 9723 * of UI_MODE_TYPE_VR_HEADSET. 9724 */ 9725 private boolean onlyVrUiModeChanged(int changes, Configuration lastReportedConfig) { 9726 final Configuration currentConfig = getConfiguration(); 9727 return changes == CONFIG_UI_MODE && (isInVrUiMode(currentConfig) 9728 != isInVrUiMode(lastReportedConfig)); 9729 } 9730 9731 /** 9732 * Returns true if the uiMode configuration changed, and desk mode 9733 * ({@link android.content.res.Configuration#UI_MODE_TYPE_DESK}) was the only change to uiMode. 9734 */ 9735 private boolean onlyDeskInUiModeChanged(Configuration lastReportedConfig) { 9736 final Configuration currentConfig = getConfiguration(); 9737 9738 boolean deskModeChanged = isInDeskUiMode(currentConfig) != isInDeskUiMode( 9739 lastReportedConfig); 9740 // UI mode contains fields other than the UI mode type, so determine if any other fields 9741 // changed. 9742 boolean uiModeOtherFieldsChanged = 9743 (currentConfig.uiMode & ~UI_MODE_TYPE_MASK) != (lastReportedConfig.uiMode 9744 & ~UI_MODE_TYPE_MASK); 9745 9746 return deskModeChanged && !uiModeOtherFieldsChanged; 9747 } 9748 9749 /** 9750 * Determines whether or not the application has desk mode resources. 9751 */ 9752 boolean hasDeskResources() { 9753 if (mHasDeskResources != null) { 9754 // We already determined this, return the cached value. 9755 return mHasDeskResources; 9756 } 9757 9758 mHasDeskResources = false; 9759 try { 9760 Resources packageResources = mAtmService.mContext.createPackageContextAsUser( 9761 packageName, 0, UserHandle.of(mUserId)).getResources(); 9762 for (Configuration sizeConfiguration : 9763 packageResources.getSizeAndUiModeConfigurations()) { 9764 if (isInDeskUiMode(sizeConfiguration)) { 9765 mHasDeskResources = true; 9766 break; 9767 } 9768 } 9769 } catch (PackageManager.NameNotFoundException e) { 9770 Slog.w(TAG, "Exception thrown during checking for desk resources " + this, e); 9771 } 9772 return mHasDeskResources; 9773 } 9774 9775 private int getConfigurationChanges(Configuration lastReportedConfig) { 9776 // Determine what has changed. May be nothing, if this is a config that has come back from 9777 // the app after going idle. In that case we just want to leave the official config object 9778 // now in the activity and do nothing else. 9779 int changes = lastReportedConfig.diff(getConfiguration()); 9780 changes = SizeConfigurationBuckets.filterDiff( 9781 changes, lastReportedConfig, getConfiguration(), mSizeConfigurations); 9782 // We don't want window configuration to cause relaunches. 9783 if ((changes & CONFIG_WINDOW_CONFIGURATION) != 0) { 9784 changes &= ~CONFIG_WINDOW_CONFIGURATION; 9785 } 9786 9787 return changes; 9788 } 9789 9790 private static boolean isResizeOnlyChange(int change) { 9791 return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION 9792 | CONFIG_SCREEN_LAYOUT)) == 0; 9793 } 9794 9795 private static boolean hasResizeChange(int change) { 9796 return (change & (CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION 9797 | CONFIG_SCREEN_LAYOUT)) != 0; 9798 } 9799 9800 void relaunchActivityLocked(boolean preserveWindow) { 9801 if (mAtmService.mSuppressResizeConfigChanges && preserveWindow) { 9802 configChangeFlags = 0; 9803 return; 9804 } 9805 if (!preserveWindow) { 9806 // If the activity is the IME input target, ensure storing the last IME shown state 9807 // before relaunching it for restoring the IME visibility once its new window focused. 9808 final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget(); 9809 mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null 9810 && imeInputTarget.getWindowState().mActivityRecord == this 9811 && mDisplayContent.mInputMethodWindow != null 9812 && mDisplayContent.mInputMethodWindow.isVisible(); 9813 } 9814 // Do not waiting for translucent activity if it is going to relaunch. 9815 final Task rootTask = getRootTask(); 9816 if (rootTask != null && rootTask.mTranslucentActivityWaiting == this) { 9817 rootTask.checkTranslucentActivityWaiting(null); 9818 } 9819 final boolean andResume = shouldBeResumed(null /*activeActivity*/); 9820 List<ResultInfo> pendingResults = null; 9821 List<ReferrerIntent> pendingNewIntents = null; 9822 if (andResume) { 9823 pendingResults = results; 9824 pendingNewIntents = newIntents; 9825 } 9826 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, 9827 "Relaunching: " + this + " with results=" + pendingResults 9828 + " newIntents=" + pendingNewIntents + " andResume=" + andResume 9829 + " preserveWindow=" + preserveWindow); 9830 if (andResume) { 9831 EventLogTags.writeWmRelaunchResumeActivity(mUserId, System.identityHashCode(this), 9832 task.mTaskId, shortComponentName, Integer.toHexString(configChangeFlags)); 9833 } else { 9834 EventLogTags.writeWmRelaunchActivity(mUserId, System.identityHashCode(this), 9835 task.mTaskId, shortComponentName, Integer.toHexString(configChangeFlags)); 9836 } 9837 9838 startFreezingScreenLocked(0); 9839 9840 try { 9841 ProtoLog.i(WM_DEBUG_STATES, "Moving to %s Relaunching %s callers=%s" , 9842 (andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6)); 9843 forceNewConfig = false; 9844 final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults, 9845 pendingNewIntents, configChangeFlags, 9846 new MergedConfiguration(getProcessGlobalConfiguration(), 9847 getMergedOverrideConfiguration()), 9848 preserveWindow); 9849 final ActivityLifecycleItem lifecycleItem; 9850 if (andResume) { 9851 lifecycleItem = ResumeActivityItem.obtain(isTransitionForward(), 9852 shouldSendCompatFakeFocus()); 9853 } else { 9854 lifecycleItem = PauseActivityItem.obtain(); 9855 } 9856 final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), token); 9857 transaction.addCallback(callbackItem); 9858 transaction.setLifecycleStateRequest(lifecycleItem); 9859 mAtmService.getLifecycleManager().scheduleTransaction(transaction); 9860 startRelaunching(); 9861 // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only 9862 // request resume if this activity is currently resumed, which implies we aren't 9863 // sleeping. 9864 } catch (RemoteException e) { 9865 Slog.w(TAG, "Failed to relaunch " + this + ": " + e); 9866 } 9867 9868 if (andResume) { 9869 ProtoLog.d(WM_DEBUG_STATES, "Resumed after relaunch %s", this); 9870 results = null; 9871 newIntents = null; 9872 mAtmService.getAppWarningsLocked().onResumeActivity(this); 9873 } else { 9874 removePauseTimeout(); 9875 setState(PAUSED, "relaunchActivityLocked"); 9876 } 9877 9878 // The activity may be waiting for stop, but that is no longer appropriate for it. 9879 mTaskSupervisor.mStoppingActivities.remove(this); 9880 9881 configChangeFlags = 0; 9882 deferRelaunchUntilPaused = false; 9883 preserveWindowOnDeferredRelaunch = false; 9884 } 9885 9886 /** 9887 * Request the process of the activity to restart with its saved state (from 9888 * {@link android.app.Activity#onSaveInstanceState}) if possible. It also forces to recompute 9889 * the override configuration. Note if the activity is in background, the process will be killed 9890 * directly with keeping its record. 9891 */ 9892 void restartProcessIfVisible() { 9893 if (finishing) return; 9894 Slog.i(TAG, "Request to restart process of " + this); 9895 9896 // Reset the existing override configuration so it can be updated according to the latest 9897 // configuration. 9898 clearSizeCompatMode(); 9899 9900 if (!attachedToProcess()) { 9901 return; 9902 } 9903 9904 // The restarting state avoids removing this record when process is died. 9905 setState(RESTARTING_PROCESS, "restartActivityProcess"); 9906 9907 if (!mVisibleRequested || mHaveState) { 9908 // Kill its process immediately because the activity should be in background. 9909 // The activity state will be update to {@link #DESTROYED} in 9910 // {@link ActivityStack#cleanUp} when handling process died. 9911 mAtmService.mH.post(() -> { 9912 final WindowProcessController wpc; 9913 synchronized (mAtmService.mGlobalLock) { 9914 if (!hasProcess() 9915 || app.getReportedProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND) { 9916 return; 9917 } 9918 wpc = app; 9919 } 9920 mAtmService.mAmInternal.killProcess(wpc.mName, wpc.mUid, "resetConfig"); 9921 }); 9922 return; 9923 } 9924 9925 if (mTransitionController.isShellTransitionsEnabled()) { 9926 final Transition transition = new Transition(TRANSIT_RELAUNCH, 0 /* flags */, 9927 mTransitionController, mWmService.mSyncEngine); 9928 mTransitionController.startCollectOrQueue(transition, (deferred) -> { 9929 if (mState != RESTARTING_PROCESS || !attachedToProcess()) { 9930 transition.abort(); 9931 return; 9932 } 9933 // Request invisible so there will be a change after the activity is restarted 9934 // to be visible. 9935 setVisibleRequested(false); 9936 transition.collect(this); 9937 mTransitionController.requestStartTransition(transition, task, 9938 null /* remoteTransition */, null /* displayChange */); 9939 scheduleStopForRestartProcess(); 9940 }); 9941 } else { 9942 startFreezingScreen(); 9943 scheduleStopForRestartProcess(); 9944 } 9945 } 9946 9947 private void scheduleStopForRestartProcess() { 9948 // The process will be killed until the activity reports stopped with saved state (see 9949 // {@link ActivityTaskManagerService.activityStopped}). 9950 try { 9951 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, 9952 StopActivityItem.obtain(0 /* configChanges */)); 9953 } catch (RemoteException e) { 9954 Slog.w(TAG, "Exception thrown during restart " + this, e); 9955 } 9956 mTaskSupervisor.scheduleRestartTimeout(this); 9957 } 9958 9959 boolean isProcessRunning() { 9960 WindowProcessController proc = app; 9961 if (proc == null) { 9962 proc = mAtmService.mProcessNames.get(processName, info.applicationInfo.uid); 9963 } 9964 return proc != null && proc.hasThread(); 9965 } 9966 9967 /** 9968 * @return Whether a task snapshot starting window may be shown. 9969 */ 9970 private boolean allowTaskSnapshot() { 9971 if (newIntents == null) { 9972 return true; 9973 } 9974 9975 // Restrict task snapshot starting window to launcher start, or is same as the last 9976 // delivered intent, or there is no intent at all (eg. task being brought to front). If 9977 // the intent is something else, likely the app is going to show some specific page or 9978 // view, instead of what's left last time. 9979 for (int i = newIntents.size() - 1; i >= 0; i--) { 9980 final Intent intent = newIntents.get(i); 9981 if (intent == null || ActivityRecord.isMainIntent(intent)) { 9982 continue; 9983 } 9984 9985 final boolean sameIntent = mLastNewIntent != null ? mLastNewIntent.filterEquals(intent) 9986 : this.intent.filterEquals(intent); 9987 if (!sameIntent || intent.getExtras() != null) { 9988 return false; 9989 } 9990 } 9991 return true; 9992 } 9993 9994 /** 9995 * Returns {@code true} if the associated activity has the no history flag set on it. 9996 * {@code false} otherwise. 9997 */ 9998 boolean isNoHistory() { 9999 return (intent.getFlags() & FLAG_ACTIVITY_NO_HISTORY) != 0 10000 || (info.flags & FLAG_NO_HISTORY) != 0; 10001 } 10002 10003 void saveToXml(TypedXmlSerializer out) throws IOException, XmlPullParserException { 10004 out.attributeLong(null, ATTR_ID, createTime); 10005 out.attributeInt(null, ATTR_LAUNCHEDFROMUID, launchedFromUid); 10006 if (launchedFromPackage != null) { 10007 out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage); 10008 } 10009 if (launchedFromFeatureId != null) { 10010 out.attribute(null, ATTR_LAUNCHEDFROMFEATURE, launchedFromFeatureId); 10011 } 10012 if (resolvedType != null) { 10013 out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType); 10014 } 10015 out.attributeBoolean(null, ATTR_COMPONENTSPECIFIED, componentSpecified); 10016 out.attributeInt(null, ATTR_USERID, mUserId); 10017 10018 if (taskDescription != null) { 10019 taskDescription.saveToXml(out); 10020 } 10021 10022 out.startTag(null, TAG_INTENT); 10023 intent.saveToXml(out); 10024 out.endTag(null, TAG_INTENT); 10025 10026 if (isPersistable() && mPersistentState != null) { 10027 out.startTag(null, TAG_PERSISTABLEBUNDLE); 10028 mPersistentState.saveToXml(out); 10029 out.endTag(null, TAG_PERSISTABLEBUNDLE); 10030 } 10031 } 10032 10033 static ActivityRecord restoreFromXml(TypedXmlPullParser in, 10034 ActivityTaskSupervisor taskSupervisor) throws IOException, XmlPullParserException { 10035 Intent intent = null; 10036 PersistableBundle persistentState = null; 10037 int launchedFromUid = in.getAttributeInt(null, ATTR_LAUNCHEDFROMUID, 0); 10038 String launchedFromPackage = in.getAttributeValue(null, ATTR_LAUNCHEDFROMPACKAGE); 10039 String launchedFromFeature = in.getAttributeValue(null, ATTR_LAUNCHEDFROMFEATURE); 10040 String resolvedType = in.getAttributeValue(null, ATTR_RESOLVEDTYPE); 10041 boolean componentSpecified = in.getAttributeBoolean(null, ATTR_COMPONENTSPECIFIED, false); 10042 int userId = in.getAttributeInt(null, ATTR_USERID, 0); 10043 long createTime = in.getAttributeLong(null, ATTR_ID, -1); 10044 final int outerDepth = in.getDepth(); 10045 10046 TaskDescription taskDescription = new TaskDescription(); 10047 taskDescription.restoreFromXml(in); 10048 10049 int event; 10050 while (((event = in.next()) != END_DOCUMENT) && 10051 (event != END_TAG || in.getDepth() >= outerDepth)) { 10052 if (event == START_TAG) { 10053 final String name = in.getName(); 10054 if (DEBUG) 10055 Slog.d(TaskPersister.TAG, "ActivityRecord: START_TAG name=" + name); 10056 if (TAG_INTENT.equals(name)) { 10057 intent = Intent.restoreFromXml(in); 10058 if (DEBUG) 10059 Slog.d(TaskPersister.TAG, "ActivityRecord: intent=" + intent); 10060 } else if (TAG_PERSISTABLEBUNDLE.equals(name)) { 10061 persistentState = PersistableBundle.restoreFromXml(in); 10062 if (DEBUG) Slog.d(TaskPersister.TAG, 10063 "ActivityRecord: persistentState=" + persistentState); 10064 } else { 10065 Slog.w(TAG, "restoreActivity: unexpected name=" + name); 10066 XmlUtils.skipCurrentTag(in); 10067 } 10068 } 10069 } 10070 10071 if (intent == null) { 10072 throw new XmlPullParserException("restoreActivity error intent=" + intent); 10073 } 10074 10075 final ActivityTaskManagerService service = taskSupervisor.mService; 10076 final ActivityInfo aInfo = taskSupervisor.resolveActivity(intent, resolvedType, 0, null, 10077 userId, Binder.getCallingUid(), 0); 10078 if (aInfo == null) { 10079 throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent + 10080 " resolvedType=" + resolvedType); 10081 } 10082 return new ActivityRecord.Builder(service) 10083 .setLaunchedFromUid(launchedFromUid) 10084 .setLaunchedFromPackage(launchedFromPackage) 10085 .setLaunchedFromFeature(launchedFromFeature) 10086 .setIntent(intent) 10087 .setResolvedType(resolvedType) 10088 .setActivityInfo(aInfo) 10089 .setComponentSpecified(componentSpecified) 10090 .setPersistentState(persistentState) 10091 .setTaskDescription(taskDescription) 10092 .setCreateTime(createTime) 10093 .build(); 10094 } 10095 10096 private static boolean isInVrUiMode(Configuration config) { 10097 return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET; 10098 } 10099 10100 private static boolean isInDeskUiMode(Configuration config) { 10101 return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_DESK; 10102 } 10103 10104 String getProcessName() { 10105 return info.applicationInfo.processName; 10106 } 10107 10108 int getUid() { 10109 return info.applicationInfo.uid; 10110 } 10111 10112 boolean isUid(int uid) { 10113 return info.applicationInfo.uid == uid; 10114 } 10115 10116 int getPid() { 10117 return app != null ? app.getPid() : 0; 10118 } 10119 10120 int getLaunchedFromPid() { 10121 return launchedFromPid; 10122 } 10123 10124 int getLaunchedFromUid() { 10125 return launchedFromUid; 10126 } 10127 10128 /** 10129 * Gets the referrer package name with respect to package visibility. This method returns null 10130 * if the given package is not visible to this activity. 10131 */ 10132 String getFilteredReferrer(String referrerPackage) { 10133 if (referrerPackage == null || (!referrerPackage.equals(packageName) 10134 && mWmService.mPmInternal.filterAppAccess( 10135 referrerPackage, info.applicationInfo.uid, mUserId))) { 10136 return null; 10137 } 10138 return referrerPackage; 10139 } 10140 10141 /** 10142 * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag 10143 * {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord 10144 * should be visible depending on Keyguard state. 10145 * 10146 * @return true if the screen can be turned on, false otherwise. 10147 */ 10148 boolean canTurnScreenOn() { 10149 if (!getTurnScreenOnFlag()) { 10150 return false; 10151 } 10152 final Task rootTask = getRootTask(); 10153 return mCurrentLaunchCanTurnScreenOn && rootTask != null 10154 && mTaskSupervisor.getKeyguardController().checkKeyguardVisibility(this); 10155 } 10156 10157 void setTurnScreenOn(boolean turnScreenOn) { 10158 mTurnScreenOn = turnScreenOn; 10159 } 10160 10161 void setAllowCrossUidActivitySwitchFromBelow(boolean allowed) { 10162 mAllowCrossUidActivitySwitchFromBelow = allowed; 10163 } 10164 10165 /** 10166 * Determines if a source is allowed to add or remove activities from the task, 10167 * if the current ActivityRecord is above it in the stack 10168 * 10169 * A transition is blocked ({@code false} returned) if all of the following are met: 10170 * <pre> 10171 * 1. The source activity and the current activity record belong to different apps 10172 * (i.e, have different UIDs). 10173 * 2. Both the source activity and the current activity target U+ 10174 * 3. The current activity has not set 10175 * {@link ActivityRecord#setAllowCrossUidActivitySwitchFromBelow(boolean)} to {@code true} 10176 * </pre> 10177 * 10178 * Returns a pair where the elements mean: 10179 * <pre> 10180 * First: {@code false} if we should actually block the transition (takes into consideration 10181 * feature flag and targetSdk). 10182 * Second: {@code false} if we should warn about the transition via toasts. This happens if 10183 * the transition would be blocked in case both the app was targeting U+ and the feature was 10184 * enabled. 10185 * </pre> 10186 * 10187 * @param sourceUid The source (s) activity performing the state change 10188 */ 10189 Pair<Boolean, Boolean> allowCrossUidActivitySwitchFromBelow(int sourceUid) { 10190 int myUid = info.applicationInfo.uid; 10191 if (sourceUid == myUid) { 10192 return new Pair<>(true, true); 10193 } 10194 10195 // If mAllowCrossUidActivitySwitchFromBelow is set, honor it. 10196 if (mAllowCrossUidActivitySwitchFromBelow) { 10197 return new Pair<>(true, true); 10198 } 10199 10200 // If it is not set, default to true if both records target ≥ U, false otherwise 10201 // TODO(b/258792202) Replace with CompatChanges and replace Pair with boolean once feature 10202 // flag is removed 10203 boolean restrictActivitySwitch = 10204 ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(myUid) 10205 && ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(sourceUid); 10206 return new Pair<>(!restrictActivitySwitch, false); 10207 } 10208 10209 boolean getTurnScreenOnFlag() { 10210 return mTurnScreenOn || containsTurnScreenOnWindow(); 10211 } 10212 10213 private boolean containsTurnScreenOnWindow() { 10214 // When we are relaunching, it is possible for us to be unfrozen before our previous 10215 // windows have been added back. Using the cached value ensures that our previous 10216 // showWhenLocked preference is honored until relaunching is complete. 10217 if (isRelaunching()) { 10218 return mLastContainsTurnScreenOnWindow; 10219 } 10220 for (int i = mChildren.size() - 1; i >= 0; i--) { 10221 if ((mChildren.get(i).mAttrs.flags & LayoutParams.FLAG_TURN_SCREEN_ON) != 0) { 10222 return true; 10223 } 10224 } 10225 return false; 10226 } 10227 10228 /** 10229 * Check if this activity is able to resume. For pre-Q apps, only the topmost activities of each 10230 * process are allowed to be resumed. 10231 * 10232 * @return true if this activity can be resumed. 10233 */ 10234 boolean canResumeByCompat() { 10235 return app == null || app.updateTopResumingActivityInProcessIfNeeded(this); 10236 } 10237 10238 boolean isTopRunningActivity() { 10239 return mRootWindowContainer.topRunningActivity() == this; 10240 } 10241 10242 /** 10243 * @return {@code true} if this is the focused activity on its current display, {@code false} 10244 * otherwise. 10245 */ 10246 boolean isFocusedActivityOnDisplay() { 10247 return mDisplayContent.forAllTaskDisplayAreas(taskDisplayArea -> 10248 taskDisplayArea.getFocusedActivity() == this); 10249 } 10250 10251 10252 /** 10253 * Check if this is the root of the task - first activity that is not finishing, starting from 10254 * the bottom of the task. If all activities are finishing - then this method will return 10255 * {@code true} if the activity is at the bottom. 10256 * 10257 * NOTE: This is different from 'effective root' - an activity that defines the task identity. 10258 */ 10259 boolean isRootOfTask() { 10260 if (task == null) { 10261 return false; 10262 } 10263 final ActivityRecord rootActivity = task.getRootActivity(true); 10264 return this == rootActivity; 10265 } 10266 10267 void setTaskOverlay(boolean taskOverlay) { 10268 mTaskOverlay = taskOverlay; 10269 setAlwaysOnTop(mTaskOverlay); 10270 } 10271 10272 boolean isTaskOverlay() { 10273 return mTaskOverlay; 10274 } 10275 10276 @Override 10277 public boolean isAlwaysOnTop() { 10278 return mTaskOverlay || super.isAlwaysOnTop(); 10279 } 10280 10281 @Override 10282 boolean showToCurrentUser() { 10283 return mShowForAllUsers || mWmService.isUserVisible(mUserId); 10284 } 10285 10286 @Override 10287 boolean canCustomizeAppTransition() { 10288 return true; 10289 } 10290 10291 @Override 10292 public String toString() { 10293 if (stringName != null) { 10294 return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) + 10295 (finishing ? " f}" : "") + (mIsExiting ? " isExiting" : "") + "}"; 10296 } 10297 StringBuilder sb = new StringBuilder(128); 10298 sb.append("ActivityRecord{"); 10299 sb.append(Integer.toHexString(System.identityHashCode(this))); 10300 sb.append(" u"); 10301 sb.append(mUserId); 10302 sb.append(' '); 10303 sb.append(intent.getComponent().flattenToShortString()); 10304 stringName = sb.toString(); 10305 return stringName; 10306 } 10307 10308 /** 10309 * Write all fields to an {@code ActivityRecordProto}. This assumes the 10310 * {@code ActivityRecordProto} is the outer-most proto data. 10311 */ 10312 void dumpDebug(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) { 10313 writeNameToProto(proto, NAME); 10314 super.dumpDebug(proto, WINDOW_TOKEN, logLevel); 10315 proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing); 10316 proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart()); 10317 proto.write(IS_ANIMATING, isAnimating(TRANSITION | PARENTS | CHILDREN, 10318 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION)); 10319 if (mThumbnail != null){ 10320 mThumbnail.dumpDebug(proto, THUMBNAIL); 10321 } 10322 proto.write(FILLS_PARENT, fillsParent()); 10323 proto.write(APP_STOPPED, mAppStopped); 10324 proto.write(TRANSLUCENT, !occludesParent()); 10325 proto.write(VISIBLE, mVisible); 10326 proto.write(VISIBLE_REQUESTED, mVisibleRequested); 10327 proto.write(CLIENT_VISIBLE, isClientVisible()); 10328 proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient); 10329 proto.write(REPORTED_DRAWN, mReportedDrawn); 10330 proto.write(REPORTED_VISIBLE, reportedVisible); 10331 proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows); 10332 proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows); 10333 proto.write(ALL_DRAWN, allDrawn); 10334 proto.write(LAST_ALL_DRAWN, mLastAllDrawn); 10335 if (mStartingWindow != null) { 10336 mStartingWindow.writeIdentifierToProto(proto, STARTING_WINDOW); 10337 } 10338 proto.write(STARTING_DISPLAYED, isStartingWindowDisplayed()); 10339 proto.write(STARTING_MOVED, startingMoved); 10340 proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW, 10341 mVisibleSetFromTransferredStartingWindow); 10342 10343 proto.write(STATE, mState.toString()); 10344 proto.write(FRONT_OF_TASK, isRootOfTask()); 10345 if (hasProcess()) { 10346 proto.write(PROC_ID, app.getPid()); 10347 } 10348 proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled()); 10349 proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode()); 10350 proto.write(MIN_ASPECT_RATIO, getMinAspectRatio()); 10351 // Only record if max bounds sandboxing is applied, if the caller has the necessary 10352 // permission to access the device configs. 10353 proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds()); 10354 proto.write(ENABLE_RECENTS_SCREENSHOT, mEnableRecentsScreenshot); 10355 proto.write(LAST_DROP_INPUT_MODE, mLastDropInputMode); 10356 proto.write(OVERRIDE_ORIENTATION, getOverrideOrientation()); 10357 proto.write(SHOULD_SEND_COMPAT_FAKE_FOCUS, shouldSendCompatFakeFocus()); 10358 proto.write(SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT, 10359 mLetterboxUiController.shouldForceRotateForCameraCompat()); 10360 proto.write(SHOULD_REFRESH_ACTIVITY_FOR_CAMERA_COMPAT, 10361 mLetterboxUiController.shouldRefreshActivityForCameraCompat()); 10362 proto.write(SHOULD_REFRESH_ACTIVITY_VIA_PAUSE_FOR_CAMERA_COMPAT, 10363 mLetterboxUiController.shouldRefreshActivityViaPauseForCameraCompat()); 10364 } 10365 10366 @Override 10367 long getProtoFieldId() { 10368 return ACTIVITY; 10369 } 10370 10371 @Override 10372 public void dumpDebug(ProtoOutputStream proto, long fieldId, 10373 @WindowTraceLogLevel int logLevel) { 10374 // Critical log level logs only visible elements to mitigate performance overheard 10375 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { 10376 return; 10377 } 10378 10379 final long token = proto.start(fieldId); 10380 dumpDebug(proto, logLevel); 10381 proto.end(token); 10382 } 10383 10384 void writeNameToProto(ProtoOutputStream proto, long fieldId) { 10385 proto.write(fieldId, shortComponentName); 10386 } 10387 10388 @Override 10389 void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { 10390 final long token = proto.start(fieldId); 10391 proto.write(HASH_CODE, System.identityHashCode(this)); 10392 proto.write(USER_ID, mUserId); 10393 proto.write(TITLE, intent.getComponent().flattenToShortString()); 10394 proto.end(token); 10395 } 10396 10397 /** 10398 * The precomputed insets of the display in each rotation. This is used to make the size 10399 * compatibility mode activity compute the configuration without relying on its current display. 10400 */ 10401 static class CompatDisplayInsets { 10402 /** The original rotation the compat insets were computed in. */ 10403 final @Rotation int mOriginalRotation; 10404 /** The original requested orientation for the activity. */ 10405 final @Configuration.Orientation int mOriginalRequestedOrientation; 10406 /** The container width on rotation 0. */ 10407 private final int mWidth; 10408 /** The container height on rotation 0. */ 10409 private final int mHeight; 10410 /** Whether the {@link Task} windowingMode represents a floating window*/ 10411 final boolean mIsFloating; 10412 /** 10413 * Whether is letterboxed because of fixed orientation when the unresizable activity is 10414 * first shown. 10415 */ 10416 final boolean mIsInFixedOrientationLetterbox; 10417 /** 10418 * The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It 10419 * is used to compute the appBounds. 10420 */ 10421 final Rect[] mNonDecorInsets = new Rect[4]; 10422 /** 10423 * The stableInsets for each rotation. Includes the status bar inset and the 10424 * nonDecorInsets. It is used to compute {@link Configuration#screenWidthDp} and 10425 * {@link Configuration#screenHeightDp}. 10426 */ 10427 final Rect[] mStableInsets = new Rect[4]; 10428 10429 /** Constructs the environment to simulate the bounds behavior of the given container. */ 10430 CompatDisplayInsets(DisplayContent display, ActivityRecord container, 10431 @Nullable Rect fixedOrientationBounds) { 10432 mOriginalRotation = display.getRotation(); 10433 mIsFloating = container.getWindowConfiguration().tasksAreFloating(); 10434 mOriginalRequestedOrientation = container.getRequestedConfigurationOrientation(); 10435 if (mIsFloating) { 10436 final Rect containerBounds = container.getWindowConfiguration().getBounds(); 10437 mWidth = containerBounds.width(); 10438 mHeight = containerBounds.height(); 10439 // For apps in freeform, the task bounds are the parent bounds from the app's 10440 // perspective. No insets because within a window. 10441 final Rect emptyRect = new Rect(); 10442 for (int rotation = 0; rotation < 4; rotation++) { 10443 mNonDecorInsets[rotation] = emptyRect; 10444 mStableInsets[rotation] = emptyRect; 10445 } 10446 mIsInFixedOrientationLetterbox = false; 10447 return; 10448 } 10449 10450 final Task task = container.getTask(); 10451 10452 mIsInFixedOrientationLetterbox = fixedOrientationBounds != null; 10453 10454 // Store the bounds of the Task for the non-resizable activity to use in size compat 10455 // mode so that the activity will not be resized regardless the windowing mode it is 10456 // currently in. 10457 // When an activity needs to be letterboxed because of fixed orientation, use fixed 10458 // orientation bounds instead of task bounds since the activity will be displayed 10459 // within these even if it is in size compat mode. 10460 final Rect filledContainerBounds = mIsInFixedOrientationLetterbox 10461 ? fixedOrientationBounds 10462 : task != null ? task.getBounds() : display.getBounds(); 10463 final int filledContainerRotation = task != null 10464 ? task.getConfiguration().windowConfiguration.getRotation() 10465 : display.getConfiguration().windowConfiguration.getRotation(); 10466 final Point dimensions = getRotationZeroDimensions( 10467 filledContainerBounds, filledContainerRotation); 10468 mWidth = dimensions.x; 10469 mHeight = dimensions.y; 10470 10471 // Bounds of the filled container if it doesn't fill the display. 10472 final Rect unfilledContainerBounds = 10473 filledContainerBounds.equals(display.getBounds()) ? null : new Rect(); 10474 final DisplayPolicy policy = display.getDisplayPolicy(); 10475 for (int rotation = 0; rotation < 4; rotation++) { 10476 mNonDecorInsets[rotation] = new Rect(); 10477 mStableInsets[rotation] = new Rect(); 10478 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); 10479 final int dw = rotated ? display.mBaseDisplayHeight : display.mBaseDisplayWidth; 10480 final int dh = rotated ? display.mBaseDisplayWidth : display.mBaseDisplayHeight; 10481 final DisplayPolicy.DecorInsets.Info decorInfo = 10482 policy.getDecorInsetsInfo(rotation, dw, dh); 10483 mNonDecorInsets[rotation].set(decorInfo.mNonDecorInsets); 10484 mStableInsets[rotation].set(decorInfo.mConfigInsets); 10485 10486 if (unfilledContainerBounds == null) { 10487 continue; 10488 } 10489 // The insets is based on the display, but the container may be smaller than the 10490 // display, so update the insets to exclude parts that are not intersected with the 10491 // container. 10492 unfilledContainerBounds.set(filledContainerBounds); 10493 display.rotateBounds( 10494 filledContainerRotation, 10495 rotation, 10496 unfilledContainerBounds); 10497 updateInsetsForBounds(unfilledContainerBounds, dw, dh, mNonDecorInsets[rotation]); 10498 updateInsetsForBounds(unfilledContainerBounds, dw, dh, mStableInsets[rotation]); 10499 } 10500 } 10501 10502 /** 10503 * Gets the width and height of the {@code container} when it is not rotated, so that after 10504 * the display is rotated, we can calculate the bounds by rotating the dimensions. 10505 * @see #getBoundsByRotation 10506 */ 10507 private static Point getRotationZeroDimensions(final Rect bounds, int rotation) { 10508 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); 10509 final int width = bounds.width(); 10510 final int height = bounds.height(); 10511 return rotated ? new Point(height, width) : new Point(width, height); 10512 } 10513 10514 /** 10515 * Updates the display insets to exclude the parts that are not intersected with the given 10516 * bounds. 10517 */ 10518 private static void updateInsetsForBounds(Rect bounds, int displayWidth, int displayHeight, 10519 Rect inset) { 10520 inset.left = Math.max(0, inset.left - bounds.left); 10521 inset.top = Math.max(0, inset.top - bounds.top); 10522 inset.right = Math.max(0, bounds.right - displayWidth + inset.right); 10523 inset.bottom = Math.max(0, bounds.bottom - displayHeight + inset.bottom); 10524 } 10525 10526 void getBoundsByRotation(Rect outBounds, int rotation) { 10527 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); 10528 final int dw = rotated ? mHeight : mWidth; 10529 final int dh = rotated ? mWidth : mHeight; 10530 outBounds.set(0, 0, dw, dh); 10531 } 10532 10533 void getFrameByOrientation(Rect outBounds, int orientation) { 10534 final int longSide = Math.max(mWidth, mHeight); 10535 final int shortSide = Math.min(mWidth, mHeight); 10536 final boolean isLandscape = orientation == ORIENTATION_LANDSCAPE; 10537 outBounds.set(0, 0, isLandscape ? longSide : shortSide, 10538 isLandscape ? shortSide : longSide); 10539 } 10540 10541 // TODO(b/267151420): Explore removing getContainerBounds() from CompatDisplayInsets. 10542 /** Gets the horizontal centered container bounds for size compatibility mode. */ 10543 void getContainerBounds(Rect outAppBounds, Rect outBounds, int rotation, int orientation, 10544 boolean orientationRequested, boolean isFixedToUserRotation) { 10545 getFrameByOrientation(outBounds, orientation); 10546 if (mIsFloating) { 10547 outAppBounds.set(outBounds); 10548 return; 10549 } 10550 10551 getBoundsByRotation(outAppBounds, rotation); 10552 final int dW = outAppBounds.width(); 10553 final int dH = outAppBounds.height(); 10554 final boolean isOrientationMismatched = 10555 ((outBounds.width() > outBounds.height()) != (dW > dH)); 10556 10557 if (isOrientationMismatched && isFixedToUserRotation && orientationRequested) { 10558 // The orientation is mismatched but the display cannot rotate. The bounds will fit 10559 // to the short side of container. 10560 if (orientation == ORIENTATION_LANDSCAPE) { 10561 outBounds.bottom = (int) ((float) dW * dW / dH); 10562 outBounds.right = dW; 10563 } else { 10564 outBounds.bottom = dH; 10565 outBounds.right = (int) ((float) dH * dH / dW); 10566 } 10567 outBounds.offset(getCenterOffset(mWidth, outBounds.width()), 0 /* dy */); 10568 } 10569 outAppBounds.set(outBounds); 10570 10571 if (isOrientationMismatched) { 10572 // One side of container is smaller than the requested size, then it will be scaled 10573 // and the final position will be calculated according to the parent container and 10574 // scale, so the original size shouldn't be shrunk by insets. 10575 final Rect insets = mNonDecorInsets[rotation]; 10576 outBounds.offset(insets.left, insets.top); 10577 outAppBounds.offset(insets.left, insets.top); 10578 } else if (rotation != ROTATION_UNDEFINED) { 10579 // Ensure the app bounds won't overlap with insets. 10580 TaskFragment.intersectWithInsetsIfFits(outAppBounds, outBounds, 10581 mNonDecorInsets[rotation]); 10582 } 10583 } 10584 } 10585 10586 private static class AppSaturationInfo { 10587 float[] mMatrix = new float[9]; 10588 float[] mTranslation = new float[3]; 10589 10590 void setSaturation(@Size(9) float[] matrix, @Size(3) float[] translation) { 10591 System.arraycopy(matrix, 0, mMatrix, 0, mMatrix.length); 10592 System.arraycopy(translation, 0, mTranslation, 0, mTranslation.length); 10593 } 10594 } 10595 10596 @Override 10597 RemoteAnimationTarget createRemoteAnimationTarget( 10598 RemoteAnimationController.RemoteAnimationRecord record) { 10599 final WindowState mainWindow = findMainWindow(); 10600 if (task == null || mainWindow == null) { 10601 return null; 10602 } 10603 final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets( 10604 task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect(); 10605 InsetUtils.addInsets(insets, getLetterboxInsets()); 10606 10607 final RemoteAnimationTarget target = new RemoteAnimationTarget(task.mTaskId, 10608 record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(), 10609 new Rect(), insets, 10610 getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds, 10611 record.mAdapter.mEndBounds, task.getWindowConfiguration(), 10612 false /*isNotInRecents*/, 10613 record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null, 10614 record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState()); 10615 target.setShowBackdrop(record.mShowBackdrop); 10616 target.setWillShowImeOnTarget(mStartingData != null && mStartingData.hasImeSurface()); 10617 target.hasAnimatingParent = record.hasAnimatingParent(); 10618 return target; 10619 } 10620 10621 @Override 10622 boolean canCreateRemoteAnimationTarget() { 10623 return true; 10624 } 10625 10626 @Override 10627 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, 10628 Rect outSurfaceInsets) { 10629 final WindowState win = findMainWindow(); 10630 if (win == null) { 10631 return; 10632 } 10633 win.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 10634 } 10635 10636 void setPictureInPictureParams(PictureInPictureParams p) { 10637 pictureInPictureArgs.copyOnlySet(p); 10638 adjustPictureInPictureParamsIfNeeded(getBounds()); 10639 getTask().getRootTask().onPictureInPictureParamsChanged(); 10640 } 10641 10642 void setShouldDockBigOverlays(boolean shouldDockBigOverlays) { 10643 this.shouldDockBigOverlays = shouldDockBigOverlays; 10644 getTask().getRootTask().onShouldDockBigOverlaysChanged(); 10645 } 10646 10647 @Override 10648 boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) { 10649 if (!super.isSyncFinished(group)) return false; 10650 if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController 10651 .isVisibilityUnknown(this)) { 10652 return false; 10653 } 10654 if (!isVisibleRequested()) return true; 10655 if (mPendingRelaunchCount > 0) return false; 10656 // Wait for attach. That is the earliest time where we know if there will be an associated 10657 // display rotation. If we don't wait, the starting-window can finishDrawing first and 10658 // cause the display rotation to end-up in a following transition. 10659 if (!isAttached()) return false; 10660 // If visibleRequested, wait for at-least one visible child. 10661 for (int i = mChildren.size() - 1; i >= 0; --i) { 10662 if (mChildren.get(i).isVisibleRequested()) { 10663 return true; 10664 } 10665 } 10666 return false; 10667 } 10668 10669 @Override 10670 void finishSync(Transaction outMergedTransaction, BLASTSyncEngine.SyncGroup group, 10671 boolean cancel) { 10672 // This override is just for getting metrics. allFinished needs to be checked before 10673 // finish because finish resets all the states. 10674 final BLASTSyncEngine.SyncGroup syncGroup = getSyncGroup(); 10675 if (syncGroup != null && group != getSyncGroup()) return; 10676 mLastAllReadyAtSync = allSyncFinished(); 10677 super.finishSync(outMergedTransaction, group, cancel); 10678 } 10679 10680 @Nullable 10681 Point getMinDimensions() { 10682 final ActivityInfo.WindowLayout windowLayout = info.windowLayout; 10683 if (windowLayout == null) { 10684 return null; 10685 } 10686 return new Point(windowLayout.minWidth, windowLayout.minHeight); 10687 } 10688 10689 /** 10690 * Adjust the source rect hint in {@link #pictureInPictureArgs} by window bounds since 10691 * it is relative to its root view (see also b/235599028). 10692 * It is caller's responsibility to make sure this is called exactly once when we update 10693 * {@link #pictureInPictureArgs} to avoid double offset. 10694 */ 10695 private void adjustPictureInPictureParamsIfNeeded(Rect windowBounds) { 10696 if (pictureInPictureArgs != null && pictureInPictureArgs.hasSourceBoundsHint()) { 10697 pictureInPictureArgs.getSourceRectHint().offset(windowBounds.left, windowBounds.top); 10698 } 10699 } 10700 10701 private void applyLocaleOverrideIfNeeded(Configuration resolvedConfig) { 10702 // We always align the locale for ActivityEmbedding apps. System apps or some apps which 10703 // has set known cert apps can embed across different uid activity. 10704 boolean shouldAlignLocale = isEmbedded() 10705 || (task != null && task.mAlignActivityLocaleWithTask); 10706 if (!shouldAlignLocale) { 10707 return; 10708 } 10709 10710 boolean differentPackage = task != null 10711 && task.realActivity != null 10712 && !task.realActivity.getPackageName().equals(packageName); 10713 if (!differentPackage) { 10714 return; 10715 } 10716 10717 final ActivityTaskManagerInternal.PackageConfig appConfig = 10718 mAtmService.mPackageConfigPersister.findPackageConfiguration( 10719 task.realActivity.getPackageName(), mUserId); 10720 // If package lookup yields locales, set the target activity's locales to match, 10721 // otherwise leave target activity as-is. 10722 if (appConfig != null && appConfig.mLocales != null && !appConfig.mLocales.isEmpty()) { 10723 resolvedConfig.setLocales(appConfig.mLocales); 10724 } 10725 } 10726 10727 /** 10728 * Whether we should send fake focus when the activity is resumed. This is done because some 10729 * game engines wait to get focus before drawing the content of the app. 10730 */ 10731 // TODO(b/263593361): Explore enabling compat fake focus for freeform. 10732 // TODO(b/263592337): Explore enabling compat fake focus for fullscreen, e.g. for when 10733 // covered with bubbles. 10734 boolean shouldSendCompatFakeFocus() { 10735 return mLetterboxUiController.shouldSendFakeFocus() && inMultiWindowMode() 10736 && !inPinnedWindowingMode() && !inFreeformWindowingMode(); 10737 } 10738 10739 boolean canCaptureSnapshot() { 10740 if (!isSurfaceShowing() || findMainWindow() == null) { 10741 return false; 10742 } 10743 return forAllWindows( 10744 // Ensure at least one window for the top app is visible before attempting to 10745 // take a screenshot. Visible here means that the WSA surface is shown and has 10746 // an alpha greater than 0. 10747 ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown() 10748 && ws.mWinAnimator.mLastAlpha > 0f, true /* traverseTopToBottom */); 10749 } 10750 10751 void overrideCustomTransition(boolean open, int enterAnim, int exitAnim, int backgroundColor) { 10752 CustomAppTransition transition = getCustomAnimation(open); 10753 if (transition == null) { 10754 transition = new CustomAppTransition(); 10755 if (open) { 10756 mCustomOpenTransition = transition; 10757 } else { 10758 mCustomCloseTransition = transition; 10759 } 10760 } 10761 10762 transition.mEnterAnim = enterAnim; 10763 transition.mExitAnim = exitAnim; 10764 transition.mBackgroundColor = backgroundColor; 10765 } 10766 10767 void clearCustomTransition(boolean open) { 10768 if (open) { 10769 mCustomOpenTransition = null; 10770 } else { 10771 mCustomCloseTransition = null; 10772 } 10773 } 10774 10775 CustomAppTransition getCustomAnimation(boolean open) { 10776 return open ? mCustomOpenTransition : mCustomCloseTransition; 10777 } 10778 10779 // Override the WindowAnimation_(Open/Close)(Enter/Exit)Animation 10780 static class CustomAppTransition { 10781 int mEnterAnim; 10782 int mExitAnim; 10783 int mBackgroundColor; 10784 } 10785 10786 static class Builder { 10787 private final ActivityTaskManagerService mAtmService; 10788 private WindowProcessController mCallerApp; 10789 private int mLaunchedFromPid; 10790 private int mLaunchedFromUid; 10791 private String mLaunchedFromPackage; 10792 private String mLaunchedFromFeature; 10793 private Intent mIntent; 10794 private String mResolvedType; 10795 private ActivityInfo mActivityInfo; 10796 private Configuration mConfiguration; 10797 private ActivityRecord mResultTo; 10798 private String mResultWho; 10799 private int mRequestCode; 10800 private boolean mComponentSpecified; 10801 private boolean mRootVoiceInteraction; 10802 private ActivityOptions mOptions; 10803 private ActivityRecord mSourceRecord; 10804 private PersistableBundle mPersistentState; 10805 private TaskDescription mTaskDescription; 10806 private long mCreateTime; 10807 10808 Builder(ActivityTaskManagerService service) { 10809 mAtmService = service; 10810 } 10811 10812 Builder setCaller(@NonNull WindowProcessController caller) { 10813 mCallerApp = caller; 10814 return this; 10815 } 10816 10817 Builder setLaunchedFromPid(int pid) { 10818 mLaunchedFromPid = pid; 10819 return this; 10820 } 10821 10822 Builder setLaunchedFromUid(int uid) { 10823 mLaunchedFromUid = uid; 10824 return this; 10825 } 10826 10827 Builder setLaunchedFromPackage(String fromPackage) { 10828 mLaunchedFromPackage = fromPackage; 10829 return this; 10830 } 10831 10832 Builder setLaunchedFromFeature(String fromFeature) { 10833 mLaunchedFromFeature = fromFeature; 10834 return this; 10835 } 10836 10837 Builder setIntent(Intent intent) { 10838 mIntent = intent; 10839 return this; 10840 } 10841 10842 Builder setResolvedType(String resolvedType) { 10843 mResolvedType = resolvedType; 10844 return this; 10845 } 10846 10847 Builder setActivityInfo(ActivityInfo activityInfo) { 10848 mActivityInfo = activityInfo; 10849 return this; 10850 } 10851 10852 Builder setResultTo(ActivityRecord resultTo) { 10853 mResultTo = resultTo; 10854 return this; 10855 } 10856 10857 Builder setResultWho(String resultWho) { 10858 mResultWho = resultWho; 10859 return this; 10860 } 10861 10862 Builder setRequestCode(int reqCode) { 10863 mRequestCode = reqCode; 10864 return this; 10865 } 10866 10867 Builder setComponentSpecified(boolean componentSpecified) { 10868 mComponentSpecified = componentSpecified; 10869 return this; 10870 } 10871 10872 Builder setRootVoiceInteraction(boolean rootVoiceInteraction) { 10873 mRootVoiceInteraction = rootVoiceInteraction; 10874 return this; 10875 } 10876 10877 Builder setActivityOptions(ActivityOptions options) { 10878 mOptions = options; 10879 return this; 10880 } 10881 10882 Builder setConfiguration(Configuration config) { 10883 mConfiguration = config; 10884 return this; 10885 } 10886 10887 Builder setSourceRecord(ActivityRecord source) { 10888 mSourceRecord = source; 10889 return this; 10890 } 10891 10892 private Builder setPersistentState(PersistableBundle persistentState) { 10893 mPersistentState = persistentState; 10894 return this; 10895 } 10896 10897 private Builder setTaskDescription(TaskDescription taskDescription) { 10898 mTaskDescription = taskDescription; 10899 return this; 10900 } 10901 10902 private Builder setCreateTime(long createTime) { 10903 mCreateTime = createTime; 10904 return this; 10905 } 10906 10907 ActivityRecord build() { 10908 if (mConfiguration == null) { 10909 mConfiguration = mAtmService.getConfiguration(); 10910 } 10911 return new ActivityRecord(mAtmService, mCallerApp, mLaunchedFromPid, 10912 mLaunchedFromUid, mLaunchedFromPackage, mLaunchedFromFeature, mIntent, 10913 mResolvedType, mActivityInfo, mConfiguration, mResultTo, mResultWho, 10914 mRequestCode, mComponentSpecified, mRootVoiceInteraction, 10915 mAtmService.mTaskSupervisor, mOptions, mSourceRecord, mPersistentState, 10916 mTaskDescription, mCreateTime); 10917 } 10918 } 10919 } 10920