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