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