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