1 /* 2 * Copyright (C) 2020 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.wm.shell.splitscreen; 18 19 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 22 import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; 23 import static android.view.RemoteAnimationTarget.MODE_OPENING; 24 25 import static com.android.wm.shell.Flags.enableFlexibleSplit; 26 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN; 27 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; 28 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; 29 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE; 30 import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString; 31 32 import android.annotation.CallSuper; 33 import android.annotation.Nullable; 34 import android.app.ActivityManager; 35 import android.app.TaskInfo; 36 import android.content.Context; 37 import android.graphics.Rect; 38 import android.os.IBinder; 39 import android.util.SparseArray; 40 import android.view.RemoteAnimationTarget; 41 import android.view.SurfaceControl; 42 import android.window.WindowContainerToken; 43 import android.window.WindowContainerTransaction; 44 45 import androidx.annotation.NonNull; 46 47 import com.android.internal.protolog.ProtoLog; 48 import com.android.internal.util.ArrayUtils; 49 import com.android.launcher3.icons.IconProvider; 50 import com.android.wm.shell.ShellTaskOrganizer; 51 import com.android.wm.shell.common.SurfaceUtils; 52 import com.android.wm.shell.common.SyncTransactionQueue; 53 import com.android.wm.shell.common.split.SplitDecorManager; 54 import com.android.wm.shell.splitscreen.SplitScreen.StageType; 55 import com.android.wm.shell.windowdecor.WindowDecorViewModel; 56 57 import java.io.PrintWriter; 58 import java.util.Optional; 59 import java.util.function.Consumer; 60 import java.util.function.Predicate; 61 62 /** 63 * Base class that handle common task org. related for split-screen stages. 64 * Note that this class and its sub-class do not directly perform hierarchy operations. 65 * They only serve to hold a collection of tasks and provide APIs like 66 * {@link #addTask(ActivityManager.RunningTaskInfo, WindowContainerTransaction)} for the centralized 67 * {@link StageCoordinator} to perform hierarchy operations in-sync with other containers. 68 * 69 * @see StageCoordinator 70 */ 71 public class StageTaskListener implements ShellTaskOrganizer.TaskListener { 72 private static final String TAG = StageTaskListener.class.getSimpleName(); 73 74 // No current way to enforce this but if enableFlexibleSplit() is enabled, then only 1 of the 75 // stages should have this be set/being used 76 private boolean mIsActive; 77 /** Unique identifier for this state, > 0 */ 78 @StageType private final int mId; 79 /** Callback interface for listening to changes in a split-screen stage. */ 80 public interface StageListenerCallbacks { onRootTaskAppeared()81 void onRootTaskAppeared(); 82 onStageVisibilityChanged(StageTaskListener stageTaskListener)83 void onStageVisibilityChanged(StageTaskListener stageTaskListener); 84 onChildTaskStatusChanged(StageTaskListener stage, int taskId, boolean present, boolean visible)85 void onChildTaskStatusChanged(StageTaskListener stage, int taskId, boolean present, 86 boolean visible); 87 onRootTaskVanished()88 void onRootTaskVanished(); 89 onNoLongerSupportMultiWindow(StageTaskListener stageTaskListener, ActivityManager.RunningTaskInfo taskInfo)90 void onNoLongerSupportMultiWindow(StageTaskListener stageTaskListener, 91 ActivityManager.RunningTaskInfo taskInfo); 92 } 93 94 private final Context mContext; 95 private final StageListenerCallbacks mCallbacks; 96 private final SyncTransactionQueue mSyncQueue; 97 private final IconProvider mIconProvider; 98 private final Optional<WindowDecorViewModel> mWindowDecorViewModel; 99 100 /** Whether or not the root task has been created. */ 101 boolean mHasRootTask = false; 102 /** Whether or not the root task is visible. */ 103 boolean mVisible = false; 104 /** Whether or not the root task has any children or not. */ 105 boolean mHasChildren = false; 106 protected ActivityManager.RunningTaskInfo mRootTaskInfo; 107 protected SurfaceControl mRootLeash; 108 protected SurfaceControl mDimLayer; 109 protected SparseArray<ActivityManager.RunningTaskInfo> mChildrenTaskInfo = new SparseArray<>(); 110 private final SparseArray<SurfaceControl> mChildrenLeashes = new SparseArray<>(); 111 // TODO(b/204308910): Extracts SplitDecorManager related code to common package. 112 private SplitDecorManager mSplitDecorManager; 113 StageTaskListener(Context context, ShellTaskOrganizer taskOrganizer, int displayId, StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue, IconProvider iconProvider, Optional<WindowDecorViewModel> windowDecorViewModel, int id)114 StageTaskListener(Context context, ShellTaskOrganizer taskOrganizer, int displayId, 115 StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue, 116 IconProvider iconProvider, 117 Optional<WindowDecorViewModel> windowDecorViewModel, int id) { 118 mContext = context; 119 mCallbacks = callbacks; 120 mSyncQueue = syncQueue; 121 mIconProvider = iconProvider; 122 mWindowDecorViewModel = windowDecorViewModel; 123 taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this); 124 mId = id; 125 } 126 getChildCount()127 int getChildCount() { 128 return mChildrenTaskInfo.size(); 129 } 130 containsTask(int taskId)131 boolean containsTask(int taskId) { 132 return mChildrenTaskInfo.contains(taskId); 133 } 134 containsToken(WindowContainerToken token)135 boolean containsToken(WindowContainerToken token) { 136 return contains(t -> t.token.equals(token)); 137 } 138 containsContainer(IBinder binder)139 boolean containsContainer(IBinder binder) { 140 return contains(t -> t.token.asBinder() == binder); 141 } 142 143 /** 144 * Returns the top visible child task's id. 145 */ getTopVisibleChildTaskId()146 int getTopVisibleChildTaskId() { 147 // TODO(b/378601156): This doesn't get the top task (translucent tasks are also 148 // visible-requested) 149 final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible 150 && t.isVisibleRequested); 151 return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID; 152 } 153 154 /** 155 * Returns the top activity uid for the top child task. 156 */ getTopChildTaskUid()157 int getTopChildTaskUid() { 158 // TODO(b/378601156): This doesn't get the top task 159 final ActivityManager.RunningTaskInfo taskInfo = 160 getChildTaskInfo(t -> t.topActivityInfo != null); 161 return taskInfo != null ? taskInfo.topActivityInfo.applicationInfo.uid : 0; 162 } 163 164 /** @return {@code true} if this listener contains the currently focused task. */ isFocused()165 boolean isFocused() { 166 return contains(t -> t.isFocused); 167 } 168 169 @StageType getId()170 int getId() { 171 return mId; 172 } 173 contains(Predicate<ActivityManager.RunningTaskInfo> predicate)174 private boolean contains(Predicate<ActivityManager.RunningTaskInfo> predicate) { 175 if (mRootTaskInfo != null && predicate.test(mRootTaskInfo)) { 176 return true; 177 } 178 179 return getChildTaskInfo(predicate) != null; 180 } 181 getRootLeash()182 public SurfaceControl getRootLeash() { 183 return mRootLeash; 184 } 185 getRunningTaskInfo()186 public ActivityManager.RunningTaskInfo getRunningTaskInfo() { 187 return mRootTaskInfo; 188 } 189 getDecorManager()190 public SplitDecorManager getDecorManager() { 191 return mSplitDecorManager; 192 } 193 194 @Nullable getChildTaskInfo( Predicate<ActivityManager.RunningTaskInfo> predicate)195 private ActivityManager.RunningTaskInfo getChildTaskInfo( 196 Predicate<ActivityManager.RunningTaskInfo> predicate) { 197 for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { 198 final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); 199 if (predicate.test(taskInfo)) { 200 return taskInfo; 201 } 202 } 203 return null; 204 } 205 206 @Override 207 @CallSuper onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash)208 public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { 209 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskAppeared: taskId=%d taskParent=%d rootTask=%d " 210 + "stageId=%s taskActivity=%s", 211 taskInfo.taskId, taskInfo.parentTaskId, 212 mRootTaskInfo != null ? mRootTaskInfo.taskId : -1, 213 stageTypeToString(mId), taskInfo.baseActivity); 214 if (mRootTaskInfo == null) { 215 mRootLeash = leash; 216 mRootTaskInfo = taskInfo; 217 mSplitDecorManager = new SplitDecorManager( 218 mRootTaskInfo.configuration, 219 mIconProvider); 220 mHasRootTask = true; 221 mCallbacks.onRootTaskAppeared(); 222 if (mVisible != mRootTaskInfo.isVisible) { 223 mVisible = mRootTaskInfo.isVisible; 224 mCallbacks.onStageVisibilityChanged(this); 225 } 226 mSyncQueue.runInSync(t -> mDimLayer = 227 SurfaceUtils.makeDimLayer(t, mRootLeash, "Dim layer")); 228 } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { 229 final int taskId = taskInfo.taskId; 230 mChildrenLeashes.put(taskId, leash); 231 mChildrenTaskInfo.put(taskId, taskInfo); 232 mCallbacks.onChildTaskStatusChanged(this, taskId, true /* present */, 233 taskInfo.isVisible && taskInfo.isVisibleRequested); 234 } else { 235 throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo 236 + "\n mRootTaskInfo: " + mRootTaskInfo); 237 } 238 } 239 240 @Override 241 @CallSuper onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo)242 public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { 243 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: taskId=%d taskAct=%s " 244 + "stageId=%s", 245 taskInfo.taskId, taskInfo.baseActivity, stageTypeToString(mId)); 246 mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo)); 247 if (mRootTaskInfo.taskId == taskInfo.taskId) { 248 mRootTaskInfo = taskInfo; 249 } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { 250 if (!taskInfo.supportsMultiWindow 251 || !ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) 252 || !ArrayUtils.contains(CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, 253 taskInfo.getWindowingMode())) { 254 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, 255 "onTaskInfoChanged: task=%d no longer supports multiwindow", 256 taskInfo.taskId); 257 // Leave split screen if the task no longer supports multi window or have 258 // uncontrolled task. 259 mCallbacks.onNoLongerSupportMultiWindow(this, taskInfo); 260 return; 261 } 262 mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); 263 mCallbacks.onChildTaskStatusChanged(this, taskInfo.taskId, true /* present */, 264 taskInfo.isVisible && taskInfo.isVisibleRequested); 265 } else { 266 throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo 267 + "\n mRootTaskInfo: " + mRootTaskInfo); 268 } 269 } 270 271 @Override 272 @CallSuper onTaskVanished(ActivityManager.RunningTaskInfo taskInfo)273 public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { 274 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskVanished: task=%d stageId=%s", 275 taskInfo.taskId, stageTypeToString(mId)); 276 final int taskId = taskInfo.taskId; 277 mWindowDecorViewModel.ifPresent(vm -> vm.onTaskVanished(taskInfo)); 278 if (mRootTaskInfo.taskId == taskId) { 279 mHasRootTask = false; 280 mVisible = false; 281 mHasChildren = false; 282 mCallbacks.onRootTaskVanished(); 283 mRootTaskInfo = null; 284 mRootLeash = null; 285 mSyncQueue.runInSync(t -> { 286 t.remove(mDimLayer); 287 mSplitDecorManager.release(t); 288 }); 289 } else if (mChildrenTaskInfo.contains(taskId)) { 290 mChildrenTaskInfo.remove(taskId); 291 mChildrenLeashes.remove(taskId); 292 mCallbacks.onChildTaskStatusChanged(this, taskId, false /* present */, 293 taskInfo.isVisible); 294 } else { 295 throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo 296 + "\n mRootTaskInfo: " + mRootTaskInfo); 297 } 298 } 299 300 @Override attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b)301 public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) { 302 b.setParent(findTaskSurface(taskId)); 303 } 304 305 @Override reparentChildSurfaceToTask(int taskId, SurfaceControl sc, SurfaceControl.Transaction t)306 public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc, 307 SurfaceControl.Transaction t) { 308 t.reparent(sc, findTaskSurface(taskId)); 309 } 310 findTaskSurface(int taskId)311 private SurfaceControl findTaskSurface(int taskId) { 312 if (mRootTaskInfo.taskId == taskId) { 313 return mRootLeash; 314 } else if (mChildrenLeashes.contains(taskId)) { 315 return mChildrenLeashes.get(taskId); 316 } else { 317 throw new IllegalArgumentException("There is no surface for taskId=" + taskId); 318 } 319 } 320 isRootTaskId(int taskId)321 boolean isRootTaskId(int taskId) { 322 return mRootTaskInfo != null && mRootTaskInfo.taskId == taskId; 323 } 324 onResizing(Rect newBounds, Rect sideBounds, Rect displayBounds, SurfaceControl.Transaction t, int offsetX, int offsetY, boolean immediately)325 void onResizing(Rect newBounds, Rect sideBounds, Rect displayBounds, 326 SurfaceControl.Transaction t, int offsetX, int offsetY, boolean immediately) { 327 if (mSplitDecorManager != null && mRootTaskInfo != null) { 328 mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, sideBounds, displayBounds, t, 329 offsetX, offsetY, immediately); 330 } 331 } 332 onResized(SurfaceControl.Transaction t)333 void onResized(SurfaceControl.Transaction t) { 334 if (mSplitDecorManager != null) { 335 mSplitDecorManager.onResized(t, null); 336 } 337 } 338 screenshotIfNeeded(SurfaceControl.Transaction t)339 void screenshotIfNeeded(SurfaceControl.Transaction t) { 340 if (mSplitDecorManager != null) { 341 mSplitDecorManager.screenshotIfNeeded(t); 342 } 343 } 344 fadeOutDecor(Runnable finishedCallback)345 void fadeOutDecor(Runnable finishedCallback) { 346 if (mSplitDecorManager != null) { 347 mSplitDecorManager.fadeOutDecor(finishedCallback, false /* addDelay */); 348 } else { 349 finishedCallback.run(); 350 } 351 } 352 getSplitDecorManager()353 SplitDecorManager getSplitDecorManager() { 354 return mSplitDecorManager; 355 } 356 addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct)357 void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) { 358 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "addTask: task=%d", task.taskId); 359 // Clear overridden bounds and windowing mode to make sure the child task can inherit 360 // windowing mode and bounds from split root. 361 wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED) 362 .setBounds(task.token, null); 363 364 wct.reparent(task.token, mRootTaskInfo.token, true /* onTop*/); 365 } 366 reorderChild(int taskId, boolean onTop, WindowContainerTransaction wct)367 void reorderChild(int taskId, boolean onTop, WindowContainerTransaction wct) { 368 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "reorderChild: task=%d onTop=%b", taskId, onTop); 369 if (!containsTask(taskId)) { 370 return; 371 } 372 wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */); 373 } 374 doForAllChildTasks(Consumer<Integer> consumer)375 void doForAllChildTasks(Consumer<Integer> consumer) { 376 for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { 377 final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); 378 consumer.accept(taskInfo.taskId); 379 } 380 } 381 doForAllChildTaskInfos(Consumer<ActivityManager.RunningTaskInfo> consumer)382 void doForAllChildTaskInfos(Consumer<ActivityManager.RunningTaskInfo> consumer) { 383 for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { 384 final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); 385 consumer.accept(taskInfo); 386 } 387 } 388 389 /** Collects all the current child tasks and prepares transaction to evict them to display. */ evictAllChildren(WindowContainerTransaction wct)390 void evictAllChildren(WindowContainerTransaction wct) { 391 for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { 392 final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); 393 evictChild(wct, taskInfo, "all"); 394 } 395 } 396 evictOtherChildren(WindowContainerTransaction wct, int taskId)397 void evictOtherChildren(WindowContainerTransaction wct, int taskId) { 398 for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { 399 final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); 400 if (taskId == taskInfo.taskId) continue; 401 evictChild(wct, taskInfo, "other"); 402 } 403 } 404 evictNonOpeningChildren(RemoteAnimationTarget[] apps, WindowContainerTransaction wct)405 void evictNonOpeningChildren(RemoteAnimationTarget[] apps, WindowContainerTransaction wct) { 406 final SparseArray<ActivityManager.RunningTaskInfo> toBeEvict = mChildrenTaskInfo.clone(); 407 for (int i = 0; i < apps.length; i++) { 408 if (apps[i].mode == MODE_OPENING) { 409 toBeEvict.remove(apps[i].taskId); 410 } 411 } 412 for (int i = toBeEvict.size() - 1; i >= 0; i--) { 413 final ActivityManager.RunningTaskInfo taskInfo = toBeEvict.valueAt(i); 414 evictChild(wct, taskInfo, "non-opening"); 415 } 416 } 417 evictInvisibleChildren(WindowContainerTransaction wct)418 void evictInvisibleChildren(WindowContainerTransaction wct) { 419 for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { 420 final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); 421 if (!taskInfo.isVisible) { 422 evictChild(wct, taskInfo, "invisible"); 423 } 424 } 425 } 426 evictChild(WindowContainerTransaction wct, int taskId, String reason)427 void evictChild(WindowContainerTransaction wct, int taskId, String reason) { 428 final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.get(taskId); 429 if (taskInfo != null) { 430 evictChild(wct, taskInfo, reason); 431 } 432 } 433 evictChild(@onNull WindowContainerTransaction wct, @NonNull TaskInfo taskInfo, @NonNull String reason)434 private void evictChild(@NonNull WindowContainerTransaction wct, @NonNull TaskInfo taskInfo, 435 @NonNull String reason) { 436 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict child: task=%d reason=%s", taskInfo.taskId, 437 reason); 438 // We are reparenting the task, but not removing the task from mChildrenTaskInfo, so to 439 // prevent this task from being considered as a top task for the roots, we need to override 440 // the visibility of the soon-to-be-hidden task 441 taskInfo.isVisible = false; 442 taskInfo.isVisibleRequested = false; 443 wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); 444 } 445 reparentTopTask(WindowContainerTransaction wct)446 void reparentTopTask(WindowContainerTransaction wct) { 447 wct.reparentTasks(null /* currentParent */, mRootTaskInfo.token, 448 CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES, 449 true /* onTop */, true /* reparentTopOnly */); 450 } 451 resetBounds(WindowContainerTransaction wct)452 void resetBounds(WindowContainerTransaction wct) { 453 wct.setBounds(mRootTaskInfo.token, null); 454 wct.setAppBounds(mRootTaskInfo.token, null); 455 wct.setSmallestScreenWidthDp(mRootTaskInfo.token, SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); 456 } 457 onSplitScreenListenerRegistered(SplitScreen.SplitScreenListener listener, @StageType int stage)458 void onSplitScreenListenerRegistered(SplitScreen.SplitScreenListener listener, 459 @StageType int stage) { 460 for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { 461 int taskId = mChildrenTaskInfo.keyAt(i); 462 listener.onTaskStageChanged(taskId, stage, 463 mChildrenTaskInfo.get(taskId).isVisible); 464 } 465 } 466 467 // --------- 468 // Previously only used in MainStage isActive()469 boolean isActive() { 470 return mIsActive; 471 } 472 activate(WindowContainerTransaction wct, boolean includingTopTask)473 void activate(WindowContainerTransaction wct, boolean includingTopTask) { 474 if (mIsActive && !enableFlexibleSplit()) return; 475 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "activate: includingTopTask=%b stage=%s", 476 includingTopTask, stageTypeToString(mId)); 477 478 if (includingTopTask) { 479 reparentTopTask(wct); 480 } 481 482 if (enableFlexibleSplit()) { 483 return; 484 } 485 mIsActive = true; 486 } 487 deactivate(WindowContainerTransaction wct)488 void deactivate(WindowContainerTransaction wct) { 489 deactivate(wct, false /* toTop */); 490 } 491 deactivate(WindowContainerTransaction wct, boolean reparentTasksToTop)492 void deactivate(WindowContainerTransaction wct, boolean reparentTasksToTop) { 493 if (!mIsActive && !enableFlexibleSplit()) return; 494 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "deactivate: reparentTasksToTop=%b " 495 + "rootTaskInfo=%s stage=%s", 496 reparentTasksToTop, mRootTaskInfo, stageTypeToString(mId)); 497 if (!enableFlexibleSplit()) { 498 mIsActive = false; 499 } 500 501 if (mRootTaskInfo == null) return; 502 final WindowContainerToken rootToken = mRootTaskInfo.token; 503 wct.reparentTasks( 504 rootToken, 505 null /* newParent */, 506 null /* windowingModes */, 507 null /* activityTypes */, 508 reparentTasksToTop); 509 } 510 511 // -------- 512 // Previously only used in SideStage. With flexible split this is called for all stages removeAllTasks(WindowContainerTransaction wct, boolean toTop)513 boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) { 514 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove all side stage tasks: childCount=%d toTop=%b " 515 + " stageI=%s", 516 mChildrenTaskInfo.size(), toTop, stageTypeToString(mId)); 517 if (mChildrenTaskInfo.size() == 0) return false; 518 wct.reparentTasks( 519 mRootTaskInfo.token, 520 null /* newParent */, 521 null /* windowingModes */, 522 null /* activityTypes */, 523 toTop); 524 return true; 525 } 526 removeTask(int taskId, WindowContainerToken newParent, WindowContainerTransaction wct)527 boolean removeTask(int taskId, WindowContainerToken newParent, WindowContainerTransaction wct) { 528 final ActivityManager.RunningTaskInfo task = mChildrenTaskInfo.get(taskId); 529 ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove side stage task: task=%d exists=%b", taskId, 530 task != null); 531 if (task == null) return false; 532 wct.reparent(task.token, newParent, false /* onTop */); 533 return true; 534 } 535 536 @Override toString()537 public String toString() { 538 return "mId: " + stageTypeToString(mId) 539 + " mVisible: " + mVisible 540 + " mActive: " + mIsActive 541 + " mHasRootTask: " + mHasRootTask 542 + " childSize: " + mChildrenTaskInfo.size(); 543 } 544 545 @Override 546 @CallSuper dump(@onNull PrintWriter pw, String prefix)547 public void dump(@NonNull PrintWriter pw, String prefix) { 548 final String innerPrefix = prefix + " "; 549 final String childPrefix = innerPrefix + " "; 550 if (mChildrenTaskInfo.size() > 0) { 551 pw.println(prefix + "Children list:"); 552 for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { 553 final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); 554 pw.println(childPrefix + "Task#" + i + " taskID=" + taskInfo.taskId 555 + " baseActivity=" + taskInfo.baseActivity); 556 } 557 } 558 pw.println(prefix + "mHasRootTask=" + mHasRootTask); 559 pw.println(prefix + "mVisible=" + mVisible); 560 pw.println(prefix + "mHasChildren=" + mHasChildren); 561 } 562 } 563