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