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