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