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.app.TaskInfo.cameraCompatControlStateToString; 20 21 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; 22 import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission; 23 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; 24 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL; 25 import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer; 26 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.app.ActivityManager; 30 import android.app.ActivityManager.RunningTaskInfo; 31 import android.app.WindowConfiguration; 32 import android.content.Intent; 33 import android.content.pm.ParceledListSlice; 34 import android.graphics.Rect; 35 import android.os.Binder; 36 import android.os.IBinder; 37 import android.os.Parcel; 38 import android.os.RemoteException; 39 import android.util.ArrayMap; 40 import android.util.Slog; 41 import android.util.proto.ProtoOutputStream; 42 import android.view.Display; 43 import android.view.SurfaceControl; 44 import android.window.ITaskOrganizer; 45 import android.window.ITaskOrganizerController; 46 import android.window.SplashScreenView; 47 import android.window.StartingWindowInfo; 48 import android.window.StartingWindowRemovalInfo; 49 import android.window.TaskAppearedInfo; 50 import android.window.TaskSnapshot; 51 import android.window.WindowContainerToken; 52 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.internal.protolog.common.ProtoLog; 55 import com.android.internal.util.ArrayUtils; 56 57 import java.io.PrintWriter; 58 import java.util.ArrayList; 59 import java.util.HashSet; 60 import java.util.LinkedList; 61 import java.util.List; 62 import java.util.WeakHashMap; 63 import java.util.function.Consumer; 64 65 /** 66 * Stores the TaskOrganizers associated with a given windowing mode and 67 * their associated state. 68 */ 69 class TaskOrganizerController extends ITaskOrganizerController.Stub { 70 private static final String TAG = "TaskOrganizerController"; 71 72 @VisibleForTesting 73 class DeathRecipient implements IBinder.DeathRecipient { 74 ITaskOrganizer mTaskOrganizer; 75 DeathRecipient(ITaskOrganizer organizer)76 DeathRecipient(ITaskOrganizer organizer) { 77 mTaskOrganizer = organizer; 78 } 79 80 @Override binderDied()81 public void binderDied() { 82 synchronized (mGlobalLock) { 83 final TaskOrganizerState state = mTaskOrganizerStates.get( 84 mTaskOrganizer.asBinder()); 85 if (state != null) { 86 state.dispose(); 87 } 88 } 89 } 90 } 91 92 /** 93 * A wrapper class around ITaskOrganizer to ensure that the calls are made in the right 94 * lifecycle order since we may be updating the visibility of task surface controls in a pending 95 * transaction before they are presented to the task org. 96 */ 97 private static class TaskOrganizerCallbacks { 98 final ITaskOrganizer mTaskOrganizer; 99 final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer; 100 TaskOrganizerCallbacks(ITaskOrganizer taskOrg, Consumer<Runnable> deferTaskOrgCallbacksConsumer)101 TaskOrganizerCallbacks(ITaskOrganizer taskOrg, 102 Consumer<Runnable> deferTaskOrgCallbacksConsumer) { 103 mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer; 104 mTaskOrganizer = taskOrg; 105 } 106 getBinder()107 IBinder getBinder() { 108 return mTaskOrganizer.asBinder(); 109 } 110 prepareLeash(Task task, String reason)111 SurfaceControl prepareLeash(Task task, String reason) { 112 return new SurfaceControl(task.getSurfaceControl(), reason); 113 } 114 onTaskAppeared(Task task)115 void onTaskAppeared(Task task) { 116 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId); 117 final RunningTaskInfo taskInfo = task.getTaskInfo(); 118 try { 119 mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, 120 "TaskOrganizerController.onTaskAppeared")); 121 } catch (RemoteException e) { 122 Slog.e(TAG, "Exception sending onTaskAppeared callback", e); 123 } 124 } 125 onTaskVanished(Task task)126 void onTaskVanished(Task task) { 127 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId); 128 final RunningTaskInfo taskInfo = task.getTaskInfo(); 129 try { 130 mTaskOrganizer.onTaskVanished(taskInfo); 131 } catch (RemoteException e) { 132 Slog.e(TAG, "Exception sending onTaskVanished callback", e); 133 } 134 } 135 onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo)136 void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) { 137 if (!task.mTaskAppearedSent) { 138 // Skip if the task has not yet received taskAppeared(). 139 return; 140 } 141 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId); 142 if (!task.isOrganized()) { 143 // This is safe to ignore if the task is no longer organized 144 return; 145 } 146 try { 147 // Purposely notify of task info change immediately instead of deferring (like 148 // appear and vanish) to allow info changes (such as new PIP params) to flow 149 // without waiting. 150 mTaskOrganizer.onTaskInfoChanged(taskInfo); 151 } catch (RemoteException e) { 152 Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e); 153 } 154 } 155 onBackPressedOnTaskRoot(Task task)156 void onBackPressedOnTaskRoot(Task task) { 157 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task back pressed on root taskId=%d", 158 task.mTaskId); 159 if (!task.mTaskAppearedSent) { 160 // Skip if the task has not yet received taskAppeared(). 161 return; 162 } 163 if (!task.isOrganized()) { 164 // This is safe to ignore if the task is no longer organized 165 return; 166 } 167 try { 168 mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo()); 169 } catch (Exception e) { 170 Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e); 171 } 172 } 173 } 174 175 /** 176 * Maintains a list of all the pending events for a given {@link android.window.TaskOrganizer} 177 */ 178 static final class TaskOrganizerPendingEventsQueue { 179 private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>(); 180 private final TaskOrganizerState mOrganizerState; 181 private RunningTaskInfo mTmpTaskInfo; 182 // Pending task events due to layout deferred. 183 private final ArrayList<PendingTaskEvent> mPendingTaskEvents = new ArrayList<>(); 184 TaskOrganizerPendingEventsQueue(TaskOrganizerState taskOrganizerState)185 TaskOrganizerPendingEventsQueue(TaskOrganizerState taskOrganizerState) { 186 mOrganizerState = taskOrganizerState; 187 } 188 189 @VisibleForTesting getPendingEventList()190 public ArrayList<PendingTaskEvent> getPendingEventList() { 191 return mPendingTaskEvents; 192 } 193 numPendingTaskEvents()194 int numPendingTaskEvents() { 195 return mPendingTaskEvents.size(); 196 } 197 clearPendingTaskEvents()198 void clearPendingTaskEvents() { 199 mPendingTaskEvents.clear(); 200 } 201 addPendingTaskEvent(PendingTaskEvent event)202 void addPendingTaskEvent(PendingTaskEvent event) { 203 mPendingTaskEvents.add(event); 204 } 205 removePendingTaskEvent(PendingTaskEvent event)206 void removePendingTaskEvent(PendingTaskEvent event) { 207 mPendingTaskEvents.remove(event); 208 } 209 210 /** 211 * Removes all the pending task events for the given {@code task}. 212 * 213 * @param task 214 * @return true if a {@link PendingTaskEvent#EVENT_APPEARED} is still pending for the given 215 * {code task}. 216 */ removePendingTaskEvents(Task task)217 boolean removePendingTaskEvents(Task task) { 218 boolean foundPendingAppearedEvents = false; 219 for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) { 220 PendingTaskEvent entry = mPendingTaskEvents.get(i); 221 if (task.mTaskId == entry.mTask.mTaskId) { 222 // This task is vanished so remove all pending event of it. 223 mPendingTaskEvents.remove(i); 224 225 if (entry.mEventType == PendingTaskEvent.EVENT_APPEARED) { 226 foundPendingAppearedEvents = true; 227 } 228 } 229 } 230 return foundPendingAppearedEvents; 231 } 232 233 @Nullable getPendingTaskEvent(Task task, int type)234 private PendingTaskEvent getPendingTaskEvent(Task task, int type) { 235 for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) { 236 PendingTaskEvent entry = mPendingTaskEvents.get(i); 237 if (task.mTaskId == entry.mTask.mTaskId && type == entry.mEventType) { 238 return entry; 239 } 240 } 241 return null; 242 } 243 244 @VisibleForTesting 245 @Nullable getPendingLifecycleTaskEvent(Task task)246 PendingTaskEvent getPendingLifecycleTaskEvent(Task task) { 247 for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) { 248 PendingTaskEvent entry = mPendingTaskEvents.get(i); 249 if (task.mTaskId == entry.mTask.mTaskId && entry.isLifecycleEvent()) { 250 return entry; 251 } 252 } 253 return null; 254 } 255 dispatchPendingEvents()256 void dispatchPendingEvents() { 257 if (mPendingTaskEvents.isEmpty()) { 258 return; 259 } 260 for (int i = 0, n = mPendingTaskEvents.size(); i < n; i++) { 261 dispatchPendingEvent(mPendingTaskEvents.get(i)); 262 } 263 mPendingTaskEvents.clear(); 264 } 265 dispatchPendingEvent(PendingTaskEvent event)266 private void dispatchPendingEvent(PendingTaskEvent event) { 267 final Task task = event.mTask; 268 switch (event.mEventType) { 269 case PendingTaskEvent.EVENT_APPEARED: 270 if (task.taskAppearedReady()) { 271 mOrganizerState.mOrganizer.onTaskAppeared(task); 272 } 273 break; 274 case PendingTaskEvent.EVENT_VANISHED: 275 mOrganizerState.mOrganizer.onTaskVanished(task); 276 mLastSentTaskInfos.remove(task); 277 break; 278 case PendingTaskEvent.EVENT_INFO_CHANGED: 279 dispatchTaskInfoChanged(event.mTask, event.mForce); 280 break; 281 case PendingTaskEvent.EVENT_ROOT_BACK_PRESSED: 282 mOrganizerState.mOrganizer.onBackPressedOnTaskRoot(task); 283 break; 284 } 285 } 286 dispatchTaskInfoChanged(Task task, boolean force)287 private void dispatchTaskInfoChanged(Task task, boolean force) { 288 RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task); 289 if (mTmpTaskInfo == null) { 290 mTmpTaskInfo = new RunningTaskInfo(); 291 } 292 mTmpTaskInfo.configuration.unset(); 293 task.fillTaskInfo(mTmpTaskInfo); 294 295 boolean changed = !mTmpTaskInfo 296 .equalsForTaskOrganizer(lastInfo) 297 || !configurationsAreEqualForOrganizer( 298 mTmpTaskInfo.configuration, 299 lastInfo.configuration); 300 if (!(changed || force)) { 301 // mTmpTaskInfo will be reused next time. 302 return; 303 } 304 final RunningTaskInfo newInfo = mTmpTaskInfo; 305 mLastSentTaskInfos.put(task, 306 mTmpTaskInfo); 307 // Since we've stored this, clean up the reference so a new one will be created next 308 // time. 309 // Transferring it this way means we only have to construct new RunningTaskInfos when 310 // they change. 311 mTmpTaskInfo = null; 312 313 if (task.isOrganized()) { 314 // Because we defer sending taskAppeared() until the app has drawn, we may receive a 315 // configuration change before the state actually has the task registered. As such 316 // we should ignore these change events to the organizer until taskAppeared(). If 317 // the task was created by the organizer, then we always send the info change. 318 mOrganizerState.mOrganizer.onTaskInfoChanged(task, newInfo); 319 } 320 } 321 } 322 323 @VisibleForTesting 324 class TaskOrganizerState { 325 private final TaskOrganizerCallbacks mOrganizer; 326 private final DeathRecipient mDeathRecipient; 327 private final ArrayList<Task> mOrganizedTasks = new ArrayList<>(); 328 private final TaskOrganizerPendingEventsQueue mPendingEventsQueue; 329 private final int mUid; 330 TaskOrganizerState(ITaskOrganizer organizer, int uid)331 TaskOrganizerState(ITaskOrganizer organizer, int uid) { 332 final Consumer<Runnable> deferTaskOrgCallbacksConsumer = 333 mDeferTaskOrgCallbacksConsumer != null 334 ? mDeferTaskOrgCallbacksConsumer 335 : mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable; 336 mOrganizer = new TaskOrganizerCallbacks(organizer, deferTaskOrgCallbacksConsumer); 337 mDeathRecipient = new DeathRecipient(organizer); 338 mPendingEventsQueue = new TaskOrganizerPendingEventsQueue(this); 339 try { 340 organizer.asBinder().linkToDeath(mDeathRecipient, 0); 341 } catch (RemoteException e) { 342 Slog.e(TAG, "TaskOrganizer failed to register death recipient"); 343 } 344 mUid = uid; 345 } 346 347 @VisibleForTesting getDeathRecipient()348 DeathRecipient getDeathRecipient() { 349 return mDeathRecipient; 350 } 351 352 @VisibleForTesting getPendingEventsQueue()353 TaskOrganizerPendingEventsQueue getPendingEventsQueue() { 354 return mPendingEventsQueue; 355 } 356 357 /** 358 * Register this task with this state, but doesn't trigger the task appeared callback to 359 * the organizer. 360 */ addTaskWithoutCallback(Task t, String reason)361 SurfaceControl addTaskWithoutCallback(Task t, String reason) { 362 t.mTaskAppearedSent = true; 363 if (!mOrganizedTasks.contains(t)) { 364 mOrganizedTasks.add(t); 365 } 366 return mOrganizer.prepareLeash(t, reason); 367 } 368 addTask(Task t)369 private boolean addTask(Task t) { 370 if (t.mTaskAppearedSent) { 371 return false; 372 } 373 374 if (!mOrganizedTasks.contains(t)) { 375 mOrganizedTasks.add(t); 376 } 377 378 if (t.taskAppearedReady()) { 379 t.mTaskAppearedSent = true; 380 return true; 381 } 382 return false; 383 } 384 removeTask(Task t, boolean removeFromSystem)385 private boolean removeTask(Task t, boolean removeFromSystem) { 386 mOrganizedTasks.remove(t); 387 mInterceptBackPressedOnRootTasks.remove(t.mTaskId); 388 boolean taskAppearedSent = t.mTaskAppearedSent; 389 if (taskAppearedSent) { 390 if (t.getSurfaceControl() != null) { 391 t.migrateToNewSurfaceControl(t.getSyncTransaction()); 392 } 393 t.mTaskAppearedSent = false; 394 } 395 if (removeFromSystem) { 396 mService.removeTask(t.mTaskId); 397 } 398 return taskAppearedSent; 399 } 400 dispose()401 void dispose() { 402 // Move organizer from managing specific windowing modes 403 mTaskOrganizers.remove(mOrganizer.mTaskOrganizer); 404 405 // Update tasks currently managed by this organizer to the next one available if 406 // possible. 407 while (!mOrganizedTasks.isEmpty()) { 408 final Task t = mOrganizedTasks.get(0); 409 if (t.mCreatedByOrganizer) { 410 // The tasks created by this organizer should ideally be deleted when this 411 // organizer is disposed off to avoid inconsistent behavior. 412 t.removeImmediately(); 413 } else { 414 t.updateTaskOrganizerState(); 415 } 416 if (mOrganizedTasks.contains(t)) { 417 // updateTaskOrganizerState should remove the task from the list, but still 418 // check it again to avoid while-loop isn't terminate. 419 if (removeTask(t, t.mRemoveWithTaskOrganizer)) { 420 TaskOrganizerController.this.onTaskVanishedInternal(this, t); 421 } 422 } 423 if (mService.getTransitionController().isShellTransitionsEnabled()) { 424 // dispose is only called outside of transitions (eg during unregister). Since 425 // we "migrate" surfaces when replacing organizers, visibility gets delegated 426 // to transitions; however, since there is no transition at this point, we have 427 // to manually show the surface here. 428 if (t.mTaskOrganizer != null && t.getSurfaceControl() != null) { 429 t.getSyncTransaction().show(t.getSurfaceControl()); 430 } 431 } 432 } 433 434 // Pending events queue for this organizer need to be cleared because this organizer 435 // has either died or unregistered itself. 436 mPendingEventsQueue.clearPendingTaskEvents(); 437 mTaskOrganizerStates.remove(mOrganizer.getBinder()); 438 } 439 unlinkDeath()440 void unlinkDeath() { 441 mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0); 442 } 443 } 444 445 static class PendingTaskEvent { 446 static final int EVENT_APPEARED = 0; 447 static final int EVENT_VANISHED = 1; 448 static final int EVENT_INFO_CHANGED = 2; 449 static final int EVENT_ROOT_BACK_PRESSED = 3; 450 451 final int mEventType; 452 final Task mTask; 453 final ITaskOrganizer mTaskOrg; 454 boolean mForce; 455 PendingTaskEvent(Task task, int event)456 PendingTaskEvent(Task task, int event) { 457 this(task, task.mTaskOrganizer, event); 458 } 459 PendingTaskEvent(Task task, ITaskOrganizer taskOrg, int eventType)460 PendingTaskEvent(Task task, ITaskOrganizer taskOrg, int eventType) { 461 mTask = task; 462 mTaskOrg = taskOrg; 463 mEventType = eventType; 464 } 465 isLifecycleEvent()466 boolean isLifecycleEvent() { 467 return mEventType == EVENT_APPEARED || mEventType == EVENT_VANISHED 468 || mEventType == EVENT_INFO_CHANGED; 469 } 470 } 471 472 private final ActivityTaskManagerService mService; 473 private final WindowManagerGlobalLock mGlobalLock; 474 475 // List of task organizers by priority 476 private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>(); 477 private final ArrayMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new ArrayMap<>(); 478 // Set of organized tasks (by taskId) that dispatch back pressed to their organizers 479 private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet(); 480 481 private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer; 482 TaskOrganizerController(ActivityTaskManagerService atm)483 TaskOrganizerController(ActivityTaskManagerService atm) { 484 mService = atm; 485 mGlobalLock = atm.mGlobalLock; 486 } 487 488 @Override onTransact(int code, Parcel data, Parcel reply, int flags)489 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 490 throws RemoteException { 491 try { 492 return super.onTransact(code, data, reply, flags); 493 } catch (RuntimeException e) { 494 throw ActivityTaskManagerService.logAndRethrowRuntimeExceptionOnTransact(TAG, e); 495 } 496 } 497 498 /** 499 * Specifies the consumer to run to defer the task org callbacks. Can be overridden while 500 * testing to allow the callbacks to be sent synchronously. 501 */ 502 @VisibleForTesting setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer)503 public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) { 504 mDeferTaskOrgCallbacksConsumer = consumer; 505 } 506 507 /** 508 * Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode. 509 */ 510 @Override registerTaskOrganizer(ITaskOrganizer organizer)511 public ParceledListSlice<TaskAppearedInfo> registerTaskOrganizer(ITaskOrganizer organizer) { 512 enforceTaskPermission("registerTaskOrganizer()"); 513 final int uid = Binder.getCallingUid(); 514 final long origId = Binder.clearCallingIdentity(); 515 try { 516 final ArrayList<TaskAppearedInfo> taskInfos = new ArrayList<>(); 517 final Runnable withGlobalLock = () -> { 518 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d", 519 organizer.asBinder(), uid); 520 if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) { 521 mTaskOrganizers.add(organizer); 522 mTaskOrganizerStates.put(organizer.asBinder(), 523 new TaskOrganizerState(organizer, uid)); 524 } 525 526 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); 527 mService.mRootWindowContainer.forAllTasks((task) -> { 528 boolean returnTask = !task.mCreatedByOrganizer; 529 task.updateTaskOrganizerState(returnTask /* skipTaskAppeared */); 530 // It is possible for the task to not yet have a surface control, so ensure that 531 // the update succeeded in setting the organizer for the task before returning 532 if (task.isOrganized() && returnTask) { 533 SurfaceControl taskLeash = state.addTaskWithoutCallback(task, 534 "TaskOrganizerController.registerTaskOrganizer"); 535 taskInfos.add(new TaskAppearedInfo(task.getTaskInfo(), taskLeash)); 536 } 537 }); 538 }; 539 if (mService.getTransitionController().isShellTransitionsEnabled()) { 540 mService.getTransitionController().mRunningLock.runWhenIdle(1000, withGlobalLock); 541 } else { 542 synchronized (mGlobalLock) { 543 withGlobalLock.run(); 544 } 545 } 546 return new ParceledListSlice<>(taskInfos); 547 } finally { 548 Binder.restoreCallingIdentity(origId); 549 } 550 } 551 552 @Override unregisterTaskOrganizer(ITaskOrganizer organizer)553 public void unregisterTaskOrganizer(ITaskOrganizer organizer) { 554 enforceTaskPermission("unregisterTaskOrganizer()"); 555 final int uid = Binder.getCallingUid(); 556 final long origId = Binder.clearCallingIdentity(); 557 try { 558 final Runnable withGlobalLock = () -> { 559 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); 560 if (state == null) { 561 return; 562 } 563 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task organizer=%s uid=%d", 564 organizer.asBinder(), uid); 565 state.unlinkDeath(); 566 state.dispose(); 567 }; 568 if (mService.getTransitionController().isShellTransitionsEnabled()) { 569 mService.getTransitionController().mRunningLock.runWhenIdle(1000, withGlobalLock); 570 } else { 571 synchronized (mGlobalLock) { 572 withGlobalLock.run(); 573 } 574 } 575 } finally { 576 Binder.restoreCallingIdentity(origId); 577 } 578 } 579 580 /** 581 * @return the task organizer key for a given windowing mode. 582 */ getTaskOrganizer()583 ITaskOrganizer getTaskOrganizer() { 584 return mTaskOrganizers.peekLast(); 585 } 586 587 // Capture the animation surface control for activity's main window 588 static class StartingWindowAnimationAdaptor implements AnimationAdapter { 589 SurfaceControl mAnimationLeash; 590 @Override getShowWallpaper()591 public boolean getShowWallpaper() { 592 return false; 593 } 594 595 @Override startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback)596 public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, 597 int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { 598 mAnimationLeash = animationLeash; 599 } 600 601 @Override onAnimationCancelled(SurfaceControl animationLeash)602 public void onAnimationCancelled(SurfaceControl animationLeash) { 603 if (mAnimationLeash == animationLeash) { 604 mAnimationLeash = null; 605 } 606 } 607 608 @Override getDurationHint()609 public long getDurationHint() { 610 return 0; 611 } 612 613 @Override getStatusBarTransitionsStartTime()614 public long getStatusBarTransitionsStartTime() { 615 return 0; 616 } 617 618 @Override dump(PrintWriter pw, String prefix)619 public void dump(PrintWriter pw, String prefix) { 620 pw.print(prefix + "StartingWindowAnimationAdaptor mCapturedLeash="); 621 pw.print(mAnimationLeash); 622 pw.println(); 623 } 624 625 @Override dumpDebug(ProtoOutputStream proto)626 public void dumpDebug(ProtoOutputStream proto) { 627 } 628 } 629 applyStartingWindowAnimation(WindowState window)630 static SurfaceControl applyStartingWindowAnimation(WindowState window) { 631 final SurfaceControl.Transaction t = window.getPendingTransaction(); 632 final Rect mainFrame = window.getRelativeFrame(); 633 final StartingWindowAnimationAdaptor adaptor = new StartingWindowAnimationAdaptor(); 634 window.startAnimation(t, adaptor, false, ANIMATION_TYPE_STARTING_REVEAL); 635 if (adaptor.mAnimationLeash == null) { 636 Slog.e(TAG, "Cannot start starting window animation, the window " + window 637 + " was removed"); 638 return null; 639 } 640 t.setPosition(adaptor.mAnimationLeash, mainFrame.left, mainFrame.top); 641 return adaptor.mAnimationLeash; 642 } 643 addStartingWindow(Task task, ActivityRecord activity, int launchTheme, TaskSnapshot taskSnapshot)644 boolean addStartingWindow(Task task, ActivityRecord activity, int launchTheme, 645 TaskSnapshot taskSnapshot) { 646 final Task rootTask = task.getRootTask(); 647 if (rootTask == null || activity.mStartingData == null) { 648 return false; 649 } 650 final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast(); 651 if (lastOrganizer == null) { 652 return false; 653 } 654 final StartingWindowInfo info = task.getStartingWindowInfo(activity); 655 if (launchTheme != 0) { 656 info.splashScreenThemeResId = launchTheme; 657 } 658 info.taskSnapshot = taskSnapshot; 659 // make this happen prior than prepare surface 660 try { 661 lastOrganizer.addStartingWindow(info, activity.token); 662 } catch (RemoteException e) { 663 Slog.e(TAG, "Exception sending onTaskStart callback", e); 664 return false; 665 } 666 return true; 667 } 668 removeStartingWindow(Task task, boolean prepareAnimation)669 void removeStartingWindow(Task task, boolean prepareAnimation) { 670 final Task rootTask = task.getRootTask(); 671 if (rootTask == null) { 672 return; 673 } 674 final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast(); 675 if (lastOrganizer == null) { 676 return; 677 } 678 final StartingWindowRemovalInfo removalInfo = new StartingWindowRemovalInfo(); 679 removalInfo.taskId = task.mTaskId; 680 removalInfo.playRevealAnimation = prepareAnimation 681 && task.getDisplayInfo().state == Display.STATE_ON; 682 final boolean playShiftUpAnimation = !task.inMultiWindowMode(); 683 final ActivityRecord topActivity = task.topActivityContainsStartingWindow(); 684 if (topActivity != null) { 685 removalInfo.deferRemoveForIme = topActivity.mDisplayContent 686 .mayImeShowOnLaunchingActivity(topActivity); 687 final WindowState mainWindow = 688 topActivity.findMainWindow(false/* includeStartingApp */); 689 // No app window for this activity, app might be crashed. 690 // Remove starting window immediately without playing reveal animation. 691 if (mainWindow == null || mainWindow.mRemoved) { 692 removalInfo.playRevealAnimation = false; 693 } else if (removalInfo.playRevealAnimation && playShiftUpAnimation) { 694 removalInfo.roundedCornerRadius = 695 topActivity.mLetterboxUiController.getRoundedCornersRadius(mainWindow); 696 removalInfo.windowAnimationLeash = applyStartingWindowAnimation(mainWindow); 697 removalInfo.mainFrame = mainWindow.getRelativeFrame(); 698 } 699 } 700 try { 701 lastOrganizer.removeStartingWindow(removalInfo); 702 } catch (RemoteException e) { 703 Slog.e(TAG, "Exception sending onStartTaskFinished callback", e); 704 } 705 } 706 copySplashScreenView(Task task)707 boolean copySplashScreenView(Task task) { 708 final Task rootTask = task.getRootTask(); 709 if (rootTask == null) { 710 return false; 711 } 712 final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast(); 713 if (lastOrganizer == null) { 714 return false; 715 } 716 try { 717 lastOrganizer.copySplashScreenView(task.mTaskId); 718 } catch (RemoteException e) { 719 Slog.e(TAG, "Exception sending copyStartingWindowView callback", e); 720 return false; 721 } 722 return true; 723 } 724 725 /** 726 * Notify the shell ({@link com.android.wm.shell.ShellTaskOrganizer} that the client has 727 * removed the splash screen view. 728 * @see com.android.wm.shell.ShellTaskOrganizer#onAppSplashScreenViewRemoved(int) 729 * @see SplashScreenView#remove() 730 */ onAppSplashScreenViewRemoved(Task task)731 public void onAppSplashScreenViewRemoved(Task task) { 732 final Task rootTask = task.getRootTask(); 733 if (rootTask == null) { 734 return; 735 } 736 final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast(); 737 if (lastOrganizer == null) { 738 return; 739 } 740 try { 741 lastOrganizer.onAppSplashScreenViewRemoved(task.mTaskId); 742 } catch (RemoteException e) { 743 Slog.e(TAG, "Exception sending onAppSplashScreenViewRemoved callback", e); 744 } 745 } 746 onTaskAppeared(ITaskOrganizer organizer, Task task)747 void onTaskAppeared(ITaskOrganizer organizer, Task task) { 748 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); 749 if (state != null && state.addTask(task)) { 750 final TaskOrganizerPendingEventsQueue pendingEvents = 751 state.mPendingEventsQueue; 752 PendingTaskEvent pending = pendingEvents.getPendingTaskEvent(task, 753 PendingTaskEvent.EVENT_APPEARED); 754 if (pending == null) { 755 pendingEvents.addPendingTaskEvent(new PendingTaskEvent(task, 756 PendingTaskEvent.EVENT_APPEARED)); 757 } 758 } 759 } 760 onTaskVanished(ITaskOrganizer organizer, Task task)761 void onTaskVanished(ITaskOrganizer organizer, Task task) { 762 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); 763 if (state != null && state.removeTask(task, task.mRemoveWithTaskOrganizer)) { 764 onTaskVanishedInternal(state, task); 765 } 766 } 767 onTaskVanishedInternal(TaskOrganizerState organizerState, Task task)768 private void onTaskVanishedInternal(TaskOrganizerState organizerState, Task task) { 769 if (organizerState == null) { 770 Slog.i(TAG, "cannot send onTaskVanished because organizer state is not " 771 + "present for this organizer"); 772 return; 773 } 774 TaskOrganizerPendingEventsQueue pendingEventsQueue = 775 organizerState.mPendingEventsQueue; 776 boolean hadPendingAppearedEvents = 777 pendingEventsQueue.removePendingTaskEvents(task); 778 if (hadPendingAppearedEvents) { 779 return; 780 } 781 pendingEventsQueue.addPendingTaskEvent(new PendingTaskEvent(task, 782 organizerState.mOrganizer.mTaskOrganizer, PendingTaskEvent.EVENT_VANISHED)); 783 } 784 785 @Override createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie, boolean removeWithTaskOrganizer)786 public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie, 787 boolean removeWithTaskOrganizer) { 788 enforceTaskPermission("createRootTask()"); 789 final long origId = Binder.clearCallingIdentity(); 790 try { 791 synchronized (mGlobalLock) { 792 DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId); 793 if (display == null) { 794 ProtoLog.e(WM_DEBUG_WINDOW_ORGANIZER, 795 "createRootTask unknown displayId=%d", displayId); 796 return; 797 } 798 799 createRootTask(display, windowingMode, launchCookie, removeWithTaskOrganizer); 800 } 801 } finally { 802 Binder.restoreCallingIdentity(origId); 803 } 804 } 805 806 @VisibleForTesting createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie)807 Task createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie) { 808 return createRootTask(display, windowingMode, launchCookie, 809 false /* removeWithTaskOrganizer */); 810 } 811 createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie, boolean removeWithTaskOrganizer)812 Task createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie, 813 boolean removeWithTaskOrganizer) { 814 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d", 815 display.mDisplayId, windowingMode); 816 // We want to defer the task appear signal until the task is fully created and attached to 817 // to the hierarchy so that the complete starting configuration is in the task info we send 818 // over to the organizer. 819 final Task task = new Task.Builder(mService) 820 .setWindowingMode(windowingMode) 821 .setIntent(new Intent()) 822 .setCreatedByOrganizer(true) 823 .setDeferTaskAppear(true) 824 .setLaunchCookie(launchCookie) 825 .setParent(display.getDefaultTaskDisplayArea()) 826 .setRemoveWithTaskOrganizer(removeWithTaskOrganizer) 827 .build(); 828 task.setDeferTaskAppear(false /* deferTaskAppear */); 829 return task; 830 } 831 832 @Override deleteRootTask(WindowContainerToken token)833 public boolean deleteRootTask(WindowContainerToken token) { 834 enforceTaskPermission("deleteRootTask()"); 835 final long origId = Binder.clearCallingIdentity(); 836 try { 837 synchronized (mGlobalLock) { 838 final WindowContainer wc = WindowContainer.fromBinder(token.asBinder()); 839 if (wc == null) return false; 840 final Task task = wc.asTask(); 841 if (task == null) return false; 842 if (!task.mCreatedByOrganizer) { 843 throw new IllegalArgumentException( 844 "Attempt to delete task not created by organizer task=" + task); 845 } 846 847 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d", 848 task.getDisplayId(), task.getWindowingMode()); 849 task.remove(true /* withTransition */, "deleteRootTask"); 850 return true; 851 } 852 } finally { 853 Binder.restoreCallingIdentity(origId); 854 } 855 } 856 dispatchPendingEvents()857 void dispatchPendingEvents() { 858 if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) { 859 return; 860 } 861 for (int taskOrgIdx = 0; taskOrgIdx < mTaskOrganizerStates.size(); taskOrgIdx++) { 862 TaskOrganizerState taskOrganizerState = mTaskOrganizerStates.valueAt(taskOrgIdx); 863 taskOrganizerState.mPendingEventsQueue.dispatchPendingEvents(); 864 } 865 } 866 reportImeDrawnOnTask(Task task)867 void reportImeDrawnOnTask(Task task) { 868 final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder()); 869 if (state != null) { 870 try { 871 state.mOrganizer.mTaskOrganizer.onImeDrawnOnTask(task.mTaskId); 872 } catch (RemoteException e) { 873 Slog.e(TAG, "Exception sending onImeDrawnOnTask callback", e); 874 } 875 } 876 } 877 onTaskInfoChanged(Task task, boolean force)878 void onTaskInfoChanged(Task task, boolean force) { 879 if (!task.mTaskAppearedSent) { 880 // Skip if task still not appeared. 881 return; 882 } 883 final TaskOrganizerState taskOrganizerState = 884 mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder()); 885 final TaskOrganizerPendingEventsQueue pendingEventsQueue = 886 taskOrganizerState.mPendingEventsQueue; 887 if (pendingEventsQueue == null) { 888 Slog.i(TAG, "cannot send onTaskInfoChanged because pending events queue is not " 889 + "present for this organizer"); 890 return; 891 } 892 if (force && pendingEventsQueue.numPendingTaskEvents() == 0) { 893 // There are task-info changed events do not result in 894 // - RootWindowContainer#performSurfacePlacementNoTrace OR 895 // - WindowAnimator#animate 896 // For instance, when an app requesting aspect ratio change when in PiP mode. 897 // To solve this, we directly dispatch the pending event if there are no events queued ( 898 // otherwise, all pending events should be dispatched on next drawn). 899 pendingEventsQueue.dispatchTaskInfoChanged(task, true /* force */); 900 return; 901 } 902 903 // Defer task info reporting while layout is deferred. This is because layout defer 904 // blocks tend to do lots of re-ordering which can mess up animations in receivers. 905 PendingTaskEvent pending = pendingEventsQueue 906 .getPendingLifecycleTaskEvent(task); 907 if (pending == null) { 908 pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_INFO_CHANGED); 909 } else { 910 if (pending.mEventType != PendingTaskEvent.EVENT_INFO_CHANGED) { 911 // If queued event is appeared, it means task still not appeared so ignore 912 // this info changed. If queued event is vanished, it means task should 913 // will vanished early so do not need this info changed. 914 return; 915 } 916 // Remove and add for re-ordering. 917 pendingEventsQueue.removePendingTaskEvent(pending); 918 } 919 pending.mForce |= force; 920 pendingEventsQueue.addPendingTaskEvent(pending); 921 } 922 923 @Override getImeTarget(int displayId)924 public WindowContainerToken getImeTarget(int displayId) { 925 enforceTaskPermission("getImeTarget()"); 926 final long origId = Binder.clearCallingIdentity(); 927 try { 928 synchronized (mGlobalLock) { 929 final DisplayContent dc = mService.mWindowManager.mRoot 930 .getDisplayContent(displayId); 931 if (dc == null) { 932 return null; 933 } 934 935 final InsetsControlTarget imeLayeringTarget = dc.getImeTarget(IME_TARGET_LAYERING); 936 if (imeLayeringTarget == null || imeLayeringTarget.getWindow() == null) { 937 return null; 938 } 939 940 // Avoid WindowState#getRootTask() so we don't attribute system windows to a task. 941 final Task task = imeLayeringTarget.getWindow().getTask(); 942 if (task == null) { 943 return null; 944 } 945 946 return task.mRemoteToken.toWindowContainerToken(); 947 } 948 } finally { 949 Binder.restoreCallingIdentity(origId); 950 } 951 } 952 953 @Override getChildTasks(WindowContainerToken parent, @Nullable int[] activityTypes)954 public List<RunningTaskInfo> getChildTasks(WindowContainerToken parent, 955 @Nullable int[] activityTypes) { 956 enforceTaskPermission("getChildTasks()"); 957 final long ident = Binder.clearCallingIdentity(); 958 try { 959 synchronized (mGlobalLock) { 960 if (parent == null) { 961 throw new IllegalArgumentException("Can't get children of null parent"); 962 } 963 final WindowContainer container = WindowContainer.fromBinder(parent.asBinder()); 964 if (container == null) { 965 Slog.e(TAG, "Can't get children of " + parent + " because it is not valid."); 966 return null; 967 } 968 final Task task = container.asTask(); 969 if (task == null) { 970 Slog.e(TAG, container + " is not a task..."); 971 return null; 972 } 973 // For now, only support returning children of tasks created by the organizer. 974 if (!task.mCreatedByOrganizer) { 975 Slog.w(TAG, "Can only get children of root tasks created via createRootTask"); 976 return null; 977 } 978 ArrayList<RunningTaskInfo> out = new ArrayList<>(); 979 for (int i = task.getChildCount() - 1; i >= 0; --i) { 980 final Task child = task.getChildAt(i).asTask(); 981 if (child == null) continue; 982 if (activityTypes != null 983 && !ArrayUtils.contains(activityTypes, child.getActivityType())) { 984 continue; 985 } 986 out.add(child.getTaskInfo()); 987 } 988 return out; 989 } 990 } finally { 991 Binder.restoreCallingIdentity(ident); 992 } 993 } 994 995 @Override getRootTasks(int displayId, @Nullable int[] activityTypes)996 public List<RunningTaskInfo> getRootTasks(int displayId, @Nullable int[] activityTypes) { 997 enforceTaskPermission("getRootTasks()"); 998 final long ident = Binder.clearCallingIdentity(); 999 try { 1000 synchronized (mGlobalLock) { 1001 final DisplayContent dc = 1002 mService.mRootWindowContainer.getDisplayContent(displayId); 1003 if (dc == null) { 1004 throw new IllegalArgumentException("Display " + displayId + " doesn't exist"); 1005 } 1006 final ArrayList<RunningTaskInfo> out = new ArrayList<>(); 1007 dc.forAllRootTasks(task -> { 1008 if (activityTypes != null 1009 && !ArrayUtils.contains(activityTypes, task.getActivityType())) { 1010 return; 1011 } 1012 out.add(task.getTaskInfo()); 1013 }); 1014 return out; 1015 } 1016 } finally { 1017 Binder.restoreCallingIdentity(ident); 1018 } 1019 } 1020 1021 @Override setInterceptBackPressedOnTaskRoot(WindowContainerToken token, boolean interceptBackPressed)1022 public void setInterceptBackPressedOnTaskRoot(WindowContainerToken token, 1023 boolean interceptBackPressed) { 1024 enforceTaskPermission("setInterceptBackPressedOnTaskRoot()"); 1025 final long origId = Binder.clearCallingIdentity(); 1026 try { 1027 synchronized (mGlobalLock) { 1028 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set intercept back pressed on root=%b", 1029 interceptBackPressed); 1030 final WindowContainer wc = WindowContainer.fromBinder(token.asBinder()); 1031 if (wc == null) { 1032 Slog.w(TAG, "Could not resolve window from token"); 1033 return; 1034 } 1035 final Task task = wc.asTask(); 1036 if (task == null) { 1037 Slog.w(TAG, "Could not resolve task from token"); 1038 return; 1039 } 1040 if (interceptBackPressed) { 1041 mInterceptBackPressedOnRootTasks.add(task.mTaskId); 1042 } else { 1043 mInterceptBackPressedOnRootTasks.remove(task.mTaskId); 1044 } 1045 } 1046 } finally { 1047 Binder.restoreCallingIdentity(origId); 1048 } 1049 } 1050 1051 @Override restartTaskTopActivityProcessIfVisible(WindowContainerToken token)1052 public void restartTaskTopActivityProcessIfVisible(WindowContainerToken token) { 1053 enforceTaskPermission("restartTopActivityProcessIfVisible()"); 1054 final long origId = Binder.clearCallingIdentity(); 1055 try { 1056 synchronized (mGlobalLock) { 1057 final WindowContainer wc = WindowContainer.fromBinder(token.asBinder()); 1058 if (wc == null) { 1059 Slog.w(TAG, "Could not resolve window from token"); 1060 return; 1061 } 1062 final Task task = wc.asTask(); 1063 if (task == null) { 1064 Slog.w(TAG, "Could not resolve task from token"); 1065 return; 1066 } 1067 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, 1068 "Restart top activity process of Task taskId=%d", task.mTaskId); 1069 final ActivityRecord activity = task.getTopNonFinishingActivity(); 1070 if (activity != null) { 1071 activity.restartProcessIfVisible(); 1072 } 1073 } 1074 } finally { 1075 Binder.restoreCallingIdentity(origId); 1076 } 1077 } 1078 1079 @Override updateCameraCompatControlState(WindowContainerToken token, int state)1080 public void updateCameraCompatControlState(WindowContainerToken token, int state) { 1081 enforceTaskPermission("updateCameraCompatControlState()"); 1082 final long origId = Binder.clearCallingIdentity(); 1083 try { 1084 synchronized (mGlobalLock) { 1085 final WindowContainer wc = WindowContainer.fromBinder(token.asBinder()); 1086 if (wc == null) { 1087 Slog.w(TAG, "Could not resolve window from token"); 1088 return; 1089 } 1090 final Task task = wc.asTask(); 1091 if (task == null) { 1092 Slog.w(TAG, "Could not resolve task from token"); 1093 return; 1094 } 1095 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, 1096 "Update camera compat control state to %s for taskId=%d", 1097 cameraCompatControlStateToString(state), task.mTaskId); 1098 final ActivityRecord activity = task.getTopNonFinishingActivity(); 1099 if (activity != null) { 1100 activity.updateCameraCompatStateFromUser(state); 1101 } 1102 } 1103 } finally { 1104 Binder.restoreCallingIdentity(origId); 1105 } 1106 } 1107 1108 @Override setOrientationRequestPolicy(boolean isIgnoreOrientationRequestDisabled, @Nullable int[] fromOrientations, @Nullable int[] toOrientations)1109 public void setOrientationRequestPolicy(boolean isIgnoreOrientationRequestDisabled, 1110 @Nullable int[] fromOrientations, @Nullable int[] toOrientations) { 1111 enforceTaskPermission("setOrientationRequestPolicy()"); 1112 final long origId = Binder.clearCallingIdentity(); 1113 try { 1114 synchronized (mGlobalLock) { 1115 mService.mWindowManager 1116 .setOrientationRequestPolicy(isIgnoreOrientationRequestDisabled, 1117 fromOrientations, toOrientations); 1118 } 1119 } finally { 1120 Binder.restoreCallingIdentity(origId); 1121 } 1122 } 1123 handleInterceptBackPressedOnTaskRoot(Task task)1124 public boolean handleInterceptBackPressedOnTaskRoot(Task task) { 1125 if (task == null || !task.isOrganized() 1126 || !mInterceptBackPressedOnRootTasks.contains(task.mTaskId)) { 1127 return false; 1128 } 1129 final TaskOrganizerPendingEventsQueue pendingEventsQueue = 1130 mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder()) 1131 .mPendingEventsQueue; 1132 if (pendingEventsQueue == null) { 1133 Slog.w(TAG, "cannot get handle BackPressedOnTaskRoot because organizerState is " 1134 + "not present"); 1135 return false; 1136 } 1137 1138 PendingTaskEvent pendingVanished = 1139 pendingEventsQueue.getPendingTaskEvent(task, 1140 PendingTaskEvent.EVENT_VANISHED); 1141 if (pendingVanished != null) { 1142 // This task will vanish before this callback so just ignore. 1143 return false; 1144 } 1145 1146 PendingTaskEvent pending = pendingEventsQueue.getPendingTaskEvent( 1147 task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED); 1148 if (pending == null) { 1149 pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED); 1150 } else { 1151 // Pending already exist, remove and add for re-ordering. 1152 pendingEventsQueue.removePendingTaskEvent(pending); 1153 } 1154 pendingEventsQueue.addPendingTaskEvent(pending); 1155 mService.mWindowManager.mWindowPlacerLocked.requestTraversal(); 1156 return true; 1157 } 1158 dump(PrintWriter pw, String prefix)1159 public void dump(PrintWriter pw, String prefix) { 1160 final String innerPrefix = prefix + " "; 1161 pw.print(prefix); pw.println("TaskOrganizerController:"); 1162 for (final TaskOrganizerState state : mTaskOrganizerStates.values()) { 1163 final ArrayList<Task> tasks = state.mOrganizedTasks; 1164 pw.print(innerPrefix + " "); 1165 pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":"); 1166 for (int k = 0; k < tasks.size(); k++) { 1167 final Task task = tasks.get(k); 1168 final int mode = task.getWindowingMode(); 1169 pw.println(innerPrefix + " (" 1170 + WindowConfiguration.windowingModeToString(mode) + ") " + task); 1171 } 1172 1173 } 1174 pw.println(); 1175 } 1176 1177 @VisibleForTesting getTaskOrganizerState(IBinder taskOrganizer)1178 TaskOrganizerState getTaskOrganizerState(IBinder taskOrganizer) { 1179 return mTaskOrganizerStates.get(taskOrganizer); 1180 } 1181 1182 @VisibleForTesting getTaskOrganizerPendingEvents(IBinder taskOrganizer)1183 TaskOrganizerPendingEventsQueue getTaskOrganizerPendingEvents(IBinder taskOrganizer) { 1184 return mTaskOrganizerStates.get(taskOrganizer).mPendingEventsQueue; 1185 } 1186 } 1187