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