1 /* 2 * Copyright (C) 2021 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.Manifest.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE; 20 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS; 21 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; 23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 24 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 25 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 26 import static android.app.WindowConfiguration.ROTATION_UNDEFINED; 27 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 28 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 29 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 30 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 31 import static android.app.WindowConfiguration.isFloating; 32 import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING; 33 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING; 34 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 35 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 36 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 37 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 38 import static android.content.res.Configuration.ORIENTATION_UNDEFINED; 39 import static android.os.Process.INVALID_UID; 40 import static android.os.Process.SYSTEM_UID; 41 import static android.os.UserHandle.USER_NULL; 42 import static android.view.Display.INVALID_DISPLAY; 43 import static android.view.Surface.ROTATION_270; 44 import static android.view.Surface.ROTATION_90; 45 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; 46 47 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_STATES; 48 import static com.android.server.wm.ActivityRecord.State.PAUSED; 49 import static com.android.server.wm.ActivityRecord.State.PAUSING; 50 import static com.android.server.wm.ActivityRecord.State.RESUMED; 51 import static com.android.server.wm.ActivityRecord.State.STOPPING; 52 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; 53 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; 54 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; 55 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; 56 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; 57 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 58 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 59 import static com.android.server.wm.ActivityTaskManagerService.checkPermission; 60 import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity; 61 import static com.android.server.wm.IdentifierProto.HASH_CODE; 62 import static com.android.server.wm.IdentifierProto.TITLE; 63 import static com.android.server.wm.IdentifierProto.USER_ID; 64 import static com.android.server.wm.TaskFragmentProto.ACTIVITY_TYPE; 65 import static com.android.server.wm.TaskFragmentProto.DISPLAY_ID; 66 import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT; 67 import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH; 68 import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER; 69 import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT; 70 71 import android.annotation.IntDef; 72 import android.annotation.NonNull; 73 import android.annotation.Nullable; 74 import android.app.ActivityOptions; 75 import android.app.IApplicationThread; 76 import android.app.ResultInfo; 77 import android.app.WindowConfiguration; 78 import android.app.servertransaction.ActivityResultItem; 79 import android.app.servertransaction.NewIntentItem; 80 import android.app.servertransaction.PauseActivityItem; 81 import android.app.servertransaction.ResumeActivityItem; 82 import android.content.PermissionChecker; 83 import android.content.pm.ActivityInfo; 84 import android.content.pm.PackageManager; 85 import android.content.res.Configuration; 86 import android.graphics.Insets; 87 import android.graphics.Point; 88 import android.graphics.Rect; 89 import android.os.IBinder; 90 import android.os.RemoteException; 91 import android.os.UserHandle; 92 import android.util.ArraySet; 93 import android.util.DisplayMetrics; 94 import android.util.Slog; 95 import android.util.proto.ProtoOutputStream; 96 import android.view.DisplayInfo; 97 import android.view.SurfaceControl; 98 import android.window.ITaskFragmentOrganizer; 99 import android.window.TaskFragmentAnimationParams; 100 import android.window.TaskFragmentInfo; 101 import android.window.TaskFragmentOrganizerToken; 102 103 import com.android.internal.annotations.VisibleForTesting; 104 import com.android.internal.protolog.ProtoLog; 105 import com.android.internal.util.ToBooleanFunction; 106 import com.android.server.am.HostingRecord; 107 import com.android.server.pm.pkg.AndroidPackage; 108 import com.android.window.flags.Flags; 109 110 import java.io.FileDescriptor; 111 import java.io.PrintWriter; 112 import java.util.ArrayList; 113 import java.util.List; 114 import java.util.Set; 115 import java.util.function.Consumer; 116 import java.util.function.Predicate; 117 118 /** 119 * A basic container that can be used to contain activities or other {@link TaskFragment}, which 120 * also able to manage the activity lifecycle and updates the visibilities of the activities in it. 121 */ 122 class TaskFragment extends WindowContainer<WindowContainer> { 123 @IntDef(prefix = {"TASK_FRAGMENT_VISIBILITY"}, value = { 124 TASK_FRAGMENT_VISIBILITY_VISIBLE, 125 TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, 126 TASK_FRAGMENT_VISIBILITY_INVISIBLE, 127 }) 128 @interface TaskFragmentVisibility {} 129 130 /** 131 * TaskFragment is visible. No other TaskFragment(s) on top that fully or partially occlude it. 132 */ 133 static final int TASK_FRAGMENT_VISIBILITY_VISIBLE = 0; 134 135 /** TaskFragment is partially occluded by other translucent TaskFragment(s) on top of it. */ 136 static final int TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1; 137 138 /** TaskFragment is completely invisible. */ 139 static final int TASK_FRAGMENT_VISIBILITY_INVISIBLE = 2; 140 141 private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskFragment" : TAG_ATM; 142 private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; 143 private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS; 144 private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION; 145 146 /** Set to false to disable the preview that is shown while a new activity is being started. */ 147 static final boolean SHOW_APP_STARTING_PREVIEW = true; 148 149 /** 150 * An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or 151 * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}: 152 * indicate that an Activity can be embedded successfully. 153 */ 154 static final int EMBEDDING_ALLOWED = 0; 155 /** 156 * An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or 157 * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}: 158 * indicate that an Activity can't be embedded because either the Activity does not allow 159 * untrusted embedding, and the embedding host app is not trusted. 160 */ 161 static final int EMBEDDING_DISALLOWED_UNTRUSTED_HOST = 1; 162 /** 163 * An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or 164 * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}: 165 * indicate that an Activity can't be embedded because this taskFragment's bounds are 166 * {@link #smallerThanMinDimension(ActivityRecord)}. 167 */ 168 static final int EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION = 2; 169 /** 170 * An embedding check result of 171 * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}: 172 * indicate that an Activity can't be embedded because the Activity is started on a new task. 173 */ 174 static final int EMBEDDING_DISALLOWED_NEW_TASK = 3; 175 176 /** 177 * Embedding check results of {@link #isAllowedToEmbedActivity(ActivityRecord)} or 178 * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}. 179 */ 180 @IntDef(prefix = {"EMBEDDING_"}, value = { 181 EMBEDDING_ALLOWED, 182 EMBEDDING_DISALLOWED_UNTRUSTED_HOST, 183 EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION, 184 EMBEDDING_DISALLOWED_NEW_TASK, 185 }) 186 @interface EmbeddingCheckResult {} 187 188 /** 189 * Indicate that the minimal width/height should use the default value. 190 * 191 * @see #mMinWidth 192 * @see #mMinHeight 193 */ 194 static final int INVALID_MIN_SIZE = -1; 195 196 final ActivityTaskManagerService mAtmService; 197 final ActivityTaskSupervisor mTaskSupervisor; 198 final RootWindowContainer mRootWindowContainer; 199 private final TaskFragmentOrganizerController mTaskFragmentOrganizerController; 200 201 // TODO(b/233177466): Move mMinWidth and mMinHeight to Task and remove usages in TaskFragment 202 /** 203 * Minimal width of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it 204 * should use the default minimal width. 205 */ 206 int mMinWidth; 207 208 /** 209 * Minimal height of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it 210 * should use the default minimal height. 211 */ 212 int mMinHeight; 213 214 Dimmer mDimmer = new Dimmer(this); 215 216 /** Apply the dim layer on the embedded TaskFragment. */ 217 static final int EMBEDDED_DIM_AREA_TASK_FRAGMENT = 0; 218 219 /** Apply the dim layer on the parent Task for an embedded TaskFragment. */ 220 static final int EMBEDDED_DIM_AREA_PARENT_TASK = 1; 221 222 /** 223 * The type of dim layer area for an embedded TaskFragment. 224 */ 225 @IntDef(prefix = {"EMBEDDED_DIM_AREA_"}, value = { 226 EMBEDDED_DIM_AREA_TASK_FRAGMENT, 227 EMBEDDED_DIM_AREA_PARENT_TASK, 228 }) 229 @interface EmbeddedDimArea {} 230 231 @EmbeddedDimArea 232 private int mEmbeddedDimArea = EMBEDDED_DIM_AREA_TASK_FRAGMENT; 233 234 /** This task fragment will be removed when the cleanup of its children are done. */ 235 private boolean mIsRemovalRequested; 236 237 /** 238 * The TaskFragments that are adjacent to each other, including this TaskFragment. 239 * All TaskFragments in this set share the same set instance. 240 */ 241 @Nullable 242 private AdjacentSet mAdjacentTaskFragments; 243 244 /** 245 * Unlike the {@link #mAdjacentTaskFragments}, the companion TaskFragment is not always visually 246 * adjacent to this one, but this TaskFragment will be removed by the organizer if the 247 * companion TaskFragment is removed. 248 */ 249 @Nullable 250 private TaskFragment mCompanionTaskFragment; 251 252 /** 253 * Prevents duplicate calls to onTaskFragmentAppeared. 254 */ 255 boolean mTaskFragmentAppearedSent; 256 257 /** 258 * Prevents unnecessary callbacks after onTaskFragmentVanished. 259 */ 260 boolean mTaskFragmentVanishedSent; 261 262 /** 263 * The last running activity of the TaskFragment was finished due to clear task while launching 264 * an activity in the Task. 265 */ 266 boolean mClearedTaskForReuse; 267 268 /** 269 * The last running activity of the TaskFragment was reparented to a different Task because it 270 * is entering PiP. 271 */ 272 boolean mClearedTaskFragmentForPip; 273 274 /** 275 * The last running activity of the TaskFragment was removed and added to the top-most of the 276 * Task because it was launched with FLAG_ACTIVITY_REORDER_TO_FRONT. 277 */ 278 boolean mClearedForReorderActivityToFront; 279 280 /** 281 * When we are in the process of pausing an activity, before starting the 282 * next one, this variable holds the activity that is currently being paused. 283 * 284 * Only set at leaf task fragments. 285 */ 286 @Nullable 287 private ActivityRecord mPausingActivity = null; 288 289 /** 290 * This is the last activity that we put into the paused state. This is 291 * used to determine if we need to do an activity transition while sleeping, 292 * when we normally hold the top activity paused. 293 */ 294 ActivityRecord mLastPausedActivity = null; 295 296 /** 297 * Current activity that is resumed, or null if there is none. 298 * Only set at leaf task fragments. 299 */ 300 @Nullable 301 private ActivityRecord mResumedActivity = null; 302 303 /** 304 * This TaskFragment was created by an organizer which has the following implementations. 305 * <ul> 306 * <li>The TaskFragment won't be removed when it is empty. Removal has to be an explicit 307 * request from the organizer.</li> 308 * <li>If this fragment is a Task object then unlike other non-root tasks, it's direct 309 * children are visible to the organizer for ordering purposes.</li> 310 * <li>A TaskFragment can be created by {@link android.window.TaskFragmentOrganizer}, and 311 * a Task can be created by {@link android.window.TaskOrganizer}.</li> 312 * </ul> 313 */ 314 @VisibleForTesting 315 boolean mCreatedByOrganizer; 316 317 /** Whether this TaskFragment is embedded in a task. */ 318 private final boolean mIsEmbedded; 319 320 /** Organizer that organizing this TaskFragment. */ 321 @Nullable 322 private ITaskFragmentOrganizer mTaskFragmentOrganizer; 323 324 int mTaskFragmentOrganizerUid = INVALID_UID; 325 @Nullable String mTaskFragmentOrganizerProcessName; 326 327 /** Client assigned unique token for this TaskFragment if this is created by an organizer. */ 328 @Nullable 329 private final IBinder mFragmentToken; 330 331 /** The animation override params for animation running on this TaskFragment. */ 332 @NonNull 333 private TaskFragmentAnimationParams mAnimationParams = TaskFragmentAnimationParams.DEFAULT; 334 335 /** 336 * The organizer requested bounds of the embedded TaskFragment relative to the parent Task. 337 * {@code null} if it is not {@link #mIsEmbedded} 338 */ 339 @Nullable 340 private final Rect mRelativeEmbeddedBounds; 341 342 /** 343 * Whether to delay the call to {@link #updateOrganizedTaskFragmentSurface()} when there is a 344 * configuration change. 345 */ 346 private boolean mDelayOrganizedTaskFragmentSurfaceUpdate; 347 348 /** 349 * Whether to delay the last activity of TaskFragment being immediately removed while finishing. 350 * This should only be set on a embedded TaskFragment, where the organizer can have the 351 * opportunity to perform animations and finishing the adjacent TaskFragment. 352 */ 353 private boolean mDelayLastActivityRemoval; 354 355 /** 356 * Whether the activity navigation should be isolated. That is, Activities cannot be launched 357 * on an isolated TaskFragment unless explicitly requested to be launched to. 358 */ 359 private boolean mIsolatedNav; 360 361 /** 362 * Whether the TaskFragment to be pinned. 363 * <p> 364 * If a TaskFragment is pinned, the TaskFragment should be the top-most TaskFragment among other 365 * sibling TaskFragments. Any newly launched and embeddable activity should not be placed in the 366 * pinned TaskFragment, unless the activity is launched from the pinned TaskFragment or 367 * explicitly requested to. Non-embeddable activities are not restricted to. 368 */ 369 private boolean mPinned; 370 371 /** 372 * Whether the TaskFragment should move to bottom of task when any activity below it is 373 * launched in clear top mode. 374 */ 375 private boolean mMoveToBottomIfClearWhenLaunch; 376 377 /** 378 * If {@code true}, transitions are allowed even if this TaskFragment is empty. If 379 * {@code false}, transitions will wait until this TaskFragment becomes non-empty or other 380 * conditions are met. Default to {@code false}. 381 * 382 * @see #isReadyToTransit 383 */ 384 private boolean mAllowTransitionWhenEmpty; 385 386 /** 387 * Specifies which configuration changes should trigger TaskFragment info changed callbacks. 388 * Only system TaskFragment organizers are allowed to set this value. 389 */ 390 private @ActivityInfo.Config int mConfigurationChangeMaskForOrganizer; 391 392 /** When set, will force the task to report as invisible. */ 393 static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1; 394 static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1; 395 static final int FLAG_FORCE_HIDDEN_FOR_TASK_FRAGMENT_ORG = 1 << 2; 396 397 @IntDef(prefix = {"FLAG_FORCE_HIDDEN_"}, value = { 398 FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, 399 FLAG_FORCE_HIDDEN_FOR_TASK_ORG, 400 FLAG_FORCE_HIDDEN_FOR_TASK_FRAGMENT_ORG, 401 }, flag = true) 402 @interface FlagForceHidden {} 403 protected int mForceHiddenFlags = 0; 404 405 private boolean mForceTranslucent = false; 406 407 /** @see #setCanAffectSystemUiFlags */ 408 private boolean mCanAffectSystemUiFlags = true; 409 410 final Point mLastSurfaceSize = new Point(); 411 412 private final Rect mTmpBounds = new Rect(); 413 private final Rect mTmpAbsBounds = new Rect(); 414 private final Rect mTmpFullBounds = new Rect(); 415 /** For calculating screenWidthDp and screenWidthDp, i.e. the area without the system bars. */ 416 private final Rect mTmpStableBounds = new Rect(); 417 /** For calculating app bounds, i.e. the area without the nav bar and display cutout. */ 418 private final Rect mTmpNonDecorBounds = new Rect(); 419 420 private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper = 421 new EnsureActivitiesVisibleHelper(this); 422 423 /** Creates an embedded task fragment. */ TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer)424 TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, 425 boolean createdByOrganizer) { 426 this(atmService, fragmentToken, createdByOrganizer, true /* isEmbedded */); 427 } 428 TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer, boolean isEmbedded)429 TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, 430 boolean createdByOrganizer, boolean isEmbedded) { 431 super(atmService.mWindowManager); 432 433 mAtmService = atmService; 434 mTaskSupervisor = mAtmService.mTaskSupervisor; 435 mRootWindowContainer = mAtmService.mRootWindowContainer; 436 mCreatedByOrganizer = createdByOrganizer; 437 mIsEmbedded = isEmbedded; 438 mRelativeEmbeddedBounds = isEmbedded ? new Rect() : null; 439 mTaskFragmentOrganizerController = 440 mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController; 441 mFragmentToken = fragmentToken; 442 mRemoteToken = new RemoteToken(this); 443 } 444 445 @NonNull fromTaskFragmentToken(@ullable IBinder token, @NonNull ActivityTaskManagerService service)446 static TaskFragment fromTaskFragmentToken(@Nullable IBinder token, 447 @NonNull ActivityTaskManagerService service) { 448 if (token == null) return null; 449 return service.mWindowOrganizerController.getTaskFragment(token); 450 } 451 setAdjacentTaskFragments(@onNull AdjacentSet adjacentTaskFragments)452 void setAdjacentTaskFragments(@NonNull AdjacentSet adjacentTaskFragments) { 453 adjacentTaskFragments.setAsAdjacent(); 454 } 455 setCompanionTaskFragment(@ullable TaskFragment companionTaskFragment)456 void setCompanionTaskFragment(@Nullable TaskFragment companionTaskFragment) { 457 mCompanionTaskFragment = companionTaskFragment; 458 } 459 getCompanionTaskFragment()460 TaskFragment getCompanionTaskFragment() { 461 return mCompanionTaskFragment; 462 } 463 clearAdjacentTaskFragments()464 void clearAdjacentTaskFragments() { 465 if (mAdjacentTaskFragments != null) { 466 mAdjacentTaskFragments.clear(); 467 } 468 } 469 removeFromAdjacentTaskFragments()470 void removeFromAdjacentTaskFragments() { 471 if (mAdjacentTaskFragments != null) { 472 mAdjacentTaskFragments.remove(this); 473 } 474 } 475 476 @Nullable getAdjacentTaskFragments()477 AdjacentSet getAdjacentTaskFragments() { 478 return mAdjacentTaskFragments; 479 } 480 481 /** 482 * Runs callback on all TaskFragments that are adjacent to this. The invoke order is not 483 * guaranteed. 484 */ forOtherAdjacentTaskFragments(@onNull Consumer<TaskFragment> callback)485 void forOtherAdjacentTaskFragments(@NonNull Consumer<TaskFragment> callback) { 486 if (mAdjacentTaskFragments == null) { 487 return; 488 } 489 mAdjacentTaskFragments.forAllTaskFragments(callback, this /* exclude */); 490 } 491 492 /** 493 * Runs callback on all TaskFragments that are adjacent to this. Returns early if callback 494 * returns true on any of them. The invoke order is not guaranteed. 495 */ forOtherAdjacentTaskFragments(@onNull Predicate<TaskFragment> callback)496 boolean forOtherAdjacentTaskFragments(@NonNull Predicate<TaskFragment> callback) { 497 if (mAdjacentTaskFragments == null) { 498 return false; 499 } 500 return mAdjacentTaskFragments.forAllTaskFragments(callback, this /* exclude */); 501 } 502 hasAdjacentTaskFragment()503 boolean hasAdjacentTaskFragment() { 504 return mAdjacentTaskFragments != null; 505 } 506 isAdjacentTo(@onNull TaskFragment other)507 boolean isAdjacentTo(@NonNull TaskFragment other) { 508 return other != this 509 && mAdjacentTaskFragments != null 510 && mAdjacentTaskFragments.contains(other); 511 } 512 setTaskFragmentOrganizer(@onNull TaskFragmentOrganizerToken organizer, int uid, @NonNull String processName)513 void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid, 514 @NonNull String processName) { 515 mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.asBinder()); 516 mTaskFragmentOrganizerUid = uid; 517 mTaskFragmentOrganizerProcessName = processName; 518 } 519 onTaskFragmentOrganizerRestarted(@onNull ITaskFragmentOrganizer organizer)520 void onTaskFragmentOrganizerRestarted(@NonNull ITaskFragmentOrganizer organizer) { 521 mTaskFragmentOrganizer = organizer; 522 } 523 onTaskFragmentOrganizerRemoved()524 void onTaskFragmentOrganizerRemoved() { 525 mTaskFragmentOrganizer = null; 526 } 527 528 /** Whether this TaskFragment is organized by the given {@code organizer}. */ hasTaskFragmentOrganizer(ITaskFragmentOrganizer organizer)529 boolean hasTaskFragmentOrganizer(ITaskFragmentOrganizer organizer) { 530 return organizer != null && mTaskFragmentOrganizer != null 531 && organizer.asBinder().equals(mTaskFragmentOrganizer.asBinder()); 532 } 533 534 /** 535 * Returns the process of organizer if this TaskFragment is organized and the activity lives in 536 * a different process than the organizer. 537 */ 538 @Nullable getOrganizerProcessIfDifferent(@ullable ActivityRecord r)539 private WindowProcessController getOrganizerProcessIfDifferent(@Nullable ActivityRecord r) { 540 final Task task = getTask(); 541 if (r == null || task == null || task.mTaskFragmentHostProcessName == null) { 542 return null; 543 } 544 if (task.mTaskFragmentHostProcessName.equals(r.processName) 545 && task.mTaskFragmentHostUid == r.getUid()) { 546 return null; 547 } 548 return mAtmService.getProcessController(task.mTaskFragmentHostProcessName, 549 task.mTaskFragmentHostUid); 550 } 551 setAnimationParams(@onNull TaskFragmentAnimationParams animationParams)552 void setAnimationParams(@NonNull TaskFragmentAnimationParams animationParams) { 553 mAnimationParams = animationParams; 554 } 555 556 @NonNull getAnimationParams()557 TaskFragmentAnimationParams getAnimationParams() { 558 return mAnimationParams; 559 } 560 561 /** @see #mIsolatedNav */ setIsolatedNav(boolean isolatedNav)562 void setIsolatedNav(boolean isolatedNav) { 563 if (!isEmbedded()) { 564 return; 565 } 566 mIsolatedNav = isolatedNav; 567 } 568 569 /** 570 * Sets whether this TaskFragment {@link #isPinned()}. 571 * <p> 572 * Note that this is no-op if the TaskFragment is not {@link #isEmbedded() embedded}. 573 */ setPinned(boolean pinned)574 void setPinned(boolean pinned) { 575 if (!isEmbedded()) { 576 return; 577 } 578 mPinned = pinned; 579 } 580 581 /** 582 * Sets whether transitions are allowed when the TaskFragment is empty. If {@code true}, 583 * transitions are allowed when the TaskFragment is empty. If {@code false}, transitions 584 * will wait until the TaskFragment becomes non-empty or other conditions are met. Default 585 * to {@code false}. 586 */ setAllowTransitionWhenEmpty(boolean allowTransitionWhenEmpty)587 void setAllowTransitionWhenEmpty(boolean allowTransitionWhenEmpty) { 588 if (!isEmbedded()) { 589 return; 590 } 591 mAllowTransitionWhenEmpty = allowTransitionWhenEmpty; 592 } 593 setConfigurationChangeMaskForOrganizer(@ctivityInfo.Config int mask)594 void setConfigurationChangeMaskForOrganizer(@ActivityInfo.Config int mask) { 595 // Only system organizers are allowed to set configuration change mask. 596 if (mTaskFragmentOrganizerController.isSystemOrganizer(mTaskFragmentOrganizer.asBinder())) { 597 mConfigurationChangeMaskForOrganizer = mask; 598 } 599 } 600 getConfigurationChangeMaskForOrganizer()601 @ActivityInfo.Config int getConfigurationChangeMaskForOrganizer() { 602 return mConfigurationChangeMaskForOrganizer; 603 } 604 605 /** @see #mIsolatedNav */ isIsolatedNav()606 boolean isIsolatedNav() { 607 return isEmbedded() && mIsolatedNav; 608 } 609 610 /** 611 * Indicates whether this TaskFragment is pinned. 612 * 613 * @see android.window.TaskFragmentOperation#OP_TYPE_SET_PINNED 614 */ isPinned()615 boolean isPinned() { 616 return isEmbedded() && mPinned; 617 } 618 619 /** Returns the currently topmost resumed activity. */ 620 @Nullable getTopResumedActivity()621 ActivityRecord getTopResumedActivity() { 622 final ActivityRecord taskFragResumedActivity = getResumedActivity(); 623 for (int i = getChildCount() - 1; i >= 0; --i) { 624 WindowContainer<?> child = getChildAt(i); 625 ActivityRecord topResumedActivity = null; 626 if (taskFragResumedActivity != null && child == taskFragResumedActivity) { 627 topResumedActivity = child.asActivityRecord(); 628 } else if (child.asTaskFragment() != null) { 629 topResumedActivity = child.asTaskFragment().getTopResumedActivity(); 630 } 631 if (topResumedActivity != null) { 632 return topResumedActivity; 633 } 634 } 635 return null; 636 } 637 638 /** 639 * Returns the currently resumed activity in this TaskFragment's 640 * {@link #mChildren direct children} 641 */ getResumedActivity()642 ActivityRecord getResumedActivity() { 643 return mResumedActivity; 644 } 645 setResumedActivity(ActivityRecord r, String reason)646 void setResumedActivity(ActivityRecord r, String reason) { 647 if (mResumedActivity == r) { 648 return; 649 } 650 651 if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) { 652 Slog.d(TAG, "setResumedActivity taskFrag:" + this + " + from: " 653 + mResumedActivity + " to:" + r + " reason:" + reason); 654 } 655 656 if (r != null && mResumedActivity == null) { 657 // Task is becoming active. 658 getTask().touchActiveTime(); 659 } 660 661 final ActivityRecord prevR = mResumedActivity; 662 mResumedActivity = r; 663 final ActivityRecord topResumed = mTaskSupervisor.updateTopResumedActivityIfNeeded(reason); 664 if (mResumedActivity != null && topResumed != null && topResumed.isEmbedded() 665 && topResumed.getTaskFragment().isAdjacentTo(this)) { 666 // Explicitly updates the last resumed Activity if the resumed activity is 667 // adjacent to the top-resumed embedded activity. 668 mAtmService.setLastResumedActivityUncheckLocked(mResumedActivity, reason); 669 } 670 if (r == null && prevR.mDisplayContent != null 671 && prevR.mDisplayContent.getFocusedRootTask() == null) { 672 // Only need to notify DWPC when no activity will resume. 673 prevR.mDisplayContent.onRunningActivityChanged(); 674 } else if (r != null) { 675 r.mDisplayContent.onRunningActivityChanged(); 676 } 677 } 678 679 @VisibleForTesting setPausingActivity(ActivityRecord pausing)680 void setPausingActivity(ActivityRecord pausing) { 681 mPausingActivity = pausing; 682 } 683 684 /** Returns the currently topmost pausing activity. */ 685 @Nullable getTopPausingActivity()686 ActivityRecord getTopPausingActivity() { 687 final ActivityRecord taskFragPausingActivity = getPausingActivity(); 688 for (int i = getChildCount() - 1; i >= 0; --i) { 689 WindowContainer<?> child = getChildAt(i); 690 ActivityRecord topPausingActivity = null; 691 if (taskFragPausingActivity != null && child == taskFragPausingActivity) { 692 topPausingActivity = child.asActivityRecord(); 693 } else if (child.asTaskFragment() != null) { 694 topPausingActivity = child.asTaskFragment().getTopPausingActivity(); 695 } 696 if (topPausingActivity != null) { 697 return topPausingActivity; 698 } 699 } 700 return null; 701 } 702 getPausingActivity()703 ActivityRecord getPausingActivity() { 704 return mPausingActivity; 705 } 706 getDisplayId()707 int getDisplayId() { 708 final DisplayContent dc = getDisplayContent(); 709 return dc != null ? dc.mDisplayId : INVALID_DISPLAY; 710 } 711 712 @Nullable getTask()713 Task getTask() { 714 if (asTask() != null) { 715 return asTask(); 716 } 717 718 TaskFragment parent = getParent() != null ? getParent().asTaskFragment() : null; 719 return parent != null ? parent.getTask() : null; 720 } 721 722 @Override 723 @Nullable getDisplayArea()724 TaskDisplayArea getDisplayArea() { 725 return (TaskDisplayArea) super.getDisplayArea(); 726 } 727 728 @Override isAttached()729 public boolean isAttached() { 730 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 731 return taskDisplayArea != null && !taskDisplayArea.isRemoved(); 732 } 733 734 /** 735 * Returns the root {@link TaskFragment}, which is usually also a {@link Task}. 736 */ 737 @NonNull getRootTaskFragment()738 TaskFragment getRootTaskFragment() { 739 final WindowContainer parent = getParent(); 740 if (parent == null) return this; 741 742 final TaskFragment parentTaskFragment = parent.asTaskFragment(); 743 return parentTaskFragment == null ? this : parentTaskFragment.getRootTaskFragment(); 744 } 745 746 @Nullable getRootTask()747 Task getRootTask() { 748 return getRootTaskFragment().asTask(); 749 } 750 751 @Override asTaskFragment()752 TaskFragment asTaskFragment() { 753 return this; 754 } 755 756 @Override isEmbedded()757 boolean isEmbedded() { 758 return mIsEmbedded; 759 } 760 761 @EmbeddingCheckResult isAllowedToEmbedActivity(@onNull ActivityRecord a)762 int isAllowedToEmbedActivity(@NonNull ActivityRecord a) { 763 return isAllowedToEmbedActivity(a, mTaskFragmentOrganizerUid); 764 } 765 766 /** 767 * Checks if the organized task fragment is allowed to have the specified activity, which is 768 * allowed if an activity allows embedding in untrusted mode, if the trusted mode can be 769 * enabled, or if the organized task fragment bounds are not 770 * {@link #smallerThanMinDimension(ActivityRecord)}. 771 * 772 * @param uid uid of the TaskFragment organizer. 773 * @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord) 774 */ 775 @EmbeddingCheckResult isAllowedToEmbedActivity(@onNull ActivityRecord a, int uid)776 int isAllowedToEmbedActivity(@NonNull ActivityRecord a, int uid) { 777 if (!isAllowedToEmbedActivityInUntrustedMode(a) 778 && !isAllowedToEmbedActivityInTrustedMode(a, uid)) { 779 return EMBEDDING_DISALLOWED_UNTRUSTED_HOST; 780 } 781 782 if (smallerThanMinDimension(a)) { 783 return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION; 784 } 785 786 return EMBEDDING_ALLOWED; 787 } 788 smallerThanMinDimension(@onNull ActivityRecord activity)789 boolean smallerThanMinDimension(@NonNull ActivityRecord activity) { 790 final Rect taskFragBounds = getBounds(); 791 final Task task = getTask(); 792 // Don't need to check if the bounds match parent Task bounds because the fallback mechanism 793 // is to reparent the Activity to parent if minimum dimensions are not satisfied. 794 if (task == null || taskFragBounds.equals(task.getBounds())) { 795 return false; 796 } 797 final Point minDimensions = activity.getMinDimensions(); 798 if (minDimensions == null) { 799 return false; 800 } 801 final int minWidth = minDimensions.x; 802 final int minHeight = minDimensions.y; 803 return taskFragBounds.width() < minWidth 804 || taskFragBounds.height() < minHeight; 805 } 806 807 /** 808 * Checks if the organized task fragment is allowed to embed activity in untrusted mode. 809 */ isAllowedToEmbedActivityInUntrustedMode(@onNull ActivityRecord a)810 boolean isAllowedToEmbedActivityInUntrustedMode(@NonNull ActivityRecord a) { 811 final WindowContainer parent = getParent(); 812 if (parent == null || !parent.getBounds().contains(getBounds())) { 813 // Without full trust between the host and the embedded activity, we don't allow 814 // TaskFragment to have bounds outside of the parent bounds. 815 return false; 816 } 817 if (hasEmbedAnyAppInUntrustedModePermission(mTaskFragmentOrganizerUid)) { 818 return true; 819 } 820 return (a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING) 821 == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING; 822 } 823 isAllowedToEmbedActivityInTrustedMode(@onNull ActivityRecord a)824 boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) { 825 return isAllowedToEmbedActivityInTrustedMode(a, mTaskFragmentOrganizerUid); 826 } 827 828 /** 829 * Checks if the organized task fragment is allowed to embed activity in fully trusted mode, 830 * which means that all transactions are allowed. This is supported in the following cases: 831 * <li>the activity belongs to the same app as the organizer host;</li> 832 * <li>the activity has declared the organizer host as trusted explicitly via known 833 * certificate.</li> 834 * @param uid uid of the TaskFragment organizer. 835 */ isAllowedToEmbedActivityInTrustedMode(@onNull ActivityRecord a, int uid)836 boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a, int uid) { 837 if (isFullyTrustedEmbedding(a, uid)) { 838 return true; 839 } 840 841 final AndroidPackage hostPackage = mAtmService.getPackageManagerInternalLocked() 842 .getPackage(uid); 843 844 return hostPackage != null 845 && isAllowedToEmbedActivityInTrustedModeByHostPackage(a, hostPackage); 846 } 847 848 @VisibleForTesting isAllowedToEmbedActivityInTrustedModeByHostPackage( @onNull ActivityRecord a, @NonNull AndroidPackage hostPackage)849 boolean isAllowedToEmbedActivityInTrustedModeByHostPackage( 850 @NonNull ActivityRecord a, @NonNull AndroidPackage hostPackage) { 851 852 // Known certs declared in the <activity> tag 853 Set<String> knownActivityEmbeddingCerts = a.info.getKnownActivityEmbeddingCerts(); 854 855 // If the activity-level value is specified, it takes precedence. Otherwise, we read the 856 // application-level value. 857 if (knownActivityEmbeddingCerts.isEmpty()) { 858 // Known certs declared in the <application> tag 859 knownActivityEmbeddingCerts = a.info.applicationInfo.getKnownActivityEmbeddingCerts(); 860 } 861 862 // An application must specify a set of app certificates that are allowed to embed it in 863 // trusted mode. 864 return hostPackage.getSigningDetails().hasAncestorOrSelfWithDigest( 865 knownActivityEmbeddingCerts); 866 } 867 868 /** 869 * It is fully trusted for embedding in the system app or embedding in the same app. This is 870 * different from {@link #isAllowedToBeEmbeddedInTrustedMode()} since there may be a small 871 * chance for a previous trusted app to start doing something bad. 872 */ isFullyTrustedEmbedding(@onNull ActivityRecord a, int uid)873 private static boolean isFullyTrustedEmbedding(@NonNull ActivityRecord a, int uid) { 874 // The system is trusted to embed other apps securely and for all users. 875 return UserHandle.getAppId(uid) == SYSTEM_UID 876 // Activities from the same UID can be embedded freely by the host. 877 || a.isUid(uid) 878 // Apps which have the signature MANAGE_ACTIVITY_TASK permission are trusted. 879 || hasManageTaskPermission(uid); 880 } 881 882 /** 883 * Checks if a particular app uid has the {@link MANAGE_ACTIVITY_TASKS} permission. 884 */ hasManageTaskPermission(int uid)885 private static boolean hasManageTaskPermission(int uid) { 886 return checkPermission(MANAGE_ACTIVITY_TASKS, PermissionChecker.PID_UNKNOWN, uid) 887 == PackageManager.PERMISSION_GRANTED; 888 } 889 890 /** 891 * Checks if a particular app uid has the {@link EMBED_ANY_APP_IN_UNTRUSTED_MODE} permission. 892 */ hasEmbedAnyAppInUntrustedModePermission(int uid)893 private static boolean hasEmbedAnyAppInUntrustedModePermission(int uid) { 894 return Flags.untrustedEmbeddingAnyAppPermission() 895 && checkPermission(EMBED_ANY_APP_IN_UNTRUSTED_MODE, 896 PermissionChecker.PID_UNKNOWN, uid) == PackageManager.PERMISSION_GRANTED; 897 } 898 899 /** 900 * Checks if all activities in the task fragment are embedded as fully trusted. 901 * @see #isFullyTrustedEmbedding(ActivityRecord, int) 902 * @param uid uid of the TaskFragment organizer. 903 */ isFullyTrustedEmbedding(int uid)904 boolean isFullyTrustedEmbedding(int uid) { 905 // Traverse all activities to see if any of them are not fully trusted embedding. 906 return !forAllActivities(r -> !isFullyTrustedEmbedding(r, uid)); 907 } 908 909 /** 910 * Checks if all activities in the task fragment are allowed to be embedded in trusted mode. 911 * @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord) 912 */ isAllowedToBeEmbeddedInTrustedMode()913 boolean isAllowedToBeEmbeddedInTrustedMode() { 914 // Traverse all activities to see if any of them are not in the trusted mode. 915 return !forAllActivities(r -> !isAllowedToEmbedActivityInTrustedMode(r)); 916 } 917 918 /** 919 * @param canAffectSystemUiFlags If false, all windows in this taskfragment can not affect 920 * SystemUI flags. See 921 * {@link WindowState#canAffectSystemUiFlags()}. 922 */ setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags)923 void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) { 924 mCanAffectSystemUiFlags = canAffectSystemUiFlags; 925 } 926 927 /** 928 * @see #setCanAffectSystemUiFlags 929 */ canAffectSystemUiFlags()930 boolean canAffectSystemUiFlags() { 931 if (!mCanAffectSystemUiFlags) { 932 return false; 933 } 934 final TaskFragment parentTaskFragment = 935 getParent() != null ? getParent().asTaskFragment() : null; 936 return parentTaskFragment == null || parentTaskFragment.canAffectSystemUiFlags(); 937 } 938 939 /** 940 * Returns the TaskFragment that is being organized, which could be this or the ascendant 941 * TaskFragment. 942 */ 943 @Nullable getOrganizedTaskFragment()944 TaskFragment getOrganizedTaskFragment() { 945 if (mTaskFragmentOrganizer != null) { 946 return this; 947 } 948 949 TaskFragment parentTaskFragment = getParent() != null ? getParent().asTaskFragment() : null; 950 return parentTaskFragment != null ? parentTaskFragment.getOrganizedTaskFragment() : null; 951 } 952 hasDirectChildActivities()953 boolean hasDirectChildActivities() { 954 for (int i = mChildren.size() - 1; i >= 0; --i) { 955 if (mChildren.get(i).asActivityRecord() != null) { 956 return true; 957 } 958 } 959 return false; 960 } 961 cleanUpActivityReferences(@onNull ActivityRecord r)962 void cleanUpActivityReferences(@NonNull ActivityRecord r) { 963 if (mPausingActivity != null && mPausingActivity == r) { 964 mPausingActivity = null; 965 } 966 967 if (mResumedActivity != null && mResumedActivity == r) { 968 setResumedActivity(null, "cleanUpActivityReferences"); 969 } 970 r.removeTimeouts(); 971 } 972 973 /** 974 * Returns whether this TaskFragment is currently forced to be hidden for any reason. 975 */ isForceHidden()976 protected boolean isForceHidden() { 977 return mForceHiddenFlags != 0; 978 } 979 980 /** 981 * Sets/unsets the forced-hidden state flag for this task depending on {@param set}. 982 * @return Whether the force hidden state changed 983 */ setForceHidden(@lagForceHidden int flags, boolean set)984 boolean setForceHidden(@FlagForceHidden int flags, boolean set) { 985 int newFlags = mForceHiddenFlags; 986 if (set) { 987 newFlags |= flags; 988 } else { 989 newFlags &= ~flags; 990 } 991 if (mForceHiddenFlags == newFlags) { 992 return false; 993 } 994 mForceHiddenFlags = newFlags; 995 return true; 996 } 997 isForceTranslucent()998 boolean isForceTranslucent() { 999 return mForceTranslucent; 1000 } 1001 setForceTranslucent(boolean set)1002 boolean setForceTranslucent(boolean set) { 1003 if (mForceTranslucent == set) { 1004 return false; 1005 } 1006 mForceTranslucent = set; 1007 return true; 1008 } 1009 isLeafTaskFragment()1010 boolean isLeafTaskFragment() { 1011 for (int i = mChildren.size() - 1; i >= 0; --i) { 1012 if (mChildren.get(i).asTaskFragment() != null) { 1013 return false; 1014 } 1015 } 1016 return true; 1017 } 1018 1019 /** 1020 * This should be called when an child activity changes state. This should only 1021 * be called from 1022 * {@link ActivityRecord#setState(ActivityRecord.State, String)} . 1023 * @param record The {@link ActivityRecord} whose state has changed. 1024 * @param state The new state. 1025 * @param reason The reason for the change. 1026 */ onActivityStateChanged(ActivityRecord record, ActivityRecord.State state, String reason)1027 void onActivityStateChanged(ActivityRecord record, ActivityRecord.State state, 1028 String reason) { 1029 if (record == mResumedActivity && state != RESUMED) { 1030 setResumedActivity(null, reason + " - onActivityStateChanged"); 1031 } 1032 1033 if (state == RESUMED) { 1034 if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) { 1035 Slog.v(TAG, "set resumed activity to:" + record + " reason:" + reason); 1036 } 1037 setResumedActivity(record, reason + " - onActivityStateChanged"); 1038 mTaskSupervisor.mRecentTasks.add(record.getTask()); 1039 } 1040 1041 // Update the process state for the organizer process if the activity is in a different 1042 // process in case the organizer process may not have activity state change in its process. 1043 final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(record); 1044 if (hostProcess != null) { 1045 mTaskSupervisor.onProcessActivityStateChanged(hostProcess, false /* forceBatch */); 1046 hostProcess.updateProcessInfo(false /* updateServiceConnectionActivities */, 1047 true /* activityChange */, true /* updateOomAdj */, 1048 false /* addPendingTopUid */); 1049 } 1050 } 1051 1052 /** 1053 * Resets local parameters because an app's activity died. 1054 * @param app The app of the activity that died. 1055 * @return {@code true} if the process of the pausing activity is died. 1056 */ handleAppDied(WindowProcessController app)1057 boolean handleAppDied(WindowProcessController app) { 1058 boolean isPausingDied = false; 1059 if (mPausingActivity != null && mPausingActivity.app == app) { 1060 ProtoLog.v(WM_DEBUG_STATES, "App died while pausing: %s", 1061 mPausingActivity); 1062 mPausingActivity = null; 1063 isPausingDied = true; 1064 } 1065 if (mLastPausedActivity != null && mLastPausedActivity.app == app) { 1066 mLastPausedActivity = null; 1067 } 1068 return isPausingDied; 1069 } 1070 awakeFromSleeping()1071 void awakeFromSleeping() { 1072 if (mPausingActivity != null) { 1073 Slog.d(TAG, "awakeFromSleeping: previously pausing activity didn't pause"); 1074 mPausingActivity.activityPaused(true); 1075 } 1076 } 1077 1078 /** 1079 * Tries to put the activities in the task fragment to sleep. 1080 * 1081 * If the task fragment is not in a state where its activities can be put to sleep, this 1082 * function will start any necessary actions to move the task fragment into such a state. 1083 * It is expected that this function get called again when those actions complete. 1084 * 1085 * @param shuttingDown {@code true} when the called because the device is shutting down. 1086 * @return true if the root task finished going to sleep, false if the root task only started 1087 * the process of going to sleep (checkReadyForSleep will be called when that process finishes). 1088 */ sleepIfPossible(boolean shuttingDown)1089 boolean sleepIfPossible(boolean shuttingDown) { 1090 boolean shouldSleep = true; 1091 if (mResumedActivity != null) { 1092 if (!shuttingDown && mResumedActivity.canTurnScreenOn()) { 1093 ProtoLog.v(WM_DEBUG_STATES, "Waiting for screen on due to %s", mResumedActivity); 1094 } else { 1095 // Still have something resumed; can't sleep until it is paused. 1096 ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity); 1097 startPausing(true /* uiSleeping */, null /* resuming */, "sleep"); 1098 } 1099 shouldSleep = false; 1100 } else if (mPausingActivity != null) { 1101 // Still waiting for something to pause; can't sleep yet. 1102 ProtoLog.v(WM_DEBUG_STATES, "Sleep still waiting to pause %s", mPausingActivity); 1103 shouldSleep = false; 1104 } 1105 1106 if (!shuttingDown) { 1107 if (containsStoppingActivity()) { 1108 // Still need to tell some activities to stop; can't sleep yet. 1109 ProtoLog.v(WM_DEBUG_STATES, "Sleep still need to stop %d activities", 1110 mTaskSupervisor.mStoppingActivities.size()); 1111 1112 mTaskSupervisor.scheduleIdle(); 1113 shouldSleep = false; 1114 } 1115 } 1116 1117 if (shouldSleep) { 1118 updateActivityVisibilities(null /* starting */, true /* notifyClients */); 1119 } 1120 1121 return shouldSleep; 1122 } 1123 containsStoppingActivity()1124 private boolean containsStoppingActivity() { 1125 for (int i = mTaskSupervisor.mStoppingActivities.size() - 1; i >= 0; --i) { 1126 ActivityRecord r = mTaskSupervisor.mStoppingActivities.get(i); 1127 if (r.getTaskFragment() == this) { 1128 return true; 1129 } 1130 } 1131 return false; 1132 } 1133 1134 /** 1135 * Returns true if the TaskFragment is translucent and can have other contents visible behind 1136 * it if needed. A TaskFragment is considered translucent if it don't contain a visible or 1137 * starting (about to be visible) activity that is fullscreen (opaque). 1138 * @param starting The currently starting activity or null if there is none. 1139 */ isTranslucent(@ullable ActivityRecord starting)1140 boolean isTranslucent(@Nullable ActivityRecord starting) { 1141 if (!isAttached() || isForceHidden() || isForceTranslucent()) { 1142 return true; 1143 } 1144 return !mTaskSupervisor.mOpaqueContainerHelper.isOpaque( 1145 this, starting, true /* ignoringKeyguard */, true /* ignoringInvisibleActivity */); 1146 } 1147 1148 /** 1149 * Whether the TaskFragment should be treated as translucent for the current transition. 1150 * This is different from {@link #isTranslucent(ActivityRecord)} as this function also checks 1151 * finishing activities when the TaskFragment itself is becoming invisible. 1152 */ isTranslucentForTransition()1153 boolean isTranslucentForTransition() { 1154 if (!isAttached() || isForceHidden() || isForceTranslucent()) { 1155 return true; 1156 } 1157 // Including finishing Activity if the TaskFragment is becoming invisible in the transition. 1158 return !mTaskSupervisor.mOpaqueContainerHelper.isOpaque(this); 1159 } 1160 1161 /** 1162 * Like {@link #isTranslucent(ActivityRecord)} but evaluating the actual visibility of the 1163 * windows rather than their visibility ignoring keyguard. 1164 */ isTranslucentAndVisible()1165 boolean isTranslucentAndVisible() { 1166 if (!isAttached() || isForceHidden() || isForceTranslucent()) { 1167 return true; 1168 } 1169 return !mTaskSupervisor.mOpaqueContainerHelper.isOpaque(this, /* starting */ null, 1170 false /* ignoringKeyguard */, true /* ignoringInvisibleActivity */); 1171 } 1172 1173 @Override getTopNonFinishingActivity()1174 ActivityRecord getTopNonFinishingActivity() { 1175 return getTopNonFinishingActivity( 1176 true /* includeOverlays */, true /* includeLaunchedFromBubble */); 1177 } 1178 1179 /** 1180 * Returns the top-most non-finishing activity, even if the activity is NOT ok to show to 1181 * the current user. 1182 * @param includeOverlays whether the task overlay activity should be included. 1183 * @param includeLaunchedFromBubble whether activities that were launched from a bubble should 1184 * be included. 1185 * @see #topRunningActivity(boolean) 1186 */ getTopNonFinishingActivity(boolean includeOverlays, boolean includeLaunchedFromBubble)1187 ActivityRecord getTopNonFinishingActivity(boolean includeOverlays, 1188 boolean includeLaunchedFromBubble) { 1189 // Split to avoid object creation due to variable capture. 1190 if (includeOverlays) { 1191 if (includeLaunchedFromBubble) { 1192 return getActivity(r -> !r.finishing); 1193 } else { 1194 return getActivity(r -> !r.finishing && !r.getLaunchedFromBubble()); 1195 } 1196 } 1197 if (includeLaunchedFromBubble) { 1198 return getActivity(r -> !r.finishing && !r.isTaskOverlay()); 1199 } else { 1200 return getActivity( 1201 r -> !r.finishing && !r.isTaskOverlay() && !r.getLaunchedFromBubble()); 1202 } 1203 } 1204 topRunningActivity()1205 ActivityRecord topRunningActivity() { 1206 return topRunningActivity(false /* focusableOnly */); 1207 } 1208 1209 /** 1210 * Returns the top-most running activity, which the activity is non-finishing and ok to show 1211 * to the current user. 1212 * 1213 * @see ActivityRecord#canBeTopRunning() 1214 */ topRunningActivity(boolean focusableOnly)1215 ActivityRecord topRunningActivity(boolean focusableOnly) { 1216 // Split into 2 to avoid object creation due to variable capture. 1217 if (focusableOnly) { 1218 return getActivity((r) -> r.canBeTopRunning() && r.isFocusable()); 1219 } 1220 return getActivity(ActivityRecord::canBeTopRunning); 1221 } 1222 1223 /** 1224 * Reports non-finishing activity count including this TaskFragment's child embedded 1225 * TaskFragments' children activities. 1226 */ getNonFinishingActivityCount()1227 int getNonFinishingActivityCount() { 1228 final int[] runningActivityCount = new int[1]; 1229 forAllActivities(a -> { 1230 if (!a.finishing) { 1231 runningActivityCount[0]++; 1232 } 1233 }); 1234 return runningActivityCount[0]; 1235 } 1236 1237 /** 1238 * Returns {@code true} if there's any non-finishing direct children activity, which is not 1239 * embedded in TaskFragments 1240 */ hasNonFinishingDirectActivity()1241 boolean hasNonFinishingDirectActivity() { 1242 for (int i = getChildCount() - 1; i >= 0; --i) { 1243 final ActivityRecord activity = getChildAt(i).asActivityRecord(); 1244 if (activity != null && !activity.finishing) { 1245 return true; 1246 } 1247 } 1248 return false; 1249 } 1250 isTopActivityFocusable()1251 boolean isTopActivityFocusable() { 1252 final ActivityRecord r = topRunningActivity(); 1253 return r != null ? r.isFocusable() 1254 : (isFocusable() && getWindowConfiguration().canReceiveKeys()); 1255 } 1256 1257 /** 1258 * Returns the visibility state of this TaskFragment. 1259 * 1260 * @param starting The currently starting activity or null if there is none. 1261 */ 1262 @TaskFragmentVisibility getVisibility(ActivityRecord starting)1263 int getVisibility(ActivityRecord starting) { 1264 if (!isAttached() || isForceHidden()) { 1265 return TASK_FRAGMENT_VISIBILITY_INVISIBLE; 1266 } 1267 1268 if (isTopActivityLaunchedBehind()) { 1269 return TASK_FRAGMENT_VISIBILITY_VISIBLE; 1270 } 1271 final WindowContainer<?> parent = getParent(); 1272 final Task thisTask = asTask(); 1273 if (thisTask != null && parent.asTask() == null 1274 && mTransitionController.isTransientVisible(thisTask)) { 1275 // Keep transient-hide root tasks visible. Non-root tasks still follow standard rule. 1276 return TASK_FRAGMENT_VISIBILITY_VISIBLE; 1277 } 1278 1279 boolean gotTranslucentFullscreen = false; 1280 boolean gotTranslucentAdjacent = false; 1281 boolean shouldBeVisible = true; 1282 1283 // This TaskFragment is only considered visible if all its parent TaskFragments are 1284 // considered visible, so check the visibility of all ancestor TaskFragment first. 1285 if (parent.asTaskFragment() != null) { 1286 final int parentVisibility = parent.asTaskFragment().getVisibility(starting); 1287 if (parentVisibility == TASK_FRAGMENT_VISIBILITY_INVISIBLE) { 1288 // Can't be visible if parent isn't visible 1289 return TASK_FRAGMENT_VISIBILITY_INVISIBLE; 1290 } else if (parentVisibility == TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) { 1291 // Parent is behind a translucent container so the highest visibility this container 1292 // can get is that. 1293 gotTranslucentFullscreen = true; 1294 } 1295 } 1296 1297 final List<TaskFragment> adjacentTaskFragments = new ArrayList<>(); 1298 for (int i = parent.getChildCount() - 1; i >= 0; --i) { 1299 final WindowContainer other = parent.getChildAt(i); 1300 if (other == null) continue; 1301 1302 final boolean hasRunningActivities = hasRunningActivity(other); 1303 if (other == this) { 1304 if (!adjacentTaskFragments.isEmpty() && !gotTranslucentAdjacent) { 1305 // The z-order of this TaskFragment is in middle of two adjacent TaskFragments 1306 // and it cannot be visible if the TaskFragment on top is not translucent and 1307 // is occluding this one. 1308 mTmpRect.set(getBounds()); 1309 for (int j = adjacentTaskFragments.size() - 1; j >= 0; --j) { 1310 final TaskFragment taskFragment = adjacentTaskFragments.get(j); 1311 if (taskFragment.isAdjacentTo(this)) { 1312 continue; 1313 } 1314 final boolean isOccluding = mTmpRect.intersect(taskFragment.getBounds()) 1315 || taskFragment.forOtherAdjacentTaskFragments(adjacentTf -> { 1316 return mTmpRect.intersect(adjacentTf.getBounds()); 1317 }); 1318 if (isOccluding) { 1319 return TASK_FRAGMENT_VISIBILITY_INVISIBLE; 1320 } 1321 } 1322 } 1323 // Should be visible if there is no other fragment occluding it, unless it doesn't 1324 // have any running activities, not starting one and not home stack. 1325 shouldBeVisible = hasRunningActivities 1326 || (starting != null && starting.isDescendantOf(this)) 1327 || (isActivityTypeHome() && !isEmbedded()); 1328 break; 1329 } 1330 1331 if (!hasRunningActivities) { 1332 continue; 1333 } 1334 1335 final int otherWindowingMode = other.getWindowingMode(); 1336 if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN 1337 || (otherWindowingMode != WINDOWING_MODE_PINNED && other.matchParentBounds())) { 1338 if (isTranslucent(other, starting)) { 1339 // Can be visible behind a translucent TaskFragment. 1340 gotTranslucentFullscreen = true; 1341 continue; 1342 } 1343 return TASK_FRAGMENT_VISIBILITY_INVISIBLE; 1344 } 1345 1346 final TaskFragment otherTaskFrag = other.asTaskFragment(); 1347 if (otherTaskFrag != null && otherTaskFrag.hasAdjacentTaskFragment()) { 1348 // For adjacent TaskFragments, we have assumptions that: 1349 // 1. A set of adjacent TaskFragments always cover the entire Task window, so that 1350 // if this TaskFragment is behind a set of opaque TaskFragments, then this 1351 // TaskFragment is invisible. 1352 // 2. Adjacent TaskFragments do not overlap, so that if this TaskFragment is behind 1353 // any translucent TaskFragment in the adjacent set, then this TaskFragment is 1354 // visible behind translucent. 1355 final boolean hasTraversedAdj = otherTaskFrag.forOtherAdjacentTaskFragments( 1356 adjacentTaskFragments::contains); 1357 if (hasTraversedAdj) { 1358 final boolean isTranslucent = 1359 isBehindTransparentTaskFragment(otherTaskFrag, starting) 1360 || otherTaskFrag.forOtherAdjacentTaskFragments( 1361 (Predicate<TaskFragment>) tf -> 1362 isBehindTransparentTaskFragment(tf, starting)); 1363 if (isTranslucent) { 1364 // Can be visible behind a translucent adjacent TaskFragments. 1365 gotTranslucentFullscreen = true; 1366 gotTranslucentAdjacent = true; 1367 continue; 1368 } 1369 // Can not be visible behind adjacent TaskFragments. 1370 return TASK_FRAGMENT_VISIBILITY_INVISIBLE; 1371 } 1372 adjacentTaskFragments.add(otherTaskFrag); 1373 } 1374 } 1375 1376 if (!shouldBeVisible) { 1377 return TASK_FRAGMENT_VISIBILITY_INVISIBLE; 1378 } 1379 1380 // Lastly - check if there is a translucent fullscreen TaskFragment on top. 1381 return gotTranslucentFullscreen 1382 ? TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT 1383 : TASK_FRAGMENT_VISIBILITY_VISIBLE; 1384 } 1385 isBehindTransparentTaskFragment( @onNull TaskFragment otherTf, @Nullable ActivityRecord starting)1386 private boolean isBehindTransparentTaskFragment( 1387 @NonNull TaskFragment otherTf, @Nullable ActivityRecord starting) { 1388 return otherTf.isTranslucent(starting) && getBounds().intersect(otherTf.getBounds()); 1389 } 1390 hasRunningActivity(WindowContainer wc)1391 private static boolean hasRunningActivity(WindowContainer wc) { 1392 if (wc.asTaskFragment() != null) { 1393 return wc.asTaskFragment().topRunningActivity() != null; 1394 } 1395 return wc.asActivityRecord() != null && !wc.asActivityRecord().finishing; 1396 } 1397 isTranslucent(WindowContainer wc, ActivityRecord starting)1398 private static boolean isTranslucent(WindowContainer wc, ActivityRecord starting) { 1399 if (wc.asTaskFragment() != null) { 1400 return wc.asTaskFragment().isTranslucent(starting); 1401 } else if (wc.asActivityRecord() != null) { 1402 return !wc.asActivityRecord().occludesParent(); 1403 } 1404 return false; 1405 } 1406 1407 isTopActivityLaunchedBehind()1408 private boolean isTopActivityLaunchedBehind() { 1409 final ActivityRecord top = topRunningActivity(); 1410 return top != null && top.mLaunchTaskBehind; 1411 } 1412 updateActivityVisibilities(@ullable ActivityRecord starting, boolean notifyClients)1413 final void updateActivityVisibilities(@Nullable ActivityRecord starting, 1414 boolean notifyClients) { 1415 mTaskSupervisor.beginActivityVisibilityUpdate(); 1416 try { 1417 mEnsureActivitiesVisibleHelper.process(starting, notifyClients); 1418 } finally { 1419 mTaskSupervisor.endActivityVisibilityUpdate(); 1420 } 1421 } 1422 resumeTopActivity(ActivityRecord prev, ActivityOptions options, boolean skipPause)1423 final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options, 1424 boolean skipPause) { 1425 ActivityRecord next = topRunningActivity(true /* focusableOnly */); 1426 if (next == null || !next.canResumeByCompat()) { 1427 return false; 1428 } 1429 1430 next.delayedResume = false; 1431 1432 if (!skipPause && !mRootWindowContainer.allPausedActivitiesComplete()) { 1433 // If we aren't skipping pause, then we have to wait for currently pausing activities. 1434 ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: some activity pausing."); 1435 return false; 1436 } 1437 1438 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 1439 // If the top activity is the resumed one, nothing to do. 1440 if (mResumedActivity == next && next.isState(RESUMED) 1441 && taskDisplayArea.allResumedActivitiesComplete()) { 1442 // Ensure the visibility gets updated before execute app transition. 1443 taskDisplayArea.ensureActivitiesVisible(null /* starting */, true /* notifyClients */); 1444 // Make sure we have executed any pending transitions, since there 1445 // should be nothing left to do at this point. 1446 executeAppTransition(options); 1447 1448 // In a multi-resumed environment, like in a freeform device, the top 1449 // activity can be resumed, but it might not be the focused app. 1450 // Set focused app when top activity is resumed. However, we shouldn't do it for a 1451 // same task because it can break focused state. (e.g. activity embedding) 1452 if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null) { 1453 final ActivityRecord focusedApp = taskDisplayArea.mDisplayContent.mFocusedApp; 1454 if (focusedApp == null || focusedApp.getTask() != next.getTask()) { 1455 taskDisplayArea.mDisplayContent.setFocusedApp(next); 1456 } 1457 } 1458 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity " 1459 + "resumed %s", next); 1460 return false; 1461 } 1462 1463 // If we are sleeping, and there is no resumed activity, and the top activity is paused, 1464 // well that is the state we want. 1465 if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) { 1466 // Make sure we have executed any pending transitions, since there 1467 // should be nothing left to do at this point. 1468 executeAppTransition(options); 1469 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Going to sleep and" 1470 + " all paused"); 1471 return false; 1472 } 1473 1474 // Make sure that the user who owns this activity is started. If not, 1475 // we will just leave it as is because someone should be bringing 1476 // another user's activities to the top of the stack. 1477 if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) { 1478 Slog.w(TAG, "Skipping resume of top activity " + next 1479 + ": user " + next.mUserId + " is stopped"); 1480 return false; 1481 } 1482 1483 // The activity may be waiting for stop, but that is no longer 1484 // appropriate for it. 1485 mTaskSupervisor.mStoppingActivities.remove(next); 1486 1487 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); 1488 1489 mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid); 1490 1491 ActivityRecord lastResumed = null; 1492 final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask(); 1493 if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTaskFragment().asTask()) { 1494 // So, why aren't we using prev here??? See the param comment on the method. prev 1495 // doesn't represent the last resumed activity. However, the last focus stack does if 1496 // it isn't null. 1497 lastResumed = lastFocusedRootTask.getTopResumedActivity(); 1498 } 1499 1500 boolean pausing = !skipPause && taskDisplayArea.pauseBackTasks(next); 1501 if (mResumedActivity != null) { 1502 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity); 1503 pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */, 1504 next, "resumeTopActivity"); 1505 } 1506 if (pausing) { 1507 ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to" 1508 + " start pausing"); 1509 // At this point we want to put the upcoming activity's process 1510 // at the top of the LRU list, since we know we will be needing it 1511 // very soon and it would be a waste to let it get killed if it 1512 // happens to be sitting towards the end. 1513 if (next.attachedToProcess()) { 1514 next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, 1515 true /* activityChange */, false /* updateOomAdj */, 1516 false /* addPendingTopUid */); 1517 } else if (!next.isProcessRunning()) { 1518 // Since the start-process is asynchronous, if we already know the process of next 1519 // activity isn't running, we can start the process earlier to save the time to wait 1520 // for the current activity to be paused. 1521 final boolean isTop = this == taskDisplayArea.getFocusedRootTask(); 1522 mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop, 1523 isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY 1524 : HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY); 1525 } 1526 if (lastResumed != null) { 1527 lastResumed.setWillCloseOrEnterPip(true); 1528 } 1529 return true; 1530 } else if (mResumedActivity == next && next.isState(RESUMED) 1531 && taskDisplayArea.allResumedActivitiesComplete()) { 1532 // It is possible for the activity to be resumed when we paused back stacks above if the 1533 // next activity doesn't have to wait for pause to complete. 1534 // So, nothing else to-do except: 1535 // Make sure we have executed any pending transitions, since there 1536 // should be nothing left to do at this point. 1537 executeAppTransition(options); 1538 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity resumed " 1539 + "(dontWaitForPause) %s", next); 1540 return true; 1541 } 1542 1543 // If the most recent activity was noHistory but was only stopped rather 1544 // than stopped+finished because the device went to sleep, we need to make 1545 // sure to finish it as we're making a new activity topmost. 1546 if (shouldSleepActivities()) { 1547 mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next); 1548 } 1549 1550 if (prev != null && prev != next && next.nowVisible) { 1551 // The next activity is already visible, so hide the previous 1552 // activity's windows right now so we can show the new one ASAP. 1553 // We only do this if the previous is finishing, which should mean 1554 // it is on top of the one being resumed so hiding it quickly 1555 // is good. Otherwise, we want to do the normal route of allowing 1556 // the resumed activity to be shown so we can decide if the 1557 // previous should actually be hidden depending on whether the 1558 // new one is found to be full-screen or not. 1559 if (prev.finishing) { 1560 prev.setVisibility(false); 1561 if (DEBUG_SWITCH) { 1562 Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev 1563 + ", nowVisible=" + next.nowVisible); 1564 } 1565 } else { 1566 if (DEBUG_SWITCH) { 1567 Slog.v(TAG_SWITCH, "Previous already visible but still waiting to hide: " + prev 1568 + ", nowVisible=" + next.nowVisible); 1569 } 1570 } 1571 } 1572 1573 try { 1574 mTaskSupervisor.getActivityMetricsLogger() 1575 .notifyBeforePackageUnstopped(next.packageName); 1576 mAtmService.getPackageManagerInternalLocked().notifyComponentUsed( 1577 next.packageName, next.mUserId, 1578 next.packageName, next.toString()); /* TODO: Verify if correct userid */ 1579 } catch (IllegalArgumentException e) { 1580 Slog.w(TAG, "Failed trying to unstop package " 1581 + next.packageName + ": " + e); 1582 } 1583 1584 // We are starting up the next activity, so tell the window manager 1585 // that the previous one will be hidden soon. This way it can know 1586 // to ignore it when computing the desired screen orientation. 1587 boolean anim = true; 1588 final DisplayContent dc = taskDisplayArea.mDisplayContent; 1589 if (prev != null) { 1590 if (prev.finishing) { 1591 if (mTaskSupervisor.mNoAnimActivities.contains(prev)) { 1592 anim = false; 1593 } 1594 prev.setVisibility(false); 1595 } else if (mTaskSupervisor.mNoAnimActivities.contains(next)) { 1596 anim = false; 1597 } 1598 } else if (mTaskSupervisor.mNoAnimActivities.contains(next)) { 1599 anim = false; 1600 } 1601 1602 if (anim) { 1603 next.applyOptionsAnimation(); 1604 } else { 1605 next.abortAndClearOptionsAnimation(); 1606 } 1607 1608 mTaskSupervisor.mNoAnimActivities.clear(); 1609 1610 if (next.attachedToProcess()) { 1611 if (DEBUG_SWITCH) { 1612 Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.mAppStopped 1613 + " visibleRequested=" + next.isVisibleRequested()); 1614 } 1615 1616 // If the previous activity is translucent, force a visibility update of 1617 // the next activity, so that it's added to WM's opening app list, and 1618 // transition animation can be set up properly. 1619 // For example, pressing Home button with a translucent activity in focus. 1620 // Launcher is already visible in this case. If we don't add it to opening 1621 // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a 1622 // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation. 1623 final boolean lastActivityTranslucent = inMultiWindowMode() 1624 || mLastPausedActivity != null && !mLastPausedActivity.occludesParent(); 1625 1626 // This activity is now becoming visible. 1627 if (!next.isVisibleRequested() || next.mAppStopped || lastActivityTranslucent) { 1628 next.app.addToPendingTop(); 1629 next.setVisibility(true); 1630 } 1631 1632 ActivityRecord lastResumedActivity = 1633 lastFocusedRootTask == null ? null 1634 : lastFocusedRootTask.getTopResumedActivity(); 1635 final ActivityRecord.State lastState = next.getState(); 1636 1637 mAtmService.updateCpuStats(); 1638 1639 ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next); 1640 1641 next.setState(RESUMED, "resumeTopActivity"); 1642 1643 // Activity should also be visible if set mLaunchTaskBehind to true (see 1644 // ActivityRecord#shouldBeVisibleIgnoringKeyguard()). 1645 if (shouldBeVisible(next)) { 1646 // We have special rotation behavior when here is some active activity that 1647 // requests specific orientation or Keyguard is locked. Make sure all activity 1648 // visibilities are set correctly as well as the transition is updated if needed 1649 // to get the correct rotation behavior. Otherwise the following call to update 1650 // the orientation may cause incorrect configurations delivered to client as a 1651 // result of invisible window resize. 1652 // TODO: Remove this once visibilities are set correctly immediately when 1653 // starting an activity. 1654 final int originalRelaunchingCount = next.mPendingRelaunchCount; 1655 mRootWindowContainer.ensureVisibilityAndConfig(next, mDisplayContent, 1656 false /* deferResume */); 1657 if (next.mPendingRelaunchCount > originalRelaunchingCount) { 1658 // The activity is scheduled to relaunch, then ResumeActivityItem will be also 1659 // included (see ActivityRecord#relaunchActivityLocked) if it should resume. 1660 next.completeResumeLocked(); 1661 return true; 1662 } 1663 } 1664 1665 final IApplicationThread appThread = next.app.getThread(); 1666 // Deliver all pending results. 1667 final ArrayList<ResultInfo> a = next.results; 1668 if (a != null) { 1669 final int size = a.size(); 1670 if (!next.finishing && size > 0) { 1671 if (DEBUG_RESULTS) { 1672 Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a); 1673 } 1674 final ActivityResultItem item = new ActivityResultItem(next.token, a); 1675 boolean isSuccessful; 1676 try { 1677 isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem( 1678 appThread, item); 1679 } catch (RemoteException e) { 1680 // TODO(b/323801078): remove Exception when cleanup 1681 isSuccessful = false; 1682 } 1683 if (!isSuccessful) { 1684 onResumeTopActivityRemoteFailure(lastState, next, lastResumedActivity, 1685 lastFocusedRootTask); 1686 return true; 1687 } 1688 } 1689 } 1690 1691 if (next.newIntents != null) { 1692 final NewIntentItem item = 1693 new NewIntentItem(next.token, next.newIntents, true /* resume */); 1694 boolean isSuccessful; 1695 try { 1696 isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem( 1697 appThread, item); 1698 } catch (RemoteException e) { 1699 // TODO(b/323801078): remove Exception when cleanup 1700 isSuccessful = false; 1701 } 1702 if (!isSuccessful) { 1703 onResumeTopActivityRemoteFailure(lastState, next, lastResumedActivity, 1704 lastFocusedRootTask); 1705 return true; 1706 } 1707 } 1708 1709 // Well the app will no longer be stopped. 1710 // Clear app token stopped state in window manager if needed. 1711 next.notifyAppResumed(); 1712 1713 EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next), 1714 next.getTask().mTaskId, next.shortComponentName); 1715 1716 mAtmService.getAppWarningsLocked().onResumeActivity(next); 1717 final int topProcessState = mAtmService.mTopProcessState; 1718 next.app.setPendingUiCleanAndForceProcessStateUpTo(topProcessState); 1719 next.abortAndClearOptionsAnimation(); 1720 final ResumeActivityItem resumeActivityItem = new ResumeActivityItem( 1721 next.token, topProcessState, dc.isNextTransitionForward(), 1722 next.shouldSendCompatFakeFocus()); 1723 boolean isSuccessful; 1724 try { 1725 isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem( 1726 appThread, resumeActivityItem); 1727 } catch (RemoteException e) { 1728 // TODO(b/323801078): remove Exception when cleanup 1729 isSuccessful = false; 1730 } 1731 if (!isSuccessful) { 1732 onResumeTopActivityRemoteFailure(lastState, next, lastResumedActivity, 1733 lastFocusedRootTask); 1734 return true; 1735 } 1736 1737 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next); 1738 1739 next.completeResumeLocked(); 1740 } else { 1741 // Whoops, need to restart this activity! 1742 if (!next.hasBeenLaunched) { 1743 next.hasBeenLaunched = true; 1744 } else { 1745 if (SHOW_APP_STARTING_PREVIEW) { 1746 next.showStartingWindow(false /* taskSwich */); 1747 } 1748 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); 1749 } 1750 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next); 1751 mTaskSupervisor.startSpecificActivity(next, true, true); 1752 } 1753 1754 return true; 1755 } 1756 1757 /** Likely app process has been killed. Needs to restart this activity. */ onResumeTopActivityRemoteFailure(@onNull ActivityRecord.State lastState, @NonNull ActivityRecord next, @Nullable ActivityRecord lastResumedActivity, @Nullable Task lastFocusedRootTask)1758 private void onResumeTopActivityRemoteFailure(@NonNull ActivityRecord.State lastState, 1759 @NonNull ActivityRecord next, @Nullable ActivityRecord lastResumedActivity, 1760 @Nullable Task lastFocusedRootTask) { 1761 ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: " 1762 + "%s", lastState, next); 1763 next.setState(lastState, "resumeTopActivityInnerLocked"); 1764 1765 // lastResumedActivity being non-null implies there is a lastStack present. 1766 if (lastResumedActivity != null) { 1767 lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked"); 1768 } 1769 1770 Slog.i(TAG, "Restarting because process died: " + next); 1771 if (!next.hasBeenLaunched) { 1772 next.hasBeenLaunched = true; 1773 } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null 1774 && lastFocusedRootTask.isTopRootTaskInDisplayArea()) { 1775 next.showStartingWindow(false /* taskSwitch */); 1776 } 1777 mTaskSupervisor.startSpecificActivity(next, true, false); 1778 } 1779 shouldSleepOrShutDownActivities()1780 boolean shouldSleepOrShutDownActivities() { 1781 return shouldSleepActivities() || mAtmService.mShuttingDown; 1782 } 1783 1784 /** 1785 * Returns true if the TaskFragment should be visible. 1786 * 1787 * @param starting The currently starting activity or null if there is none. 1788 */ shouldBeVisible(ActivityRecord starting)1789 boolean shouldBeVisible(ActivityRecord starting) { 1790 return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE; 1791 } 1792 1793 /** 1794 * Returns {@code true} is the activity in this TaskFragment can be resumed. 1795 * 1796 * @param starting The currently starting activity or {@code null} if there is none. 1797 */ canBeResumed(@ullable ActivityRecord starting)1798 boolean canBeResumed(@Nullable ActivityRecord starting) { 1799 // No need to resume activity in TaskFragment that is not visible. 1800 return isTopActivityFocusable() 1801 && getVisibility(starting) == TASK_FRAGMENT_VISIBILITY_VISIBLE; 1802 } 1803 isFocusableAndVisible()1804 boolean isFocusableAndVisible() { 1805 return isTopActivityFocusable() && shouldBeVisible(null /* starting */); 1806 } 1807 startPausing(boolean uiSleeping, ActivityRecord resuming, String reason)1808 final boolean startPausing(boolean uiSleeping, ActivityRecord resuming, String reason) { 1809 return startPausing(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason); 1810 } 1811 1812 /** 1813 * Start pausing the currently resumed activity. It is an error to call this if there 1814 * is already an activity being paused or there is no resumed activity. 1815 * 1816 * @param userLeaving True if this should result in an onUserLeaving to the current activity. 1817 * @param uiSleeping True if this is happening with the user interface going to sleep (the 1818 * screen turning off). 1819 * @param resuming The activity we are currently trying to resume or null if this is not being 1820 * called as part of resuming the top activity, so we shouldn't try to instigate 1821 * a resume here if not null. 1822 * @param reason The reason of pausing the activity. 1823 * @return Returns true if an activity now is in the PAUSING state, and we are waiting for 1824 * it to tell us when it is done. 1825 */ startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, String reason)1826 boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, 1827 String reason) { 1828 if (!hasDirectChildActivities()) { 1829 return false; 1830 } 1831 if (mResumedActivity != null && !mResumedActivity.finishing 1832 && mTransitionController.isTransientLaunch(mResumedActivity)) { 1833 // Even if the transient activity is occluded, defer pausing (addToStopping will still 1834 // be called) it until the transient transition is done. So the current resuming 1835 // activity won't need to wait for additional pause complete. 1836 ProtoLog.d(WM_DEBUG_STATES, "startPausing: Skipping pause for transient " 1837 + "resumed activity=%s", mResumedActivity); 1838 return false; 1839 } 1840 1841 ProtoLog.d(WM_DEBUG_STATES, "startPausing: taskFrag=%s mResumedActivity=%s", this, 1842 mResumedActivity); 1843 1844 if (mPausingActivity != null) { 1845 Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity 1846 + " state=" + mPausingActivity.getState()); 1847 if (!shouldSleepActivities()) { 1848 // Avoid recursion among check for sleep and complete pause during sleeping. 1849 // Because activity will be paused immediately after resume, just let pause 1850 // be completed by the order of activity paused from clients. 1851 completePause(false, resuming); 1852 } 1853 } 1854 ActivityRecord prev = mResumedActivity; 1855 1856 if (prev == null) { 1857 if (resuming == null) { 1858 Slog.wtf(TAG, "Trying to pause when nothing is resumed"); 1859 mRootWindowContainer.resumeFocusedTasksTopActivities(); 1860 } 1861 return false; 1862 } 1863 1864 if (prev == resuming) { 1865 Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed"); 1866 return false; 1867 } 1868 1869 ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev); 1870 mPausingActivity = prev; 1871 mLastPausedActivity = prev; 1872 if (!prev.finishing && prev.isNoHistory() 1873 && !mTaskSupervisor.mNoHistoryActivities.contains(prev)) { 1874 mTaskSupervisor.mNoHistoryActivities.add(prev); 1875 } 1876 prev.setState(PAUSING, "startPausingLocked"); 1877 prev.getTask().touchActiveTime(); 1878 1879 mAtmService.updateCpuStats(); 1880 1881 boolean pauseImmediately = false; 1882 boolean shouldAutoPip = false; 1883 if (resuming != null) { 1884 // We do not want to trigger auto-PiP upon launch of a translucent activity. 1885 final boolean resumingOccludesParent = resuming.occludesParent(); 1886 1887 if (ActivityTaskManagerService.isPip2ExperimentEnabled()) { 1888 // If a new task is being launched, then mark the existing top activity as 1889 // supporting picture-in-picture while pausing only if the starting activity 1890 // would not be considered an overlay on top of the current activity 1891 // (eg. not fullscreen, or the assistant) 1892 Task.enableEnterPipOnTaskSwitch(prev, resuming.getTask(), 1893 resuming, resuming.getOptions()); 1894 } 1895 1896 // Resuming the new resume activity only if the previous activity can't go into Pip 1897 // since we want to give Pip activities a chance to enter Pip before resuming the 1898 // next activity. 1899 final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState( 1900 "shouldAutoPipWhilePausing", userLeaving); 1901 if (prev.supportsEnterPipOnTaskSwitch && userLeaving 1902 && resumingOccludesParent && lastResumedCanPip 1903 && prev.pictureInPictureArgs.isAutoEnterEnabled()) { 1904 shouldAutoPip = true; 1905 } else if (!lastResumedCanPip) { 1906 // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous 1907 // activity to be paused. 1908 pauseImmediately = (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0; 1909 } else { 1910 // The previous activity may still enter PIP even though it did not allow auto-PIP. 1911 } 1912 } 1913 1914 if (prev.attachedToProcess()) { 1915 if (shouldAutoPip && ActivityTaskManagerService.isPip2ExperimentEnabled()) { 1916 prev.mPauseSchedulePendingForPip = true; 1917 boolean willAutoPip = mAtmService.prepareAutoEnterPictureAndPictureMode(prev); 1918 ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, requesting PIP mode " 1919 + "via requestStartTransition(): %s, willAutoPip: %b", prev, willAutoPip); 1920 } else if (shouldAutoPip) { 1921 prev.mPauseSchedulePendingForPip = true; 1922 boolean didAutoPip = mAtmService.enterPictureInPictureMode( 1923 prev, prev.pictureInPictureArgs, false /* fromClient */); 1924 ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode " 1925 + "directly: %s, didAutoPip: %b", prev, didAutoPip); 1926 } else { 1927 schedulePauseActivity(prev, userLeaving, pauseImmediately, 1928 false /* autoEnteringPip */, reason); 1929 } 1930 } else { 1931 mPausingActivity = null; 1932 mLastPausedActivity = null; 1933 mTaskSupervisor.mNoHistoryActivities.remove(prev); 1934 } 1935 1936 // If we are not going to sleep, we want to ensure the device is 1937 // awake until the next activity is started. 1938 if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) { 1939 mTaskSupervisor.acquireLaunchWakelock(); 1940 } 1941 1942 // If already entered PIP mode, no need to keep pausing. 1943 if (mPausingActivity != null) { 1944 // Have the window manager pause its key dispatching until the new 1945 // activity has started. If we're pausing the activity just because 1946 // the screen is being turned off and the UI is sleeping, don't interrupt 1947 // key dispatch; the same activity will pick it up again on wakeup. 1948 if (!uiSleeping) { 1949 prev.pauseKeyDispatchingLocked(); 1950 } else { 1951 ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off"); 1952 } 1953 1954 if (pauseImmediately) { 1955 // If the caller said they don't want to wait for the pause, then complete 1956 // the pause now. 1957 completePause(false, resuming); 1958 return false; 1959 1960 } else { 1961 prev.schedulePauseTimeout(); 1962 // All activities will be stopped when sleeping, don't need to wait for pause. 1963 if (!uiSleeping) { 1964 // Unset readiness since we now need to wait until this pause is complete. 1965 mTransitionController.setReady(this, false /* ready */); 1966 } 1967 return true; 1968 } 1969 1970 } else { 1971 // This activity either failed to schedule the pause or it entered PIP mode, 1972 // so just treat it as being paused now. 1973 ProtoLog.v(WM_DEBUG_STATES, "Activity not running or entered PiP, resuming next."); 1974 if (resuming == null) { 1975 mRootWindowContainer.resumeFocusedTasksTopActivities(); 1976 } 1977 return false; 1978 } 1979 } 1980 schedulePauseActivity(ActivityRecord prev, boolean userLeaving, boolean pauseImmediately, boolean autoEnteringPip, String reason)1981 void schedulePauseActivity(ActivityRecord prev, boolean userLeaving, 1982 boolean pauseImmediately, boolean autoEnteringPip, String reason) { 1983 ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev); 1984 prev.mPauseSchedulePendingForPip = false; 1985 EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), 1986 prev.shortComponentName, "userLeaving=" + userLeaving, reason); 1987 1988 final PauseActivityItem item = new PauseActivityItem(prev.token, prev.finishing, 1989 userLeaving, pauseImmediately, autoEnteringPip); 1990 boolean isSuccessful; 1991 try { 1992 isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem( 1993 prev.app.getThread(), item); 1994 } catch (RemoteException e) { 1995 // TODO(b/323801078): remove Exception when cleanup 1996 // Ignore exception, if process died other code will cleanup. 1997 Slog.w(TAG, "Exception thrown during pause", e); 1998 isSuccessful = false; 1999 } 2000 if (!isSuccessful) { 2001 mPausingActivity = null; 2002 mLastPausedActivity = null; 2003 mTaskSupervisor.mNoHistoryActivities.remove(prev); 2004 } 2005 } 2006 2007 @VisibleForTesting completePause(boolean resumeNext, ActivityRecord resuming)2008 void completePause(boolean resumeNext, ActivityRecord resuming) { 2009 // Complete the pausing process of a pausing activity, so it doesn't make sense to 2010 // operate on non-leaf tasks. 2011 // warnForNonLeafTask("completePauseLocked"); 2012 2013 ActivityRecord prev = mPausingActivity; 2014 ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev); 2015 2016 if (prev != null) { 2017 prev.setWillCloseOrEnterPip(false); 2018 prev.supportsEnterPipOnTaskSwitch = false; 2019 final boolean wasStopping = prev.isState(STOPPING); 2020 prev.setState(PAUSED, "completePausedLocked"); 2021 mPausingActivity = null; 2022 if (prev.finishing) { 2023 // We will update the activity visibility later, no need to do in 2024 // completeFinishing(). Updating visibility here might also making the next 2025 // activities to be resumed, and could result in wrong app transition due to 2026 // lack of previous activity information. 2027 ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev); 2028 prev = prev.completeFinishing(false /* updateVisibility */, 2029 "completePausedLocked"); 2030 } else if (prev.attachedToProcess()) { 2031 ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s " 2032 + "wasStopping=%b visibleRequested=%b", prev, wasStopping, 2033 prev.isVisibleRequested()); 2034 if (wasStopping) { 2035 // We are also stopping, the stop request must have gone soon after the pause. 2036 // We can't clobber it, because the stop confirmation will not be handled. 2037 // We don't need to schedule another stop, we only need to let it happen. 2038 prev.setState(STOPPING, "completePausedLocked"); 2039 } else if (!prev.isVisibleRequested() || shouldSleepOrShutDownActivities()) { 2040 // Clear out any deferred client hide we might currently have. 2041 prev.clearDeferHidingClient(); 2042 // If we were visible then resumeTopActivities will release resources before 2043 // stopping. 2044 prev.addToStopping(true /* scheduleIdle */, false /* idleDelayed */, 2045 "completePauseLocked"); 2046 } 2047 } else { 2048 ProtoLog.v(WM_DEBUG_STATES, "App died during pause, not stopping: %s", prev); 2049 prev = null; 2050 } 2051 } 2052 2053 if (resumeNext) { 2054 final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); 2055 if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) { 2056 mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev); 2057 } else { 2058 // checkReadyForSleep(); 2059 final ActivityRecord top = 2060 topRootTask != null ? topRootTask.topRunningActivity() : null; 2061 if (top == null || (prev != null && top != prev)) { 2062 // If there are no more activities available to run, do resume anyway to start 2063 // something. Also if the top activity on the root task is not the just paused 2064 // activity, we need to go ahead and resume it to ensure we complete an 2065 // in-flight app switch. 2066 mRootWindowContainer.resumeFocusedTasksTopActivities(); 2067 } 2068 } 2069 } 2070 2071 if (prev != null) { 2072 prev.resumeKeyDispatchingLocked(); 2073 } 2074 2075 mRootWindowContainer.ensureActivitiesVisible(resuming); 2076 2077 // Notify when the task stack has changed, but only if visibilities changed (not just 2078 // focus). Also if there is an active root pinned task - we always want to notify it about 2079 // task stack changes, because its positioning may depend on it. 2080 if (mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause 2081 || (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) { 2082 mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged(); 2083 mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = false; 2084 } 2085 } 2086 2087 @ActivityInfo.ScreenOrientation 2088 @Override getOrientation(@ctivityInfo.ScreenOrientation int candidate)2089 int getOrientation(@ActivityInfo.ScreenOrientation int candidate) { 2090 if (shouldReportOrientationUnspecified()) { 2091 return SCREEN_ORIENTATION_UNSPECIFIED; 2092 } 2093 if (canSpecifyOrientation()) { 2094 return super.getOrientation(candidate); 2095 } 2096 return SCREEN_ORIENTATION_UNSET; 2097 } 2098 2099 @ActivityInfo.ScreenOrientation 2100 @Override getOverrideOrientation()2101 protected int getOverrideOrientation() { 2102 if (isEmbedded() && !isVisibleRequested()) { 2103 return SCREEN_ORIENTATION_UNSPECIFIED; 2104 } 2105 return super.getOverrideOrientation(); 2106 } 2107 2108 /** 2109 * Whether or not to allow this container to specify an app requested orientation. 2110 * 2111 * This is different from {@link #providesOrientation()} that 2112 * 1. The container may still provide an orientation even if it can't specify the app requested 2113 * one, such as {@link #shouldReportOrientationUnspecified()} 2114 * 2. Even if the container can specify an app requested orientation, it may not be used by the 2115 * parent container if it is {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}. 2116 */ canSpecifyOrientation()2117 boolean canSpecifyOrientation() { 2118 final int windowingMode = getWindowingMode(); 2119 final int activityType = getActivityType(); 2120 return windowingMode == WINDOWING_MODE_FULLSCREEN 2121 || activityType == ACTIVITY_TYPE_HOME 2122 || activityType == ACTIVITY_TYPE_RECENTS 2123 || activityType == ACTIVITY_TYPE_ASSISTANT; 2124 } 2125 2126 /** 2127 * Whether or not the parent container should use the orientation provided by this container 2128 * even if it is {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}. 2129 */ 2130 @Override providesOrientation()2131 boolean providesOrientation() { 2132 return super.providesOrientation() || shouldReportOrientationUnspecified(); 2133 } 2134 shouldReportOrientationUnspecified()2135 private boolean shouldReportOrientationUnspecified() { 2136 // Apps and their containers are not allowed to specify orientation from adjacent 2137 // TaskFragment. 2138 return hasAdjacentTaskFragment() && isVisibleRequested(); 2139 } 2140 2141 @Override forAllTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom)2142 void forAllTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom) { 2143 super.forAllTaskFragments(callback, traverseTopToBottom); 2144 callback.accept(this); 2145 } 2146 2147 @Override forAllLeafTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom)2148 void forAllLeafTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom) { 2149 final int count = mChildren.size(); 2150 boolean isLeafTaskFrag = true; 2151 if (traverseTopToBottom) { 2152 for (int i = count - 1; i >= 0; --i) { 2153 final TaskFragment child = mChildren.get(i).asTaskFragment(); 2154 if (child != null) { 2155 isLeafTaskFrag = false; 2156 child.forAllLeafTaskFragments(callback, traverseTopToBottom); 2157 } 2158 } 2159 } else { 2160 for (int i = 0; i < count; i++) { 2161 final TaskFragment child = mChildren.get(i).asTaskFragment(); 2162 if (child != null) { 2163 isLeafTaskFrag = false; 2164 child.forAllLeafTaskFragments(callback, traverseTopToBottom); 2165 } 2166 } 2167 } 2168 if (isLeafTaskFrag) callback.accept(this); 2169 } 2170 2171 @Override forAllLeafTaskFragments(Predicate<TaskFragment> callback)2172 boolean forAllLeafTaskFragments(Predicate<TaskFragment> callback) { 2173 boolean isLeafTaskFrag = true; 2174 for (int i = mChildren.size() - 1; i >= 0; --i) { 2175 final TaskFragment child = mChildren.get(i).asTaskFragment(); 2176 if (child != null) { 2177 isLeafTaskFrag = false; 2178 if (child.forAllLeafTaskFragments(callback)) { 2179 return true; 2180 } 2181 } 2182 } 2183 if (isLeafTaskFrag) { 2184 return callback.test(this); 2185 } 2186 return false; 2187 } 2188 addChild(ActivityRecord r)2189 void addChild(ActivityRecord r) { 2190 addChild(r, POSITION_TOP); 2191 } 2192 2193 @Override addChild(WindowContainer child, int index)2194 void addChild(WindowContainer child, int index) { 2195 ActivityRecord r = topRunningActivity(); 2196 mClearedTaskForReuse = false; 2197 mClearedTaskFragmentForPip = false; 2198 mClearedForReorderActivityToFront = false; 2199 2200 final ActivityRecord addingActivity = child.asActivityRecord(); 2201 final boolean isAddingActivity = addingActivity != null; 2202 final Task task = isAddingActivity ? getTask() : null; 2203 2204 // If this task had any activity before we added this one. 2205 boolean taskHadActivity = task != null && task.getTopMostActivity() != null; 2206 // getActivityType() looks at the top child, so we need to read the type before adding 2207 // a new child in case the new child is on top and UNDEFINED. 2208 final int activityType = task != null ? task.getActivityType() : ACTIVITY_TYPE_UNDEFINED; 2209 2210 super.addChild(child, index); 2211 2212 if (isAddingActivity && task != null) { 2213 addingActivity.inHistory = true; 2214 task.onDescendantActivityAdded(taskHadActivity, activityType, addingActivity); 2215 } 2216 2217 final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(addingActivity); 2218 if (hostProcess != null) { 2219 hostProcess.addEmbeddedActivity(addingActivity); 2220 } 2221 } 2222 2223 @Override onChildPositionChanged(WindowContainer child)2224 void onChildPositionChanged(WindowContainer child) { 2225 super.onChildPositionChanged(child); 2226 2227 sendTaskFragmentInfoChanged(); 2228 } 2229 executeAppTransition(ActivityOptions options)2230 void executeAppTransition(ActivityOptions options) { 2231 mDisplayContent.executeAppTransition(); 2232 ActivityOptions.abort(options); 2233 } 2234 2235 @Override canCreateRemoteAnimationTarget()2236 boolean canCreateRemoteAnimationTarget() { 2237 return true; 2238 } 2239 shouldSleepActivities()2240 boolean shouldSleepActivities() { 2241 final DisplayContent dc = mDisplayContent; 2242 if (dc == null) { 2243 return mAtmService.isSleepingLocked(); 2244 } 2245 if (!dc.isSleeping()) { 2246 return false; 2247 } 2248 // In case the unlocking order is keyguard-going-away -> screen-turning-on (display is 2249 // sleeping by screen-off-token which may be notified to release from power manager's 2250 // thread), keep the activities resume-able to avoid extra activity lifecycle when 2251 // performing keyguard-going-away. This only applies to default display because currently 2252 // the per-display keyguard-going-away state is assigned from a global signal. 2253 if (!dc.isDefaultDisplay || !dc.isKeyguardGoingAway()) { 2254 return true; 2255 } 2256 return !shouldBeVisible(null /* starting */); 2257 } 2258 2259 @Override resolveOverrideConfiguration(Configuration newParentConfig)2260 void resolveOverrideConfiguration(Configuration newParentConfig) { 2261 mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); 2262 super.resolveOverrideConfiguration(newParentConfig); 2263 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 2264 2265 if (mRelativeEmbeddedBounds != null && !mRelativeEmbeddedBounds.isEmpty()) { 2266 // For embedded TaskFragment, make sure the bounds is set based on the relative bounds. 2267 resolvedConfig.windowConfiguration.setBounds(translateRelativeBoundsToAbsoluteBounds( 2268 mRelativeEmbeddedBounds, newParentConfig.windowConfiguration.getBounds())); 2269 } 2270 int windowingMode = resolvedConfig.windowConfiguration.getWindowingMode(); 2271 final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode(); 2272 2273 // Resolve override windowing mode to fullscreen for home task (even on freeform 2274 // display), or split-screen if in split-screen mode. 2275 if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) { 2276 windowingMode = WINDOWING_MODE_FULLSCREEN; 2277 resolvedConfig.windowConfiguration.setWindowingMode(windowingMode); 2278 } 2279 2280 // Do not allow tasks not support multi window to be in a multi-window mode, unless it is in 2281 // pinned windowing mode. 2282 if (!supportsMultiWindow()) { 2283 final int candidateWindowingMode = 2284 windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode; 2285 if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode) 2286 && candidateWindowingMode != WINDOWING_MODE_PINNED) { 2287 resolvedConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 2288 } 2289 } 2290 2291 final Task thisTask = asTask(); 2292 if (thisTask != null) { 2293 thisTask.resolveLeafTaskOnlyOverrideConfigs(newParentConfig, 2294 mTmpBounds /* previousBounds */); 2295 } 2296 computeConfigResourceOverrides(resolvedConfig, newParentConfig); 2297 } 2298 supportsMultiWindow()2299 boolean supportsMultiWindow() { 2300 return supportsMultiWindowInDisplayArea(getDisplayArea()); 2301 } 2302 2303 /** 2304 * @return whether this task supports multi-window if it is in the given 2305 * {@link TaskDisplayArea}. 2306 */ supportsMultiWindowInDisplayArea(@ullable TaskDisplayArea tda)2307 boolean supportsMultiWindowInDisplayArea(@Nullable TaskDisplayArea tda) { 2308 if (!mAtmService.mSupportsMultiWindow) { 2309 return false; 2310 } 2311 if (tda == null) { 2312 return false; 2313 } 2314 final Task task = getTask(); 2315 if (task == null) { 2316 return false; 2317 } 2318 if (!task.isResizeable() && !tda.supportsNonResizableMultiWindow()) { 2319 // Not support non-resizable in multi window. 2320 return false; 2321 } 2322 2323 final ActivityRecord rootActivity = task.getRootActivity(); 2324 return tda.supportsActivityMinWidthHeightMultiWindow(mMinWidth, mMinHeight, 2325 rootActivity != null ? rootActivity.info : null); 2326 } 2327 getTaskId()2328 private int getTaskId() { 2329 return getTask() != null ? getTask().mTaskId : INVALID_TASK_ID; 2330 } 2331 2332 static class ConfigOverrideHint { 2333 @Nullable DisplayInfo mTmpOverrideDisplayInfo; 2334 @Nullable AppCompatDisplayInsets mTmpCompatInsets; 2335 @Nullable Rect mParentAppBoundsOverride; 2336 @Nullable Rect mParentBoundsOverride; 2337 int mTmpOverrideConfigOrientation; 2338 boolean mUseOverrideInsetsForConfig; 2339 resolveTmpOverrides(DisplayContent dc, Configuration parentConfig, boolean isFixedRotationTransforming, @Nullable Rect safeRegionBounds)2340 void resolveTmpOverrides(DisplayContent dc, Configuration parentConfig, 2341 boolean isFixedRotationTransforming, @Nullable Rect safeRegionBounds) { 2342 mParentAppBoundsOverride = safeRegionBounds != null ? safeRegionBounds : new Rect( 2343 parentConfig.windowConfiguration.getAppBounds()); 2344 mParentBoundsOverride = safeRegionBounds != null ? safeRegionBounds : new Rect( 2345 parentConfig.windowConfiguration.getBounds()); 2346 mTmpOverrideConfigOrientation = parentConfig.orientation; 2347 Insets insets = Insets.NONE; 2348 if (safeRegionBounds != null) { 2349 // Modify orientation based on the parent app bounds if safe region bounds are set. 2350 mTmpOverrideConfigOrientation = 2351 mParentAppBoundsOverride.height() >= mParentAppBoundsOverride.width() 2352 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; 2353 } else if (mUseOverrideInsetsForConfig && dc != null 2354 && !isFloating(parentConfig.windowConfiguration.getWindowingMode())) { 2355 // Insets are decoupled from configuration by default from V+, use legacy 2356 // compatibility behaviour for apps targeting SDK earlier than 35 2357 // (see applySizeOverrideIfNeeded). 2358 int rotation = parentConfig.windowConfiguration.getRotation(); 2359 if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming) { 2360 rotation = dc.getRotation(); 2361 } 2362 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); 2363 final int dw = rotated ? dc.mBaseDisplayHeight : dc.mBaseDisplayWidth; 2364 final int dh = rotated ? dc.mBaseDisplayWidth : dc.mBaseDisplayHeight; 2365 DisplayPolicy.DecorInsets.Info decorInsets = dc.getDisplayPolicy() 2366 .getDecorInsetsInfo(rotation, dw, dh); 2367 final Rect stableBounds = decorInsets.mOverrideConfigFrame; 2368 mTmpOverrideConfigOrientation = stableBounds.width() > stableBounds.height() 2369 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT; 2370 insets = Insets.of(decorInsets.mOverrideNonDecorInsets); 2371 } 2372 mParentAppBoundsOverride.inset(insets); 2373 } 2374 resetTmpOverrides()2375 void resetTmpOverrides() { 2376 mTmpOverrideDisplayInfo = null; 2377 mTmpCompatInsets = null; 2378 mTmpOverrideConfigOrientation = ORIENTATION_UNDEFINED; 2379 } 2380 } 2381 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig)2382 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2383 @NonNull Configuration parentConfig) { 2384 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* configOverrideHint */); 2385 } 2386 2387 /** 2388 * Forces the app bounds related configuration can be computed by 2389 * {@link #computeConfigResourceOverrides(Configuration, Configuration, ConfigOverrideHint)}. 2390 */ invalidateAppBoundsConfig(@onNull Configuration inOutConfig)2391 private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) { 2392 final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds(); 2393 if (appBounds != null) { 2394 appBounds.setEmpty(); 2395 } 2396 inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED; 2397 inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED; 2398 } 2399 2400 /** 2401 * Calculates configuration values used by the client to get resources. This should be run 2402 * using app-facing bounds (bounds unmodified by animations or transient interactions). 2403 * 2404 * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely 2405 * configuring an "inherit-bounds" window which means that all configuration settings would 2406 * just be inherited from the parent configuration. 2407 **/ computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable ConfigOverrideHint overrideHint)2408 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2409 @NonNull Configuration parentConfig, @Nullable ConfigOverrideHint overrideHint) { 2410 DisplayInfo overrideDisplayInfo = null; 2411 AppCompatDisplayInsets compatInsets = null; 2412 boolean useOverrideInsetsForConfig = false; 2413 if (overrideHint != null) { 2414 overrideDisplayInfo = overrideHint.mTmpOverrideDisplayInfo; 2415 compatInsets = overrideHint.mTmpCompatInsets; 2416 useOverrideInsetsForConfig = overrideHint.mUseOverrideInsetsForConfig; 2417 if (overrideDisplayInfo != null) { 2418 // Make sure the screen related configs can be computed by the provided 2419 // display info. 2420 inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED; 2421 } 2422 if (overrideDisplayInfo != null || compatInsets != null) { 2423 // Make sure the app bounds can be computed by the compat insets. 2424 invalidateAppBoundsConfig(inOutConfig); 2425 } 2426 } 2427 int windowingMode = inOutConfig.windowConfiguration.getWindowingMode(); 2428 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 2429 windowingMode = parentConfig.windowConfiguration.getWindowingMode(); 2430 } 2431 2432 float density = inOutConfig.densityDpi; 2433 if (density == Configuration.DENSITY_DPI_UNDEFINED) { 2434 density = parentConfig.densityDpi; 2435 } 2436 density *= DisplayMetrics.DENSITY_DEFAULT_SCALE; 2437 2438 // The bounds may have been overridden at this level. If the parent cannot cover these 2439 // bounds, the configuration is still computed according to the override bounds. 2440 final boolean insideParentBounds; 2441 2442 final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); 2443 final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds(); 2444 if (resolvedBounds.isEmpty()) { 2445 mTmpFullBounds.set(parentBounds); 2446 insideParentBounds = true; 2447 } else { 2448 mTmpFullBounds.set(resolvedBounds); 2449 insideParentBounds = parentBounds.contains(resolvedBounds); 2450 } 2451 2452 // Non-null compatibility insets means the activity prefers to keep its original size, so 2453 // out bounds doesn't need to be restricted by the parent or current display 2454 final boolean customContainerPolicy = compatInsets != null; 2455 2456 Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); 2457 if (outAppBounds == null || outAppBounds.isEmpty()) { 2458 // App-bounds hasn't been overridden, so calculate a value for it. 2459 inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds); 2460 outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); 2461 2462 // Floating tasks shouldn't be restricted by containing app bounds. 2463 if (!customContainerPolicy && !isFloating(windowingMode)) { 2464 final Rect containingAppBounds; 2465 if (insideParentBounds) { 2466 containingAppBounds = useOverrideInsetsForConfig 2467 ? overrideHint.mParentAppBoundsOverride 2468 : parentConfig.windowConfiguration.getAppBounds(); 2469 } else { 2470 // Restrict appBounds to display non-decor rather than parent because the 2471 // override bounds are beyond the parent. Otherwise, it won't match the 2472 // overridden bounds. 2473 final TaskDisplayArea displayArea = getDisplayArea(); 2474 containingAppBounds = displayArea != null 2475 ? displayArea.getWindowConfiguration().getAppBounds() : null; 2476 } 2477 if (containingAppBounds != null && !containingAppBounds.isEmpty()) { 2478 outAppBounds.intersect(containingAppBounds); 2479 } 2480 } 2481 } 2482 2483 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED 2484 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2485 if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) { 2486 mTmpNonDecorBounds.set(mTmpFullBounds); 2487 mTmpStableBounds.set(mTmpFullBounds); 2488 } else if (!customContainerPolicy 2489 && (overrideDisplayInfo != null || getDisplayContent() != null)) { 2490 final DisplayInfo di = overrideDisplayInfo != null 2491 ? overrideDisplayInfo 2492 : getDisplayContent().getDisplayInfo(); 2493 2494 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen 2495 // area, i.e. the screen area without the system bars. 2496 // The non decor inset are areas that could never be removed in Honeycomb. See 2497 // {@link WindowManagerPolicy#getNonDecorInsetsLw}. 2498 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di, 2499 useOverrideInsetsForConfig); 2500 } else { 2501 // Apply the given non-decor and stable insets to calculate the corresponding bounds 2502 // for screen size of configuration. 2503 int rotation = inOutConfig.windowConfiguration.getRotation(); 2504 if (rotation == ROTATION_UNDEFINED) { 2505 rotation = parentConfig.windowConfiguration.getRotation(); 2506 } 2507 if (rotation != ROTATION_UNDEFINED && customContainerPolicy) { 2508 mTmpNonDecorBounds.set(mTmpFullBounds); 2509 mTmpStableBounds.set(mTmpFullBounds); 2510 compatInsets.getBoundsByRotation(mTmpBounds, rotation); 2511 intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds, 2512 compatInsets.mNonDecorInsets[rotation]); 2513 intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds, 2514 compatInsets.mStableInsets[rotation]); 2515 outAppBounds.set(mTmpNonDecorBounds); 2516 } else { 2517 // Set to app bounds because it excludes decor insets. 2518 mTmpNonDecorBounds.set(outAppBounds); 2519 mTmpStableBounds.set(outAppBounds); 2520 } 2521 } 2522 2523 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) { 2524 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density + 0.5f); 2525 inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy) 2526 ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp) 2527 : overrideScreenWidthDp; 2528 } 2529 if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2530 final int overrideScreenHeightDp = 2531 (int) (mTmpStableBounds.height() / density + 0.5f); 2532 inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy) 2533 ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp) 2534 : overrideScreenHeightDp; 2535 } 2536 2537 // TODO(b/238331848): Consider simplifying logic that computes smallestScreenWidthDp. 2538 if (inOutConfig.smallestScreenWidthDp 2539 == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 2540 // When entering to or exiting from Pip, the PipTaskOrganizer will set the 2541 // windowing mode of the activity in the task to WINDOWING_MODE_FULLSCREEN and 2542 // temporarily set the bounds of the task to fullscreen size for transitioning. 2543 // It will get the wrong value if the calculation is based on this temporary 2544 // fullscreen bounds. 2545 // We should just inherit the value from parent for this temporary state. 2546 final boolean inPipTransition = windowingMode == WINDOWING_MODE_PINNED 2547 && !mTmpFullBounds.isEmpty() && mTmpFullBounds.equals(parentBounds); 2548 if (WindowConfiguration.isFloating(windowingMode) && !inPipTransition) { 2549 // For floating tasks, calculate the smallest width from the bounds of the 2550 // task, because they should not be affected by insets. 2551 inOutConfig.smallestScreenWidthDp = (int) (0.5f 2552 + Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density); 2553 } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW && mIsEmbedded 2554 && !resolvedBounds.equals(parentBounds)) { 2555 // For embedded TFs, the smallest width should be updated. Otherwise, inherit 2556 // from the parent task would result in applications loaded wrong resource. 2557 inOutConfig.smallestScreenWidthDp = 2558 Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp); 2559 } 2560 // otherwise, it will just inherit 2561 } 2562 } 2563 2564 if (inOutConfig.orientation == ORIENTATION_UNDEFINED) { 2565 inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp) 2566 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; 2567 } 2568 if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) { 2569 // For calculating screen layout, we need to use the non-decor inset screen area for the 2570 // calculation for compatibility reasons, i.e. screen area without system bars that 2571 // could never go away in Honeycomb. 2572 int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density + 0.5f); 2573 int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density + 0.5f); 2574 // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is 2575 // undefined so it can't be used. 2576 if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) { 2577 compatScreenWidthDp = inOutConfig.screenWidthDp; 2578 } 2579 if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2580 compatScreenHeightDp = inOutConfig.screenHeightDp; 2581 } 2582 // Reducing the screen layout starting from its parent config. 2583 inOutConfig.screenLayout = computeScreenLayout(parentConfig.screenLayout, 2584 compatScreenWidthDp, compatScreenHeightDp); 2585 } 2586 } 2587 2588 /** 2589 * Gets bounds with non-decor and stable insets applied respectively. 2590 * 2591 * If bounds overhangs the display, those edges will not get insets. See 2592 * {@link #intersectWithInsetsIfFits} 2593 * 2594 * @param outNonDecorBounds where to place bounds with non-decor insets applied. 2595 * @param outStableBounds where to place bounds with stable insets applied. 2596 * @param bounds the bounds to inset. 2597 * @param useLegacyInsetsForStableBounds {@code true} if we need to use the legacy insets frame 2598 * for apps targeting U or before when calculating stable bounds. 2599 */ calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, DisplayInfo displayInfo, boolean useLegacyInsetsForStableBounds)2600 void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, 2601 DisplayInfo displayInfo, boolean useLegacyInsetsForStableBounds) { 2602 outNonDecorBounds.set(bounds); 2603 outStableBounds.set(bounds); 2604 if (mDisplayContent == null) { 2605 return; 2606 } 2607 mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); 2608 2609 final DisplayPolicy policy = mDisplayContent.getDisplayPolicy(); 2610 final DisplayPolicy.DecorInsets.Info info = policy.getDecorInsetsInfo( 2611 displayInfo.rotation, displayInfo.logicalWidth, displayInfo.logicalHeight); 2612 if (!useLegacyInsetsForStableBounds) { 2613 intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mConfigInsets); 2614 intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, info.mNonDecorInsets); 2615 } else { 2616 intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mOverrideConfigInsets); 2617 intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, info.mOverrideNonDecorInsets); 2618 } 2619 } 2620 2621 /** 2622 * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than 2623 * intersectBounds on a side, then the respective side will not be intersected. 2624 * 2625 * The assumption is that if inOutBounds is initially larger than intersectBounds, then the 2626 * inset on that side is no-longer applicable. This scenario happens when a task's minimal 2627 * bounds are larger than the provided parent/display bounds. 2628 * 2629 * @param inOutBounds the bounds to intersect. 2630 * @param intersectBounds the bounds to intersect with. 2631 * @param intersectInsets insets to apply to intersectBounds before intersecting. 2632 */ intersectWithInsetsIfFits( Rect inOutBounds, Rect intersectBounds, Rect intersectInsets)2633 static void intersectWithInsetsIfFits( 2634 Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) { 2635 if (inOutBounds.right <= intersectBounds.right) { 2636 inOutBounds.right = 2637 Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right); 2638 } 2639 if (inOutBounds.bottom <= intersectBounds.bottom) { 2640 inOutBounds.bottom = 2641 Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom); 2642 } 2643 if (inOutBounds.left >= intersectBounds.left) { 2644 inOutBounds.left = 2645 Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left); 2646 } 2647 if (inOutBounds.top >= intersectBounds.top) { 2648 inOutBounds.top = 2649 Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top); 2650 } 2651 } 2652 2653 @Override getActivityType()2654 public int getActivityType() { 2655 final int applicationType = super.getActivityType(); 2656 if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) { 2657 return applicationType; 2658 } 2659 final ActivityRecord activity = getTopMostActivity(); 2660 return activity != null ? activity.getActivityType() : getTopChild().getActivityType(); 2661 } 2662 2663 @Override onConfigurationChanged(Configuration newParentConfig)2664 public void onConfigurationChanged(Configuration newParentConfig) { 2665 super.onConfigurationChanged(newParentConfig); 2666 updateOrganizedTaskFragmentSurface(); 2667 sendTaskFragmentInfoChanged(); 2668 } 2669 deferOrganizedTaskFragmentSurfaceUpdate()2670 void deferOrganizedTaskFragmentSurfaceUpdate() { 2671 mDelayOrganizedTaskFragmentSurfaceUpdate = true; 2672 } 2673 continueOrganizedTaskFragmentSurfaceUpdate()2674 void continueOrganizedTaskFragmentSurfaceUpdate() { 2675 mDelayOrganizedTaskFragmentSurfaceUpdate = false; 2676 updateOrganizedTaskFragmentSurface(); 2677 } 2678 2679 /** 2680 * TaskFragmentOrganizer doesn't have access to the surface for security reasons, so we need to 2681 * update its surface on the server side if it is not collected for Shell or in pending 2682 * animation. 2683 */ updateOrganizedTaskFragmentSurface()2684 void updateOrganizedTaskFragmentSurface() { 2685 if (mDelayOrganizedTaskFragmentSurfaceUpdate || mTaskFragmentOrganizer == null) { 2686 return; 2687 } 2688 if (mTransitionController.isShellTransitionsEnabled() 2689 && !mTransitionController.isCollecting(this)) { 2690 // TaskFragmentOrganizer doesn't have access to the surface for security reasons, so 2691 // update the surface here if it is not collected by Shell transition. 2692 updateOrganizedTaskFragmentSurfaceUnchecked(); 2693 } else if (!mTransitionController.isShellTransitionsEnabled() && !isAnimating()) { 2694 // Update the surface here instead of in the organizer so that we can make sure 2695 // it can be synced with the surface freezer for legacy app transition. 2696 updateOrganizedTaskFragmentSurfaceUnchecked(); 2697 } 2698 } 2699 updateOrganizedTaskFragmentSurfaceUnchecked()2700 private void updateOrganizedTaskFragmentSurfaceUnchecked() { 2701 final SurfaceControl.Transaction t = getSyncTransaction(); 2702 updateSurfacePosition(t); 2703 updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */); 2704 } 2705 2706 /** Updates the surface size so that the sub windows cannot be shown out of bounds. */ updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t, boolean forceUpdate)2707 private void updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t, 2708 boolean forceUpdate) { 2709 if (mTaskFragmentOrganizer == null) { 2710 // We only want to update for organized TaskFragment. Task will handle itself. 2711 return; 2712 } 2713 if (mSurfaceControl == null || mSurfaceAnimator.hasLeash()) { 2714 return; 2715 } 2716 2717 // If this TaskFragment is closing while resizing, crop to the starting bounds instead. 2718 final Rect bounds = getBounds(); 2719 final int width = bounds.width(); 2720 final int height = bounds.height(); 2721 if (!forceUpdate && width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) { 2722 return; 2723 } 2724 if (fillsParent()) { 2725 // Rely on parent's crop. 2726 t.setCrop(mSurfaceControl, null); 2727 } else { 2728 t.setWindowCrop(mSurfaceControl, width, height); 2729 } 2730 mLastSurfaceSize.set(width, height); 2731 } 2732 2733 @Override onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash)2734 public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) { 2735 super.onAnimationLeashCreated(t, leash); 2736 // Reset surface bounds for animation. It will be taken care by the animation leash, and 2737 // reset again onAnimationLeashLost. 2738 if (mTaskFragmentOrganizer != null 2739 && (mLastSurfaceSize.x != 0 || mLastSurfaceSize.y != 0)) { 2740 t.setWindowCrop(mSurfaceControl, 0, 0); 2741 final SurfaceControl.Transaction syncTransaction = getSyncTransaction(); 2742 if (t != syncTransaction) { 2743 // Avoid restoring to old window crop if the sync transaction is applied later. 2744 syncTransaction.setWindowCrop(mSurfaceControl, 0, 0); 2745 } 2746 mLastSurfaceSize.set(0, 0); 2747 } 2748 } 2749 2750 @Override onAnimationLeashLost(SurfaceControl.Transaction t)2751 public void onAnimationLeashLost(SurfaceControl.Transaction t) { 2752 super.onAnimationLeashLost(t); 2753 // Update the surface bounds after animation. 2754 if (mTaskFragmentOrganizer != null) { 2755 updateOrganizedTaskFragmentSurfaceSize(t, true /* forceUpdate */); 2756 } 2757 } 2758 2759 /** 2760 * Gets the relative bounds of this embedded TaskFragment. This should only be called on 2761 * embedded TaskFragment. 2762 */ 2763 @NonNull getRelativeEmbeddedBounds()2764 Rect getRelativeEmbeddedBounds() { 2765 if (mRelativeEmbeddedBounds == null) { 2766 throw new IllegalStateException("The TaskFragment is not embedded"); 2767 } 2768 return mRelativeEmbeddedBounds; 2769 } 2770 2771 /** 2772 * Translates the given relative bounds to screen space based on the given parent bounds. 2773 * When the relative bounds is outside of the parent bounds, it will be adjusted to fit the Task 2774 * bounds. 2775 */ translateRelativeBoundsToAbsoluteBounds(@onNull Rect relativeBounds, @NonNull Rect parentBounds)2776 Rect translateRelativeBoundsToAbsoluteBounds(@NonNull Rect relativeBounds, 2777 @NonNull Rect parentBounds) { 2778 if (relativeBounds.isEmpty()) { 2779 mTmpAbsBounds.setEmpty(); 2780 return mTmpAbsBounds; 2781 } 2782 // Translate the relative bounds to absolute bounds. 2783 mTmpAbsBounds.set(relativeBounds); 2784 mTmpAbsBounds.offset(parentBounds.left, parentBounds.top); 2785 2786 if (!isAllowedToBeEmbeddedInTrustedMode() && !parentBounds.contains(mTmpAbsBounds)) { 2787 // For untrusted embedding, we want to make sure the embedded bounds will never go 2788 // outside of the Task bounds. 2789 // We expect the organizer to update the bounds after receiving the Task bounds changed, 2790 // so skip trusted embedding to avoid unnecessary configuration change before organizer 2791 // requests a new bounds. 2792 // When the requested TaskFragment bounds is outside of Task bounds, try use the 2793 // intersection. 2794 // This can happen when the Task resized before the TaskFragmentOrganizer request. 2795 if (!mTmpAbsBounds.intersect(parentBounds)) { 2796 // Use empty bounds to fill Task if there is no intersection. 2797 mTmpAbsBounds.setEmpty(); 2798 } 2799 } 2800 return mTmpAbsBounds; 2801 } 2802 recomputeConfiguration()2803 void recomputeConfiguration() { 2804 onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration()); 2805 } 2806 2807 /** 2808 * Sets the relative bounds in parent coordinate for this embedded TaskFragment. 2809 * This will not override the requested bounds, and the actual bounds will be calculated in 2810 * {@link #resolveOverrideConfiguration}, so that it makes sure to record and use the relative 2811 * bounds that is set by the organizer until the organizer requests a new relative bounds. 2812 */ setRelativeEmbeddedBounds(@onNull Rect relativeEmbeddedBounds)2813 void setRelativeEmbeddedBounds(@NonNull Rect relativeEmbeddedBounds) { 2814 if (mRelativeEmbeddedBounds == null) { 2815 throw new IllegalStateException("The TaskFragment is not embedded"); 2816 } 2817 if (mRelativeEmbeddedBounds.equals(relativeEmbeddedBounds)) { 2818 return; 2819 } 2820 mRelativeEmbeddedBounds.set(relativeEmbeddedBounds); 2821 } 2822 2823 /** 2824 * Updates the record of relative bounds of this embedded TaskFragment, and checks whether we 2825 * should prepare a transition for the bounds change. 2826 */ shouldStartChangeTransition(@onNull Rect absStartBounds, @NonNull Rect relStartBounds)2827 boolean shouldStartChangeTransition(@NonNull Rect absStartBounds, 2828 @NonNull Rect relStartBounds) { 2829 if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) { 2830 return false; 2831 } 2832 2833 if (mTransitionController.isShellTransitionsEnabled()) { 2834 // For Shell transition, the change will be collected anyway, so only take snapshot when 2835 // the bounds are resized. 2836 final Rect endBounds = getConfiguration().windowConfiguration.getBounds(); 2837 return endBounds.width() != absStartBounds.width() 2838 || endBounds.height() != absStartBounds.height(); 2839 } else { 2840 // For legacy transition, we need to trigger a change transition as long as the bounds 2841 // is changed, even if it is not resized. 2842 return !relStartBounds.equals(mRelativeEmbeddedBounds); 2843 } 2844 } 2845 2846 @Override canStartChangeTransition()2847 boolean canStartChangeTransition() { 2848 final Task task = getTask(); 2849 // Skip change transition when the Task is drag resizing. 2850 return task != null && !task.isDragResizing() && super.canStartChangeTransition(); 2851 } 2852 2853 @Override isSyncFinished(BLASTSyncEngine.SyncGroup group)2854 boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) { 2855 return super.isSyncFinished(group) && isReadyToTransit(); 2856 } 2857 2858 @Override setSurfaceControl(SurfaceControl sc)2859 void setSurfaceControl(SurfaceControl sc) { 2860 super.setSurfaceControl(sc); 2861 if (mTaskFragmentOrganizer != null) { 2862 updateOrganizedTaskFragmentSurfaceUnchecked(); 2863 // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to 2864 // emit the callbacks now. 2865 sendTaskFragmentAppeared(); 2866 } 2867 } 2868 sendTaskFragmentInfoChanged()2869 void sendTaskFragmentInfoChanged() { 2870 if (mTaskFragmentOrganizer != null) { 2871 mTaskFragmentOrganizerController 2872 .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this); 2873 } 2874 } 2875 sendTaskFragmentParentInfoChanged()2876 void sendTaskFragmentParentInfoChanged() { 2877 final Task parentTask = getParent().asTask(); 2878 if (mTaskFragmentOrganizer != null && parentTask != null) { 2879 mTaskFragmentOrganizerController 2880 .onTaskFragmentParentInfoChanged(mTaskFragmentOrganizer, parentTask); 2881 } 2882 } 2883 sendTaskFragmentAppeared()2884 private void sendTaskFragmentAppeared() { 2885 if (mTaskFragmentOrganizer != null) { 2886 mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this); 2887 } 2888 } 2889 sendTaskFragmentVanished()2890 private void sendTaskFragmentVanished() { 2891 if (mTaskFragmentOrganizer != null) { 2892 mTaskFragmentOrganizerController.onTaskFragmentVanished(mTaskFragmentOrganizer, this); 2893 } 2894 } 2895 2896 /** 2897 * Returns a {@link TaskFragmentInfo} with information from this TaskFragment. Should not be 2898 * called from {@link Task}. 2899 */ getTaskFragmentInfo()2900 TaskFragmentInfo getTaskFragmentInfo() { 2901 List<IBinder> childActivities = new ArrayList<>(); 2902 List<IBinder> inRequestedTaskFragmentActivities = new ArrayList<>(); 2903 for (int i = 0; i < getChildCount(); i++) { 2904 final WindowContainer<?> wc = getChildAt(i); 2905 final ActivityRecord ar = wc.asActivityRecord(); 2906 if (mTaskFragmentOrganizerUid != INVALID_UID && ar != null 2907 && ar.info.processName.equals(mTaskFragmentOrganizerProcessName) 2908 && ar.getUid() == mTaskFragmentOrganizerUid && !ar.finishing) { 2909 // Only includes Activities that belong to the organizer process for security. 2910 childActivities.add(ar.token); 2911 if (ar.mRequestedLaunchingTaskFragmentToken == mFragmentToken) { 2912 inRequestedTaskFragmentActivities.add(ar.token); 2913 } 2914 } 2915 } 2916 final Point positionInParent = new Point(); 2917 getRelativePosition(positionInParent); 2918 return new TaskFragmentInfo( 2919 mFragmentToken, 2920 mRemoteToken.toWindowContainerToken(), 2921 getConfiguration(), 2922 getNonFinishingActivityCount(), 2923 shouldBeVisible(null /* starting */), 2924 childActivities, 2925 inRequestedTaskFragmentActivities, 2926 positionInParent, 2927 mClearedTaskForReuse, 2928 mClearedTaskFragmentForPip, 2929 mClearedForReorderActivityToFront, 2930 calculateMinDimension(), 2931 isTopNonFinishingChild()); 2932 } 2933 isTopNonFinishingChild()2934 private boolean isTopNonFinishingChild() { 2935 final WindowContainer<?> parent = getParent(); 2936 if (parent == null) { 2937 // Either the TaskFragment is not attached or is going to destroy. Return false. 2938 return false; 2939 } 2940 final ActivityRecord topNonFishingActivity = parent.getActivity(ar -> !ar.finishing); 2941 // If the parent's top non-finishing activity is this TaskFragment's, it means 2942 // this TaskFragment is the top non-finishing container of its parent. 2943 return topNonFishingActivity != null && topNonFishingActivity 2944 .equals(getTopNonFinishingActivity()); 2945 } 2946 2947 /** 2948 * Calculates the minimum dimensions that this TaskFragment can be resized. 2949 * @see TaskFragmentInfo#getMinimumWidth() 2950 * @see TaskFragmentInfo#getMinimumHeight() 2951 */ calculateMinDimension()2952 Point calculateMinDimension() { 2953 final int[] maxMinWidth = new int[1]; 2954 final int[] maxMinHeight = new int[1]; 2955 2956 forAllActivities(a -> { 2957 if (a.finishing) { 2958 return; 2959 } 2960 final Point minDimensions = a.getMinDimensions(); 2961 if (minDimensions == null) { 2962 return; 2963 } 2964 maxMinWidth[0] = Math.max(maxMinWidth[0], minDimensions.x); 2965 maxMinHeight[0] = Math.max(maxMinHeight[0], minDimensions.y); 2966 }); 2967 return new Point(maxMinWidth[0], maxMinHeight[0]); 2968 } 2969 2970 @Nullable getFragmentToken()2971 IBinder getFragmentToken() { 2972 return mFragmentToken; 2973 } 2974 2975 @Nullable getTaskFragmentOrganizer()2976 ITaskFragmentOrganizer getTaskFragmentOrganizer() { 2977 return mTaskFragmentOrganizer; 2978 } 2979 2980 @Override isOrganized()2981 boolean isOrganized() { 2982 return mTaskFragmentOrganizer != null; 2983 } 2984 2985 /** Whether this is an organized {@link TaskFragment} and not a {@link Task}. */ isOrganizedTaskFragment()2986 final boolean isOrganizedTaskFragment() { 2987 return mTaskFragmentOrganizer != null; 2988 } 2989 2990 /** 2991 * Whether this is an embedded {@link TaskFragment} that does not fill the parent {@link Task}. 2992 */ isEmbeddedWithBoundsOverride()2993 boolean isEmbeddedWithBoundsOverride() { 2994 if (!mIsEmbedded) { 2995 return false; 2996 } 2997 final Task task = getTask(); 2998 if (task == null) { 2999 return false; 3000 } 3001 final Rect taskBounds = task.getBounds(); 3002 final Rect taskFragBounds = getBounds(); 3003 return !taskBounds.equals(taskFragBounds) && taskBounds.contains(taskFragBounds); 3004 } 3005 3006 /** Whether the Task should be visible. */ isTaskVisibleRequested()3007 boolean isTaskVisibleRequested() { 3008 final Task task = getTask(); 3009 return task != null && task.isVisibleRequested(); 3010 } 3011 isReadyToTransit()3012 boolean isReadyToTransit() { 3013 // We only wait when this is organized to give the organizer a chance to update. 3014 if (!isOrganizedTaskFragment()) { 3015 return true; 3016 } 3017 // We don't want to start the transition if the organized TaskFragment is empty, unless 3018 // it is requested to be removed or the mAllowTransitionWhenEmpty flag is true. 3019 if (getTopNonFinishingActivity() != null || mIsRemovalRequested 3020 || mAllowTransitionWhenEmpty) { 3021 return true; 3022 } 3023 // Organizer shouldn't change embedded TaskFragment in PiP. 3024 if (isEmbeddedTaskFragmentInPip()) { 3025 return true; 3026 } 3027 // The TaskFragment becomes empty because the last running activity enters PiP when the Task 3028 // is minimized. 3029 if (mClearedTaskFragmentForPip && !isTaskVisibleRequested()) { 3030 return true; 3031 } 3032 return false; 3033 } 3034 3035 @Override canCustomizeAppTransition()3036 boolean canCustomizeAppTransition() { 3037 // This is only called when the app transition is going to be played by system server. In 3038 // this case, we should allow custom app transition for fullscreen embedded TaskFragment 3039 // just like Activity. 3040 return isEmbedded() && matchParentBounds(); 3041 } 3042 3043 /** Clear {@link #mLastPausedActivity} for all {@link TaskFragment} children */ clearLastPausedActivity()3044 void clearLastPausedActivity() { 3045 forAllTaskFragments(taskFragment -> taskFragment.mLastPausedActivity = null); 3046 } 3047 3048 /** 3049 * Sets {@link #mMinWidth} and {@link #mMinWidth} to this TaskFragment. 3050 * It is usually set from the parent {@link Task} when adding the TaskFragment to the window 3051 * hierarchy. 3052 */ setMinDimensions(int minWidth, int minHeight)3053 void setMinDimensions(int minWidth, int minHeight) { 3054 if (asTask() != null) { 3055 throw new UnsupportedOperationException("This method must not be used to Task. The " 3056 + " minimum dimension of Task should be passed from Task constructor."); 3057 } 3058 mMinWidth = minWidth; 3059 mMinHeight = minHeight; 3060 } 3061 3062 /** 3063 * Whether this is an embedded TaskFragment in PIP Task. We don't allow any client config 3064 * override for such TaskFragment to prevent flight with PipTaskOrganizer. 3065 */ isEmbeddedTaskFragmentInPip()3066 boolean isEmbeddedTaskFragmentInPip() { 3067 return isOrganizedTaskFragment() && getTask() != null && getTask().inPinnedWindowingMode(); 3068 } 3069 shouldRemoveSelfOnLastChildRemoval()3070 boolean shouldRemoveSelfOnLastChildRemoval() { 3071 if (!mCreatedByOrganizer || mIsRemovalRequested) { 3072 return true; 3073 } 3074 // The TaskFragmentOrganizer may be killed while the embedded TaskFragments remains in WM 3075 // core. The embedded TaskFragment should still be removed when the child activities are 3076 // all gone (like package force-stopped). 3077 return mIsEmbedded && mTaskFragmentOrganizer == null; 3078 } 3079 3080 /** 3081 * Returns whether this TaskFragment is going to be removed. 3082 */ isRemovalRequested()3083 boolean isRemovalRequested() { 3084 return mIsRemovalRequested; 3085 } 3086 3087 @Override removeChild(WindowContainer child)3088 void removeChild(WindowContainer child) { 3089 removeChild(child, true /* removeSelfIfPossible */); 3090 } 3091 removeChild(WindowContainer child, boolean removeSelfIfPossible)3092 void removeChild(WindowContainer child, boolean removeSelfIfPossible) { 3093 super.removeChild(child); 3094 final ActivityRecord r = child.asActivityRecord(); 3095 final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(r); 3096 if (hostProcess != null) { 3097 hostProcess.removeEmbeddedActivity(r); 3098 } 3099 if (removeSelfIfPossible && shouldRemoveSelfOnLastChildRemoval() && !hasChild()) { 3100 removeImmediately("removeLastChild " + child); 3101 } 3102 } 3103 3104 /** 3105 * Requests to remove this task fragment. If it doesn't have children, it is removed 3106 * immediately. Otherwise it will be removed until all activities are destroyed. 3107 * 3108 * @param withTransition Whether to use transition animation when removing activities. Set to 3109 * {@code false} if this is invisible to user, e.g. display removal. 3110 */ remove(boolean withTransition, String reason)3111 void remove(boolean withTransition, String reason) { 3112 if (!hasChild()) { 3113 removeImmediately(reason); 3114 return; 3115 } 3116 mIsRemovalRequested = true; 3117 // The task order may be changed by finishIfPossible() for adjusting focus if there are 3118 // nested tasks, so add all activities into a list to avoid missed removals. 3119 final ArrayList<ActivityRecord> removingActivities = new ArrayList<>(); 3120 forAllActivities((r) -> { 3121 if (!r.finishing) { 3122 removingActivities.add(r); 3123 } 3124 }); 3125 for (int i = removingActivities.size() - 1; i >= 0; --i) { 3126 final ActivityRecord r = removingActivities.get(i); 3127 if (withTransition && r.isVisible()) { 3128 r.finishIfPossible(reason, false /* oomAdj */); 3129 } else { 3130 r.destroyIfPossible(reason); 3131 } 3132 } 3133 } 3134 setDelayLastActivityRemoval(boolean delay)3135 void setDelayLastActivityRemoval(boolean delay) { 3136 if (!mIsEmbedded) { 3137 Slog.w(TAG, "Set delaying last activity removal on a non-embedded TF."); 3138 } 3139 mDelayLastActivityRemoval = delay; 3140 } 3141 isDelayLastActivityRemoval()3142 boolean isDelayLastActivityRemoval() { 3143 return mDelayLastActivityRemoval; 3144 } 3145 shouldDeferRemoval()3146 boolean shouldDeferRemoval() { 3147 if (!hasChild()) { 3148 return false; 3149 } 3150 return isExitAnimationRunningSelfOrChild(); 3151 } 3152 3153 @Override handleCompleteDeferredRemoval()3154 boolean handleCompleteDeferredRemoval() { 3155 if (shouldDeferRemoval()) { 3156 return true; 3157 } 3158 return super.handleCompleteDeferredRemoval(); 3159 } 3160 3161 /** The overridden method must call {@link #removeImmediately()} instead of super. */ removeImmediately(String reason)3162 void removeImmediately(String reason) { 3163 Slog.d(TAG, "Remove task fragment: " + reason); 3164 removeImmediately(); 3165 } 3166 3167 @Override removeImmediately()3168 void removeImmediately() { 3169 if (asTask() == null) { 3170 EventLogTags.writeWmTfRemoved(System.identityHashCode(this), getTaskId()); 3171 } 3172 mIsRemovalRequested = false; 3173 removeFromAdjacentTaskFragments(); 3174 cleanUpEmbeddedTaskFragment(); 3175 final boolean shouldExecuteAppTransition = 3176 mClearedTaskFragmentForPip && isTaskVisibleRequested(); 3177 super.removeImmediately(); 3178 sendTaskFragmentVanished(); 3179 if (shouldExecuteAppTransition && mDisplayContent != null) { 3180 // When the Task is still visible, and the TaskFragment is removed because the last 3181 // running activity is reparenting to PiP, it is possible that no activity is getting 3182 // paused or resumed (having an embedded activity in split), thus we need to relayout 3183 // and execute it explicitly. 3184 mAtmService.addWindowLayoutReasons( 3185 ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED); 3186 mDisplayContent.executeAppTransition(); 3187 } 3188 } 3189 3190 /** Called on remove to cleanup. */ cleanUpEmbeddedTaskFragment()3191 private void cleanUpEmbeddedTaskFragment() { 3192 if (!mIsEmbedded) { 3193 return; 3194 } 3195 mAtmService.mWindowOrganizerController.cleanUpEmbeddedTaskFragment(this); 3196 final Task task = getTask(); 3197 if (task == null) { 3198 return; 3199 } 3200 task.forAllLeafTaskFragments(taskFragment -> { 3201 if (taskFragment.getCompanionTaskFragment() == this) { 3202 taskFragment.setCompanionTaskFragment(null /* companionTaskFragment */); 3203 } 3204 }, false /* traverseTopToBottom */); 3205 } 3206 shouldBoostDimmer()3207 boolean shouldBoostDimmer() { 3208 if (asTask() != null || !isDimmingOnParentTask()) { 3209 // early return if not embedded or should not dim on parent Task. 3210 return false; 3211 } 3212 3213 if (!hasAdjacentTaskFragment()) { 3214 // early return if no adjacent TF. 3215 return false; 3216 } 3217 3218 final ArrayList<WindowContainer> siblings = getParent().mChildren; 3219 final int zOrder = siblings.indexOf(this); 3220 final boolean hasAdjacentOnTop = forOtherAdjacentTaskFragments( 3221 tf -> siblings.indexOf(tf) > zOrder); 3222 if (!hasAdjacentOnTop) { 3223 // early return if this TF already has higher z-ordering. 3224 return false; 3225 } 3226 3227 final ToBooleanFunction<WindowState> getDimBehindWindow = 3228 (w) -> (w.mAttrs.flags & FLAG_DIM_BEHIND) != 0 && w.mActivityRecord != null 3229 && w.mActivityRecord.isEmbedded() && (w.mActivityRecord.isVisibleRequested() 3230 || w.mActivityRecord.isVisible()); 3231 final boolean adjacentHasDimmingWindow = forOtherAdjacentTaskFragments(tf -> { 3232 return tf.forAllWindows(getDimBehindWindow, true); 3233 }); 3234 if (adjacentHasDimmingWindow) { 3235 // early return if the adjacent Tf has a dimming window. 3236 return false; 3237 } 3238 3239 // boost if there's an Activity window that has FLAG_DIM_BEHIND flag. 3240 return forAllWindows(getDimBehindWindow, true); 3241 } 3242 3243 @Deprecated 3244 @Override getDimmer()3245 Dimmer getDimmer() { 3246 // If this is in an embedded TaskFragment and we want the dim applies on the TaskFragment. 3247 if (mIsEmbedded && !isDimmingOnParentTask()) { 3248 return mDimmer; 3249 } 3250 3251 return super.getDimmer(); 3252 } 3253 3254 /** Bounds to be used for dimming, as well as touch related tests. */ getDimBounds(@onNull Rect out)3255 void getDimBounds(@NonNull Rect out) { 3256 if (Flags.useTasksDimOnly() && mDimmer.hasDimState()) { 3257 out.set(mDimmer.getDimBounds()); 3258 } else { 3259 if (mIsEmbedded && isDimmingOnParentTask() && getDimmer().getDimBounds() != null) { 3260 // Return the task bounds if the dimmer is showing and should cover on the Task (not 3261 // just on this embedded TaskFragment). 3262 out.set(getTask().getBounds()); 3263 } else { 3264 out.set(getBounds()); 3265 } 3266 } 3267 } 3268 setEmbeddedDimArea(@mbeddedDimArea int embeddedDimArea)3269 void setEmbeddedDimArea(@EmbeddedDimArea int embeddedDimArea) { 3270 mEmbeddedDimArea = embeddedDimArea; 3271 } 3272 setMoveToBottomIfClearWhenLaunch(boolean moveToBottomIfClearWhenLaunch)3273 void setMoveToBottomIfClearWhenLaunch(boolean moveToBottomIfClearWhenLaunch) { 3274 mMoveToBottomIfClearWhenLaunch = moveToBottomIfClearWhenLaunch; 3275 } 3276 isMoveToBottomIfClearWhenLaunch()3277 boolean isMoveToBottomIfClearWhenLaunch() { 3278 return mMoveToBottomIfClearWhenLaunch; 3279 } 3280 3281 @VisibleForTesting isDimmingOnParentTask()3282 boolean isDimmingOnParentTask() { 3283 return mEmbeddedDimArea == EMBEDDED_DIM_AREA_PARENT_TASK; 3284 } 3285 3286 @Override prepareSurfaces()3287 void prepareSurfaces() { 3288 if (asTask() != null) { 3289 super.prepareSurfaces(); 3290 return; 3291 } 3292 3293 mDimmer.resetDimStates(); 3294 super.prepareSurfaces(); 3295 3296 if (!Flags.useTasksDimOnly()) { 3297 final Rect dimBounds = mDimmer.getDimBounds(); 3298 if (dimBounds != null) { 3299 // Bounds need to be relative, as the dim layer is a child. 3300 dimBounds.offsetTo(0 /* newLeft */, 0 /* newTop */); 3301 if (mDimmer.updateDims(getSyncTransaction())) { 3302 scheduleAnimation(); 3303 } 3304 } 3305 } else { 3306 if (mDimmer.updateDims(getSyncTransaction())) { 3307 scheduleAnimation(); 3308 } 3309 } 3310 } 3311 3312 @Override fillsParent()3313 boolean fillsParent() { 3314 // From the perspective of policy, we still want to report that this task fills parent 3315 // in fullscreen windowing mode even it doesn't match parent bounds because there will be 3316 // letterbox around its real content. 3317 return getWindowingMode() == WINDOWING_MODE_FULLSCREEN || matchParentBounds(); 3318 } 3319 3320 @Override onChildVisibleRequestedChanged(@ullable WindowContainer child)3321 protected boolean onChildVisibleRequestedChanged(@Nullable WindowContainer child) { 3322 if (!super.onChildVisibleRequestedChanged(child)) return false; 3323 // Send the info changed to update the TaskFragment visibility. 3324 sendTaskFragmentInfoChanged(); 3325 return true; 3326 } 3327 3328 @Nullable 3329 @Override getTaskFragment(Predicate<TaskFragment> callback)3330 TaskFragment getTaskFragment(Predicate<TaskFragment> callback) { 3331 final TaskFragment taskFragment = super.getTaskFragment(callback); 3332 if (taskFragment != null) { 3333 return taskFragment; 3334 } 3335 return callback.test(this) ? this : null; 3336 } 3337 3338 /** 3339 * Moves the passed child to front 3340 * @return whether it was actually moved (vs already being top). 3341 */ moveChildToFront(WindowContainer newTop)3342 boolean moveChildToFront(WindowContainer newTop) { 3343 int origDist = getDistanceFromTop(newTop); 3344 positionChildAt(POSITION_TOP, newTop, false /* includeParents */); 3345 return getDistanceFromTop(newTop) != origDist; 3346 } 3347 toFullString()3348 String toFullString() { 3349 final StringBuilder sb = new StringBuilder(128); 3350 sb.append(this); 3351 sb.setLength(sb.length() - 1); // Remove tail '}'. 3352 if (mTaskFragmentOrganizerUid != INVALID_UID) { 3353 sb.append(" organizerUid="); 3354 sb.append(mTaskFragmentOrganizerUid); 3355 } 3356 if (mTaskFragmentOrganizerProcessName != null) { 3357 sb.append(" organizerProc="); 3358 sb.append(mTaskFragmentOrganizerProcessName); 3359 } 3360 if (mAdjacentTaskFragments != null) { 3361 sb.append(" adjacent="); 3362 sb.append(mAdjacentTaskFragments); 3363 } 3364 sb.append('}'); 3365 return sb.toString(); 3366 } 3367 3368 @Override toString()3369 public String toString() { 3370 return "TaskFragment{" + Integer.toHexString(System.identityHashCode(this)) 3371 + " mode=" + WindowConfiguration.windowingModeToString(getWindowingMode()) + "}"; 3372 } 3373 dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header)3374 boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll, 3375 boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header) { 3376 boolean printed = false; 3377 Runnable headerPrinter = () -> { 3378 if (needSep) { 3379 pw.println(); 3380 } 3381 if (header != null) { 3382 header.run(); 3383 } 3384 3385 dumpInner(prefix, pw, dumpAll, dumpPackage); 3386 }; 3387 3388 if (dumpPackage == null) { 3389 // If we are not filtering by package, we want to print absolutely everything, 3390 // so always print the header even if there are no tasks/activities inside. 3391 headerPrinter.run(); 3392 headerPrinter = null; 3393 printed = true; 3394 } 3395 3396 for (int i = mChildren.size() - 1; i >= 0; --i) { 3397 WindowContainer child = mChildren.get(i); 3398 if (child.asTaskFragment() != null) { 3399 printed |= child.asTaskFragment().dump(prefix + " ", fd, pw, dumpAll, 3400 dumpClient, dumpPackage, needSep, headerPrinter); 3401 } else if (child.asActivityRecord() != null) { 3402 ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + " ", 3403 "Hist ", true, !dumpAll, dumpClient, dumpPackage, false, headerPrinter, 3404 getTask()); 3405 } 3406 } 3407 3408 return printed; 3409 } 3410 dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage)3411 void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) { 3412 pw.print(prefix); pw.print("* "); pw.println(toFullString()); 3413 final Rect bounds = getRequestedOverrideBounds(); 3414 if (!bounds.isEmpty()) { 3415 pw.println(prefix + " mBounds=" + bounds); 3416 } 3417 if (mIsRemovalRequested) { 3418 pw.println(prefix + " mIsRemovalRequested=true"); 3419 } 3420 if (dumpAll) { 3421 printThisActivity(pw, mLastPausedActivity, dumpPackage, false, 3422 prefix + " mLastPausedActivity: ", null); 3423 } 3424 } 3425 3426 @Override dump(PrintWriter pw, String prefix, boolean dumpAll)3427 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 3428 super.dump(pw, prefix, dumpAll); 3429 pw.println(prefix + "bounds=" + getBounds().toShortString() 3430 + (mIsolatedNav ? ", isolatedNav" : "")); 3431 final String doublePrefix = prefix + " "; 3432 for (int i = mChildren.size() - 1; i >= 0; i--) { 3433 final WindowContainer<?> child = mChildren.get(i); 3434 final TaskFragment tf = child.asTaskFragment(); 3435 pw.println(prefix + "* " + (tf != null ? tf.toFullString() : child)); 3436 // Only dump non-activity because full activity info is already printed by 3437 // RootWindowContainer#dumpActivities. 3438 if (tf != null) { 3439 child.dump(pw, doublePrefix, dumpAll); 3440 } 3441 } 3442 } 3443 3444 @Override writeIdentifierToProto(ProtoOutputStream proto, long fieldId)3445 void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { 3446 final long token = proto.start(fieldId); 3447 proto.write(HASH_CODE, System.identityHashCode(this)); 3448 final ActivityRecord topActivity = topRunningActivity(); 3449 proto.write(USER_ID, topActivity != null ? topActivity.mUserId : USER_NULL); 3450 proto.write(TITLE, topActivity != null ? topActivity.intent.getComponent() 3451 .flattenToShortString() : "TaskFragment"); 3452 proto.end(token); 3453 } 3454 3455 @Override getProtoFieldId()3456 long getProtoFieldId() { 3457 return TASK_FRAGMENT; 3458 } 3459 3460 @Override dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTracingLogLevel int logLevel)3461 public void dumpDebug(ProtoOutputStream proto, long fieldId, 3462 @WindowTracingLogLevel int logLevel) { 3463 if (logLevel == WindowTracingLogLevel.CRITICAL && !isVisible()) { 3464 return; 3465 } 3466 3467 final long token = proto.start(fieldId); 3468 3469 super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); 3470 3471 proto.write(DISPLAY_ID, getDisplayId()); 3472 proto.write(ACTIVITY_TYPE, getActivityType()); 3473 proto.write(MIN_WIDTH, mMinWidth); 3474 proto.write(MIN_HEIGHT, mMinHeight); 3475 3476 proto.end(token); 3477 } 3478 3479 /** Set of {@link TaskFragment}s that are adjacent to each other. */ 3480 static class AdjacentSet { 3481 private final ArraySet<TaskFragment> mAdjacentSet; 3482 AdjacentSet(@onNull TaskFragment... taskFragments)3483 AdjacentSet(@NonNull TaskFragment... taskFragments) { 3484 this(new ArraySet<>(taskFragments)); 3485 } 3486 AdjacentSet(@onNull ArraySet<TaskFragment> taskFragments)3487 AdjacentSet(@NonNull ArraySet<TaskFragment> taskFragments) { 3488 final int size = taskFragments.size(); 3489 if (size < 2) { 3490 throw new IllegalArgumentException("Adjacent TaskFragments must contain at least" 3491 + " two TaskFragments, but only " + size + " were provided."); 3492 } 3493 if (size > 2) { 3494 for (int i = 0; i < size; i++) { 3495 if (taskFragments.valueAt(i).asTask() == null) { 3496 throw new IllegalArgumentException( 3497 "Not yet support 3+ adjacent for non-Task TFs"); 3498 } 3499 } 3500 } 3501 mAdjacentSet = taskFragments; 3502 } 3503 3504 /** Updates each {@link TaskFragment} in the set to be adjacent to each other. */ setAsAdjacent()3505 private void setAsAdjacent() { 3506 if (mAdjacentSet.isEmpty() 3507 || equals(mAdjacentSet.valueAt(0).mAdjacentTaskFragments)) { 3508 // No need to update if any TaskFragment in the set has already been updated to the 3509 // same set. 3510 return; 3511 } 3512 for (int i = mAdjacentSet.size() - 1; i >= 0; i--) { 3513 final TaskFragment taskFragment = mAdjacentSet.valueAt(i); 3514 taskFragment.removeFromAdjacentTaskFragments(); 3515 taskFragment.mAdjacentTaskFragments = this; 3516 } 3517 } 3518 3519 /** Removes the {@link TaskFragment} from the adjacent set. */ remove(@onNull TaskFragment taskFragment)3520 private void remove(@NonNull TaskFragment taskFragment) { 3521 taskFragment.mAdjacentTaskFragments = null; 3522 taskFragment.mDelayLastActivityRemoval = false; 3523 mAdjacentSet.remove(taskFragment); 3524 if (mAdjacentSet.size() < 2) { 3525 // To be considered as adjacent, there must be at least 2 TaskFragments in the set. 3526 clear(); 3527 } 3528 } 3529 3530 /** Clears the adjacent relationship. */ clear()3531 private void clear() { 3532 for (int i = mAdjacentSet.size() - 1; i >= 0; i--) { 3533 final TaskFragment taskFragment = mAdjacentSet.valueAt(i); 3534 // Clear all reference. 3535 taskFragment.mAdjacentTaskFragments = null; 3536 taskFragment.mDelayLastActivityRemoval = false; 3537 } 3538 mAdjacentSet.clear(); 3539 } 3540 3541 /** Whether the {@link TaskFragment} is in this adjacent set. */ contains(@onNull TaskFragment taskFragment)3542 boolean contains(@NonNull TaskFragment taskFragment) { 3543 return mAdjacentSet.contains(taskFragment); 3544 } 3545 3546 /** 3547 * Runs the callback on all adjacent TaskFragments. Skips the exclude one if not null. 3548 */ forAllTaskFragments(@onNull Consumer<TaskFragment> callback, @Nullable TaskFragment exclude)3549 void forAllTaskFragments(@NonNull Consumer<TaskFragment> callback, 3550 @Nullable TaskFragment exclude) { 3551 for (int i = mAdjacentSet.size() - 1; i >= 0; i--) { 3552 final TaskFragment taskFragment = mAdjacentSet.valueAt(i); 3553 if (taskFragment != exclude) { 3554 callback.accept(taskFragment); 3555 } 3556 } 3557 } 3558 3559 /** 3560 * Runs the callback on all adjacent TaskFragments until one returns {@code true}. Skips the 3561 * exclude one if not null. 3562 */ forAllTaskFragments(@onNull Predicate<TaskFragment> callback, @Nullable TaskFragment exclude)3563 boolean forAllTaskFragments(@NonNull Predicate<TaskFragment> callback, 3564 @Nullable TaskFragment exclude) { 3565 for (int i = mAdjacentSet.size() - 1; i >= 0; i--) { 3566 final TaskFragment taskFragment = mAdjacentSet.valueAt(i); 3567 if (taskFragment == exclude) { 3568 continue; 3569 } 3570 if (callback.test(taskFragment)) { 3571 return true; 3572 } 3573 } 3574 return false; 3575 } 3576 size()3577 int size() { 3578 return mAdjacentSet.size(); 3579 } 3580 3581 @Override equals(@ullable Object o)3582 public boolean equals(@Nullable Object o) { 3583 if (this == o) { 3584 return true; 3585 } 3586 if (!(o instanceof AdjacentSet other)) { 3587 return false; 3588 } 3589 return mAdjacentSet.equals(other.mAdjacentSet); 3590 } 3591 3592 @Override toString()3593 public String toString() { 3594 final StringBuilder sb = new StringBuilder(); 3595 sb.append("AdjacentSet{"); 3596 final int size = mAdjacentSet.size(); 3597 for (int i = 0; i < size; i++) { 3598 if (i != 0) { 3599 sb.append(", "); 3600 } 3601 sb.append(mAdjacentSet.valueAt(i)); 3602 } 3603 sb.append("}"); 3604 return sb.toString(); 3605 } 3606 } 3607 } 3608