1 /* 2 * Copyright (C) 2019 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.Manifest.permission.MANAGE_ACTIVITY_STACKS; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 23 24 import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS; 25 import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS; 26 27 import android.annotation.Nullable; 28 import android.app.ActivityManager; 29 import android.app.ActivityManager.RunningTaskInfo; 30 import android.app.ActivityManager.TaskDescription; 31 import android.app.WindowConfiguration; 32 import android.content.Intent; 33 import android.content.pm.ActivityInfo; 34 import android.os.Binder; 35 import android.os.IBinder; 36 import android.os.RemoteException; 37 import android.util.Slog; 38 import android.util.SparseArray; 39 import android.view.SurfaceControl; 40 import android.window.ITaskOrganizer; 41 import android.window.ITaskOrganizerController; 42 import android.window.WindowContainerToken; 43 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.internal.util.ArrayUtils; 46 47 import java.io.PrintWriter; 48 import java.util.ArrayList; 49 import java.util.HashMap; 50 import java.util.LinkedList; 51 import java.util.List; 52 import java.util.WeakHashMap; 53 import java.util.function.Consumer; 54 55 /** 56 * Stores the TaskOrganizers associated with a given windowing mode and 57 * their associated state. 58 */ 59 class TaskOrganizerController extends ITaskOrganizerController.Stub { 60 private static final String TAG = "TaskOrganizerController"; 61 private static final LinkedList<IBinder> EMPTY_LIST = new LinkedList<>(); 62 63 /** 64 * Masks specifying which configurations are important to report back to an organizer when 65 * changed. 66 */ 67 private static final int REPORT_CONFIGS = CONTROLLABLE_CONFIGS; 68 private static final int REPORT_WINDOW_CONFIGS = CONTROLLABLE_WINDOW_CONFIGS; 69 70 private final WindowManagerGlobalLock mGlobalLock; 71 72 private class DeathRecipient implements IBinder.DeathRecipient { 73 ITaskOrganizer mTaskOrganizer; 74 DeathRecipient(ITaskOrganizer organizer)75 DeathRecipient(ITaskOrganizer organizer) { 76 mTaskOrganizer = organizer; 77 } 78 79 @Override binderDied()80 public void binderDied() { 81 synchronized (mGlobalLock) { 82 final TaskOrganizerState state = mTaskOrganizerStates.remove( 83 mTaskOrganizer.asBinder()); 84 if (state != null) { 85 state.dispose(); 86 } 87 } 88 } 89 } 90 91 /** 92 * A wrapper class around ITaskOrganizer to ensure that the calls are made in the right 93 * lifecycle order since we may be updating the visibility of task surface controls in a pending 94 * transaction before they are presented to the task org. 95 */ 96 private class TaskOrganizerCallbacks { 97 final WindowManagerService mService; 98 final ITaskOrganizer mTaskOrganizer; 99 final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer; 100 101 private final SurfaceControl.Transaction mTransaction; 102 TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg, Consumer<Runnable> deferTaskOrgCallbacksConsumer)103 TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg, 104 Consumer<Runnable> deferTaskOrgCallbacksConsumer) { 105 mService = wm; 106 mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer; 107 mTaskOrganizer = taskOrg; 108 mTransaction = wm.mTransactionFactory.get(); 109 } 110 getBinder()111 IBinder getBinder() { 112 return mTaskOrganizer.asBinder(); 113 } 114 onTaskAppeared(Task task)115 void onTaskAppeared(Task task) { 116 final boolean visible = task.isVisible(); 117 final RunningTaskInfo taskInfo = task.getTaskInfo(); 118 mDeferTaskOrgCallbacksConsumer.accept(() -> { 119 try { 120 SurfaceControl outSurfaceControl = new SurfaceControl(task.getSurfaceControl(), 121 "TaskOrganizerController.onTaskAppeared"); 122 if (!task.mCreatedByOrganizer && !visible) { 123 // To prevent flashes, we hide the task prior to sending the leash to the 124 // task org if the task has previously hidden (ie. when entering PIP) 125 mTransaction.hide(outSurfaceControl); 126 mTransaction.apply(); 127 } 128 mTaskOrganizer.onTaskAppeared(taskInfo, outSurfaceControl); 129 } catch (RemoteException e) { 130 Slog.e(TAG, "Exception sending onTaskAppeared callback", e); 131 } 132 }); 133 } 134 135 onTaskVanished(Task task)136 void onTaskVanished(Task task) { 137 final RunningTaskInfo taskInfo = task.getTaskInfo(); 138 mDeferTaskOrgCallbacksConsumer.accept(() -> { 139 try { 140 mTaskOrganizer.onTaskVanished(taskInfo); 141 } catch (RemoteException e) { 142 Slog.e(TAG, "Exception sending onTaskVanished callback", e); 143 } 144 }); 145 } 146 onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo)147 void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) { 148 if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) { 149 // Skip if the task has not yet received taskAppeared(), except for tasks created 150 // by the organizer that don't receive that signal 151 return; 152 } 153 mDeferTaskOrgCallbacksConsumer.accept(() -> { 154 if (!task.isOrganized()) { 155 // This is safe to ignore if the task is no longer organized 156 return; 157 } 158 try { 159 mTaskOrganizer.onTaskInfoChanged(taskInfo); 160 } catch (RemoteException e) { 161 Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e); 162 } 163 }); 164 } 165 onBackPressedOnTaskRoot(Task task)166 void onBackPressedOnTaskRoot(Task task) { 167 if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) { 168 // Skip if the task has not yet received taskAppeared(), except for tasks created 169 // by the organizer that don't receive that signal 170 return; 171 } 172 mDeferTaskOrgCallbacksConsumer.accept(() -> { 173 if (!task.isOrganized()) { 174 // This is safe to ignore if the task is no longer organized 175 return; 176 } 177 try { 178 mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo()); 179 } catch (Exception e) { 180 Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e); 181 } 182 }); 183 } 184 } 185 186 private class TaskOrganizerState { 187 private final TaskOrganizerCallbacks mOrganizer; 188 private final DeathRecipient mDeathRecipient; 189 private final ArrayList<Task> mOrganizedTasks = new ArrayList<>(); 190 private final int mUid; 191 private boolean mInterceptBackPressedOnTaskRoot; 192 TaskOrganizerState(ITaskOrganizer organizer, int uid)193 TaskOrganizerState(ITaskOrganizer organizer, int uid) { 194 final Consumer<Runnable> deferTaskOrgCallbacksConsumer = 195 mDeferTaskOrgCallbacksConsumer != null 196 ? mDeferTaskOrgCallbacksConsumer 197 : mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable; 198 mOrganizer = new TaskOrganizerCallbacks(mService.mWindowManager, organizer, 199 deferTaskOrgCallbacksConsumer); 200 mDeathRecipient = new DeathRecipient(organizer); 201 try { 202 organizer.asBinder().linkToDeath(mDeathRecipient, 0); 203 } catch (RemoteException e) { 204 Slog.e(TAG, "TaskOrganizer failed to register death recipient"); 205 } 206 mUid = uid; 207 } 208 setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed)209 void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) { 210 mInterceptBackPressedOnTaskRoot = interceptBackPressed; 211 } 212 addTask(Task t)213 void addTask(Task t) { 214 if (t.mTaskAppearedSent) return; 215 216 if (!mOrganizedTasks.contains(t)) { 217 mOrganizedTasks.add(t); 218 } 219 if (t.taskAppearedReady()) { 220 t.mTaskAppearedSent = true; 221 mOrganizer.onTaskAppeared(t); 222 } 223 } 224 removeTask(Task t)225 void removeTask(Task t) { 226 if (t.mTaskAppearedSent) { 227 t.migrateToNewSurfaceControl(); 228 t.mTaskAppearedSent = false; 229 mOrganizer.onTaskVanished(t); 230 } 231 mOrganizedTasks.remove(t); 232 } 233 dispose()234 void dispose() { 235 // Move organizer from managing specific windowing modes 236 for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) { 237 mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder()); 238 } 239 240 // Update tasks currently managed by this organizer to the next one available if 241 // possible. 242 while (!mOrganizedTasks.isEmpty()) { 243 final Task t = mOrganizedTasks.get(0); 244 t.updateTaskOrganizerState(true /* forceUpdate */); 245 if (mOrganizedTasks.contains(t)) { 246 removeTask(t); 247 } 248 } 249 250 // Remove organizer state after removing tasks so we get a chance to send 251 // onTaskVanished. 252 mTaskOrganizerStates.remove(asBinder()); 253 } 254 unlinkDeath()255 void unlinkDeath() { 256 mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0); 257 } 258 } 259 260 private final SparseArray<LinkedList<IBinder>> mTaskOrganizersForWindowingMode = 261 new SparseArray<>(); 262 private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>(); 263 private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>(); 264 private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>(); 265 266 private final ActivityTaskManagerService mService; 267 268 private RunningTaskInfo mTmpTaskInfo; 269 private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer; 270 TaskOrganizerController(ActivityTaskManagerService atm)271 TaskOrganizerController(ActivityTaskManagerService atm) { 272 mService = atm; 273 mGlobalLock = atm.mGlobalLock; 274 } 275 enforceStackPermission(String func)276 private void enforceStackPermission(String func) { 277 mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func); 278 } 279 280 /** 281 * Specifies the consumer to run to defer the task org callbacks. Can be overridden while 282 * testing to allow the callbacks to be sent synchronously. 283 */ 284 @VisibleForTesting setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer)285 public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) { 286 mDeferTaskOrgCallbacksConsumer = consumer; 287 } 288 289 /** 290 * Register a TaskOrganizer to manage tasks as they enter the given windowing mode. 291 * If there was already a TaskOrganizer for this windowing mode it will be evicted 292 * but will continue to organize it's existing tasks. 293 */ 294 @Override registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode)295 public void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) { 296 if (windowingMode == WINDOWING_MODE_PINNED) { 297 if (!mService.mSupportsPictureInPicture) { 298 throw new UnsupportedOperationException("Picture in picture is not supported on " 299 + "this device"); 300 } 301 } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) { 302 if (!mService.mSupportsSplitScreenMultiWindow) { 303 throw new UnsupportedOperationException("Split-screen is not supported on this " 304 + "device"); 305 } 306 } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) { 307 if (!mService.mSupportsMultiWindow) { 308 throw new UnsupportedOperationException("Multi-window is not supported on this " 309 + "device"); 310 } 311 } else { 312 throw new UnsupportedOperationException("As of now only Pinned/Split/Multiwindow" 313 + " windowing modes are supported for registerTaskOrganizer"); 314 } 315 enforceStackPermission("registerTaskOrganizer()"); 316 final int uid = Binder.getCallingUid(); 317 final long origId = Binder.clearCallingIdentity(); 318 try { 319 synchronized (mGlobalLock) { 320 if (getTaskOrganizer(windowingMode) != null) { 321 Slog.w(TAG, "Task organizer already exists for windowing mode: " 322 + windowingMode); 323 } 324 325 LinkedList<IBinder> orgs = mTaskOrganizersForWindowingMode.get(windowingMode); 326 if (orgs == null) { 327 orgs = new LinkedList<>(); 328 mTaskOrganizersForWindowingMode.put(windowingMode, orgs); 329 } 330 orgs.add(organizer.asBinder()); 331 if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) { 332 mTaskOrganizerStates.put(organizer.asBinder(), 333 new TaskOrganizerState(organizer, uid)); 334 } 335 336 mService.mRootWindowContainer.forAllTasks((task) -> { 337 if (task.getWindowingMode() == windowingMode) { 338 task.updateTaskOrganizerState(true /* forceUpdate */); 339 } 340 }); 341 } 342 } finally { 343 Binder.restoreCallingIdentity(origId); 344 } 345 } 346 347 @Override unregisterTaskOrganizer(ITaskOrganizer organizer)348 public void unregisterTaskOrganizer(ITaskOrganizer organizer) { 349 enforceStackPermission("unregisterTaskOrganizer()"); 350 final long origId = Binder.clearCallingIdentity(); 351 try { 352 synchronized (mGlobalLock) { 353 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); 354 if (state == null) { 355 return; 356 } 357 state.unlinkDeath(); 358 state.dispose(); 359 } 360 } finally { 361 Binder.restoreCallingIdentity(origId); 362 } 363 } 364 getTaskOrganizer(int windowingMode)365 ITaskOrganizer getTaskOrganizer(int windowingMode) { 366 final IBinder organizer = 367 mTaskOrganizersForWindowingMode.get(windowingMode, EMPTY_LIST).peekLast(); 368 if (organizer == null) { 369 return null; 370 } 371 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer); 372 if (state == null) { 373 return null; 374 } 375 return state.mOrganizer.mTaskOrganizer; 376 } 377 onTaskAppeared(ITaskOrganizer organizer, Task task)378 void onTaskAppeared(ITaskOrganizer organizer, Task task) { 379 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); 380 state.addTask(task); 381 } 382 onTaskVanished(ITaskOrganizer organizer, Task task)383 void onTaskVanished(ITaskOrganizer organizer, Task task) { 384 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); 385 if (state != null) { 386 state.removeTask(task); 387 } 388 } 389 390 @Override createRootTask(int displayId, int windowingMode)391 public RunningTaskInfo createRootTask(int displayId, int windowingMode) { 392 enforceStackPermission("createRootTask()"); 393 final long origId = Binder.clearCallingIdentity(); 394 try { 395 synchronized (mGlobalLock) { 396 DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId); 397 if (display == null) { 398 return null; 399 } 400 401 final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode, 402 ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(), 403 true /* createdByOrganizer */); 404 RunningTaskInfo out = task.getTaskInfo(); 405 mLastSentTaskInfos.put(task, out); 406 return out; 407 } 408 } finally { 409 Binder.restoreCallingIdentity(origId); 410 } 411 } 412 413 @Override deleteRootTask(WindowContainerToken token)414 public boolean deleteRootTask(WindowContainerToken token) { 415 enforceStackPermission("deleteRootTask()"); 416 final long origId = Binder.clearCallingIdentity(); 417 try { 418 synchronized (mGlobalLock) { 419 final Task task = WindowContainer.fromBinder(token.asBinder()).asTask(); 420 if (task == null) return false; 421 if (!task.mCreatedByOrganizer) { 422 throw new IllegalArgumentException( 423 "Attempt to delete task not created by organizer task=" + task); 424 } 425 task.removeImmediately(); 426 return true; 427 } 428 } finally { 429 Binder.restoreCallingIdentity(origId); 430 } 431 } 432 dispatchPendingTaskInfoChanges()433 void dispatchPendingTaskInfoChanges() { 434 if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) { 435 return; 436 } 437 for (int i = 0, n = mPendingTaskInfoChanges.size(); i < n; ++i) { 438 dispatchTaskInfoChanged(mPendingTaskInfoChanges.get(i), false /* force */); 439 } 440 mPendingTaskInfoChanges.clear(); 441 } 442 dispatchTaskInfoChanged(Task task, boolean force)443 void dispatchTaskInfoChanged(Task task, boolean force) { 444 if (!force && mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) { 445 // Defer task info reporting while layout is deferred. This is because layout defer 446 // blocks tend to do lots of re-ordering which can mess up animations in receivers. 447 mPendingTaskInfoChanges.remove(task); 448 mPendingTaskInfoChanges.add(task); 449 return; 450 } 451 RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task); 452 if (mTmpTaskInfo == null) { 453 mTmpTaskInfo = new RunningTaskInfo(); 454 } 455 mTmpTaskInfo.configuration.unset(); 456 task.fillTaskInfo(mTmpTaskInfo); 457 boolean changed = lastInfo == null 458 || mTmpTaskInfo.topActivityType != lastInfo.topActivityType 459 || mTmpTaskInfo.isResizeable != lastInfo.isResizeable 460 || mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams 461 || !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription) 462 || mTmpTaskInfo.requestedOrientation != lastInfo.requestedOrientation; 463 if (!changed) { 464 int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration); 465 final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0 466 ? (int) mTmpTaskInfo.configuration.windowConfiguration.diff( 467 lastInfo.configuration.windowConfiguration, 468 true /* compareUndefined */) : 0; 469 if ((winCfgChanges & REPORT_WINDOW_CONFIGS) == 0) { 470 cfgChanges &= ~ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 471 } 472 changed = (cfgChanges & REPORT_CONFIGS) != 0; 473 } 474 if (!(changed || force)) { 475 return; 476 } 477 final RunningTaskInfo newInfo = mTmpTaskInfo; 478 mLastSentTaskInfos.put(task, mTmpTaskInfo); 479 // Since we've stored this, clean up the reference so a new one will be created next time. 480 // Transferring it this way means we only have to construct new RunningTaskInfos when they 481 // change. 482 mTmpTaskInfo = null; 483 484 if (task.isOrganized()) { 485 // Because we defer sending taskAppeared() until the app has drawn, we may receive a 486 // configuration change before the state actually has the task registered. As such we 487 // should ignore these change events to the organizer until taskAppeared(). If the task 488 // was created by the organizer, then we always send the info change. 489 final TaskOrganizerState state = mTaskOrganizerStates.get( 490 task.mTaskOrganizer.asBinder()); 491 if (state != null) { 492 state.mOrganizer.onTaskInfoChanged(task, newInfo); 493 } 494 } 495 } 496 497 @Override getImeTarget(int displayId)498 public WindowContainerToken getImeTarget(int displayId) { 499 enforceStackPermission("getImeTarget()"); 500 final long origId = Binder.clearCallingIdentity(); 501 try { 502 synchronized (mGlobalLock) { 503 DisplayContent dc = mService.mWindowManager.mRoot 504 .getDisplayContent(displayId); 505 if (dc == null || dc.mInputMethodTarget == null) { 506 return null; 507 } 508 // Avoid WindowState#getRootTask() so we don't attribute system windows to a task. 509 final Task task = dc.mInputMethodTarget.getTask(); 510 if (task == null) { 511 return null; 512 } 513 return task.getRootTask().mRemoteToken.toWindowContainerToken(); 514 } 515 } finally { 516 Binder.restoreCallingIdentity(origId); 517 } 518 } 519 520 @Override setLaunchRoot(int displayId, @Nullable WindowContainerToken token)521 public void setLaunchRoot(int displayId, @Nullable WindowContainerToken token) { 522 enforceStackPermission("setLaunchRoot()"); 523 final long origId = Binder.clearCallingIdentity(); 524 try { 525 synchronized (mGlobalLock) { 526 TaskDisplayArea defaultTaskDisplayArea = mService.mRootWindowContainer 527 .getDisplayContent(displayId).getDefaultTaskDisplayArea(); 528 if (defaultTaskDisplayArea == null) { 529 return; 530 } 531 Task task = token == null 532 ? null : WindowContainer.fromBinder(token.asBinder()).asTask(); 533 if (task == null) { 534 defaultTaskDisplayArea.mLaunchRootTask = null; 535 return; 536 } 537 if (!task.mCreatedByOrganizer) { 538 throw new IllegalArgumentException("Attempt to set task not created by " 539 + "organizer as launch root task=" + task); 540 } 541 if (task.getDisplayArea() == null 542 || task.getDisplayArea().getDisplayId() != displayId) { 543 throw new RuntimeException("Can't set launch root for display " + displayId 544 + " to task on display " + task.getDisplayContent().getDisplayId()); 545 } 546 task.getDisplayArea().mLaunchRootTask = task; 547 } 548 } finally { 549 Binder.restoreCallingIdentity(origId); 550 } 551 } 552 553 @Override getChildTasks(WindowContainerToken parent, @Nullable int[] activityTypes)554 public List<RunningTaskInfo> getChildTasks(WindowContainerToken parent, 555 @Nullable int[] activityTypes) { 556 enforceStackPermission("getChildTasks()"); 557 final long ident = Binder.clearCallingIdentity(); 558 try { 559 synchronized (mGlobalLock) { 560 if (parent == null) { 561 throw new IllegalArgumentException("Can't get children of null parent"); 562 } 563 final WindowContainer container = WindowContainer.fromBinder(parent.asBinder()); 564 if (container == null) { 565 Slog.e(TAG, "Can't get children of " + parent + " because it is not valid."); 566 return null; 567 } 568 final Task task = container.asTask(); 569 if (task == null) { 570 Slog.e(TAG, container + " is not a task..."); 571 return null; 572 } 573 // For now, only support returning children of tasks created by the organizer. 574 if (!task.mCreatedByOrganizer) { 575 Slog.w(TAG, "Can only get children of root tasks created via createRootTask"); 576 return null; 577 } 578 ArrayList<RunningTaskInfo> out = new ArrayList<>(); 579 for (int i = task.getChildCount() - 1; i >= 0; --i) { 580 final Task child = task.getChildAt(i).asTask(); 581 if (child == null) continue; 582 if (activityTypes != null 583 && !ArrayUtils.contains(activityTypes, child.getActivityType())) { 584 continue; 585 } 586 out.add(child.getTaskInfo()); 587 } 588 return out; 589 } 590 } finally { 591 Binder.restoreCallingIdentity(ident); 592 } 593 } 594 595 @Override getRootTasks(int displayId, @Nullable int[] activityTypes)596 public List<RunningTaskInfo> getRootTasks(int displayId, @Nullable int[] activityTypes) { 597 enforceStackPermission("getRootTasks()"); 598 final long ident = Binder.clearCallingIdentity(); 599 try { 600 synchronized (mGlobalLock) { 601 final DisplayContent dc = 602 mService.mRootWindowContainer.getDisplayContent(displayId); 603 if (dc == null) { 604 throw new IllegalArgumentException("Display " + displayId + " doesn't exist"); 605 } 606 ArrayList<RunningTaskInfo> out = new ArrayList<>(); 607 for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { 608 final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); 609 for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { 610 final Task task = taskDisplayArea.getStackAt(sNdx); 611 if (activityTypes != null 612 && !ArrayUtils.contains(activityTypes, task.getActivityType())) { 613 continue; 614 } 615 out.add(task.getTaskInfo()); 616 } 617 } 618 return out; 619 } 620 } finally { 621 Binder.restoreCallingIdentity(ident); 622 } 623 } 624 625 @Override setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer, boolean interceptBackPressed)626 public void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer, 627 boolean interceptBackPressed) { 628 enforceStackPermission("setInterceptBackPressedOnTaskRoot()"); 629 final long origId = Binder.clearCallingIdentity(); 630 try { 631 synchronized (mGlobalLock) { 632 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); 633 if (state != null) { 634 state.setInterceptBackPressedOnTaskRoot(interceptBackPressed); 635 } 636 } 637 } finally { 638 Binder.restoreCallingIdentity(origId); 639 } 640 } 641 handleInterceptBackPressedOnTaskRoot(Task task)642 public boolean handleInterceptBackPressedOnTaskRoot(Task task) { 643 if (task == null || !task.isOrganized()) { 644 return false; 645 } 646 647 final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder()); 648 if (!state.mInterceptBackPressedOnTaskRoot) { 649 return false; 650 } 651 652 state.mOrganizer.onBackPressedOnTaskRoot(task); 653 return true; 654 } 655 dump(PrintWriter pw, String prefix)656 public void dump(PrintWriter pw, String prefix) { 657 final String innerPrefix = prefix + " "; 658 pw.print(prefix); pw.println("TaskOrganizerController:"); 659 pw.print(innerPrefix); pw.println("Per windowing mode:"); 660 for (int i = 0; i < mTaskOrganizersForWindowingMode.size(); i++) { 661 final int windowingMode = mTaskOrganizersForWindowingMode.keyAt(i); 662 final List<IBinder> taskOrgs = mTaskOrganizersForWindowingMode.valueAt(i); 663 pw.println(innerPrefix + " " 664 + WindowConfiguration.windowingModeToString(windowingMode) + ":"); 665 for (int j = 0; j < taskOrgs.size(); j++) { 666 final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j)); 667 final ArrayList<Task> tasks = state.mOrganizedTasks; 668 pw.print(innerPrefix + " "); 669 pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":"); 670 for (int k = 0; k < tasks.size(); k++) { 671 pw.println(innerPrefix + " " + tasks.get(k)); 672 } 673 } 674 675 } 676 pw.println(); 677 } 678 } 679