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