summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java1
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java6
-rw-r--r--services/core/java/com/android/server/wm/Task.java5
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java277
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java197
8 files changed, 419 insertions, 82 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index faa4a0ed2294..c9b38d00c0ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -262,12 +262,6 @@ public class ShellTaskOrganizer extends TaskOrganizer {
synchronized (mLock) {
ProtoLog.v(WM_SHELL_TASK_ORG, "Task info changed taskId=%d", taskInfo.taskId);
final TaskAppearedInfo data = mTasks.get(taskInfo.taskId);
- if (data == null) {
- // TODO(b/171749427): It means onTaskInfoChanged send before onTaskAppeared or
- // after onTaskVanished, it should be fixed in controller side.
- return;
- }
-
final TaskListener oldListener = getTaskListener(data.getTaskInfo());
final TaskListener newListener = getTaskListener(taskInfo);
mTasks.put(taskInfo.taskId, new TaskAppearedInfo(taskInfo, data.getLeash()));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
index de3bb2950c0a..f8b4dd9bc621 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
@@ -41,12 +41,12 @@ public class PipUiEventLogger {
}
public void setTaskInfo(TaskInfo taskInfo) {
- if (taskInfo == null) {
- mPackageName = null;
- mPackageUid = INVALID_PACKAGE_UID;
- } else {
+ if (taskInfo != null && taskInfo.topActivity != null) {
mPackageName = taskInfo.topActivity.getPackageName();
mPackageUid = getUid(mPackageName, taskInfo.userId);
+ } else {
+ mPackageName = null;
+ mPackageUid = INVALID_PACKAGE_UID;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index f1b3cc5866a4..fc1811b11d73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1005,6 +1005,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
private void updateThemeColors() {
+ if (mScrimBehind == null) return;
int background = Utils.getColorAttr(mScrimBehind.getContext(),
android.R.attr.colorBackgroundFloating).getDefaultColor();
int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 23acbf75429c..ff349fa637a5 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -862,6 +862,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
}
}
+
+ // Send any pending task-info changes that were queued-up during a layout deferment
+ mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
checkAppTransitionReady(surfacePlacer);
@@ -1014,9 +1017,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mWmService.scheduleAnimationLocked();
- // Send any pending task-info changes that were queued-up during a layout deferment
- mWmService.mAtmService.mTaskOrganizerController.dispatchPendingTaskInfoChanges();
-
if (DEBUG_WINDOW_TRACE) Slog.e(TAG, "performSurfacePlacementInner exit");
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 637240c06de2..af85ec69eeac 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4993,7 +4993,6 @@ class Task extends WindowContainer<WindowContainer> {
}
} else {
// No longer managed by any organizer.
- mTaskAppearedSent = false;
setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
if (mCreatedByOrganizer) {
removeImmediately("setTaskOrganizer");
@@ -5019,7 +5018,7 @@ class Task extends WindowContainer<WindowContainer> {
*/
boolean updateTaskOrganizerState(boolean forceUpdate, boolean skipTaskAppeared) {
if (getSurfaceControl() == null) {
- // Can't call onTaskAppeared without a surfacecontrol, so defer this until after one
+ // Can't call onTaskAppeared without a surfacecontrol, so defer this until next one
// is created.
return false;
}
@@ -7672,7 +7671,7 @@ class Task extends WindowContainer<WindowContainer> {
void dispatchTaskInfoChangedIfNeeded(boolean force) {
if (isOrganized()) {
- mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, force);
+ mAtmService.mTaskOrganizerController.onTaskInfoChanged(this, force);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 65247d0b9937..b3e010872d3b 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -151,27 +151,23 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
final boolean visible = task.isVisible();
final RunningTaskInfo taskInfo = task.getTaskInfo();
- mDeferTaskOrgCallbacksConsumer.accept(() -> {
- try {
- mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
- "TaskOrganizerController.onTaskAppeared"));
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
- }
- });
+ try {
+ mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
+ "TaskOrganizerController.onTaskAppeared"));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
+ }
}
void onTaskVanished(Task task) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId);
final RunningTaskInfo taskInfo = task.getTaskInfo();
- mDeferTaskOrgCallbacksConsumer.accept(() -> {
- try {
- mTaskOrganizer.onTaskVanished(taskInfo);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskVanished callback", e);
- }
- });
+ try {
+ mTaskOrganizer.onTaskVanished(taskInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskVanished callback", e);
+ }
}
void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
@@ -180,20 +176,18 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return;
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
- mDeferTaskOrgCallbacksConsumer.accept(() -> {
- if (!task.isOrganized()) {
- // This is safe to ignore if the task is no longer organized
- return;
- }
- try {
- // Purposely notify of task info change immediately instead of deferring (like
- // appear and vanish) to allow info changes (such as new PIP params) to flow
- // without waiting.
- mTaskOrganizer.onTaskInfoChanged(taskInfo);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
- }
- });
+ if (!task.isOrganized()) {
+ // This is safe to ignore if the task is no longer organized
+ return;
+ }
+ try {
+ // Purposely notify of task info change immediately instead of deferring (like
+ // appear and vanish) to allow info changes (such as new PIP params) to flow
+ // without waiting.
+ mTaskOrganizer.onTaskInfoChanged(taskInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
+ }
}
void onBackPressedOnTaskRoot(Task task) {
@@ -203,17 +197,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
// Skip if the task has not yet received taskAppeared().
return;
}
- mDeferTaskOrgCallbacksConsumer.accept(() -> {
- if (!task.isOrganized()) {
- // This is safe to ignore if the task is no longer organized
- return;
- }
- try {
- mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
- } catch (Exception e) {
- Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
- }
- });
+ if (!task.isOrganized()) {
+ // This is safe to ignore if the task is no longer organized
+ return;
+ }
+ try {
+ mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
+ }
}
}
@@ -258,28 +250,34 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return mOrganizer.prepareLeash(t, t.isVisible(), reason);
}
- void addTask(Task t) {
- if (t.mTaskAppearedSent) return;
+ private boolean addTask(Task t) {
+ if (t.mTaskAppearedSent) {
+ return false;
+ }
if (!mOrganizedTasks.contains(t)) {
mOrganizedTasks.add(t);
}
+
if (t.taskAppearedReady()) {
t.mTaskAppearedSent = true;
- mOrganizer.onTaskAppeared(t);
+ return true;
}
+ return false;
}
- void removeTask(Task t) {
+ private boolean removeTask(Task t) {
+ mOrganizedTasks.remove(t);
+ mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
+
if (t.mTaskAppearedSent) {
if (t.getSurfaceControl() != null) {
t.migrateToNewSurfaceControl();
}
t.mTaskAppearedSent = false;
- mOrganizer.onTaskVanished(t);
+ return true;
}
- mOrganizedTasks.remove(t);
- mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
+ return false;
}
void dispose() {
@@ -290,8 +288,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
// possible.
while (!mOrganizedTasks.isEmpty()) {
final Task t = mOrganizedTasks.get(0);
- if (!t.updateTaskOrganizerState(true /* forceUpdate */)) {
- removeTask(t);
+ t.updateTaskOrganizerState(true /* forceUpdate */);
+ if (mOrganizedTasks.contains(t)) {
+ // updateTaskOrganizerState should remove the task from the list, but still
+ // check it again to avoid while-loop isn't terminate.
+ if (removeTask(t)) {
+ TaskOrganizerController.this.onTaskVanishedInternal(
+ mOrganizer.mTaskOrganizer, t);
+ }
}
}
@@ -305,6 +309,33 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
}
+ static class PendingTaskEvent {
+ static final int EVENT_APPEARED = 0;
+ static final int EVENT_VANISHED = 1;
+ static final int EVENT_INFO_CHANGED = 2;
+ static final int EVENT_ROOT_BACK_PRESSED = 3;
+
+ final int mEventType;
+ final Task mTask;
+ final ITaskOrganizer mTaskOrg;
+ boolean mForce;
+
+ PendingTaskEvent(Task task, int event) {
+ this(task, task.mTaskOrganizer, event);
+ }
+
+ PendingTaskEvent(Task task, ITaskOrganizer taskOrg, int eventType) {
+ mTask = task;
+ mTaskOrg = taskOrg;
+ mEventType = eventType;
+ }
+
+ boolean isLifecycleEvent() {
+ return mEventType == EVENT_APPEARED || mEventType == EVENT_VANISHED
+ || mEventType == EVENT_INFO_CHANGED;
+ }
+ }
+
private final ActivityTaskManagerService mService;
private final WindowManagerGlobalLock mGlobalLock;
@@ -312,7 +343,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
- private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
+ // Pending task events due to layout deferred.
+ private final ArrayList<PendingTaskEvent> mPendingTaskEvents = new ArrayList<>();
// Set of organized tasks (by taskId) that dispatch back pressed to their organizers
private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
@@ -337,6 +369,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
mDeferTaskOrgCallbacksConsumer = consumer;
}
+
+ @VisibleForTesting
+ ArrayList<PendingTaskEvent> getPendingEventList() {
+ return mPendingTaskEvents;
+ }
+
/**
* Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode.
*/
@@ -442,14 +480,38 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
- state.addTask(task);
+ if (state != null && state.addTask(task)) {
+ PendingTaskEvent pending = getPendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
+ if (pending == null) {
+ pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
+ mPendingTaskEvents.add(pending);
+ }
+ }
}
void onTaskVanished(ITaskOrganizer organizer, Task task) {
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
- if (state != null) {
- state.removeTask(task);
+ if (state != null && state.removeTask(task)) {
+ onTaskVanishedInternal(organizer, task);
+ }
+ }
+
+ private void onTaskVanishedInternal(ITaskOrganizer organizer, Task task) {
+ for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
+ PendingTaskEvent entry = mPendingTaskEvents.get(i);
+ if (task.mTaskId == entry.mTask.mTaskId) {
+ // This task is vanished so remove all pending event of it.
+ mPendingTaskEvents.remove(i);
+ if (entry.mEventType == PendingTaskEvent.EVENT_APPEARED) {
+ // If task appeared callback still pend, ignore this callback too.
+ return;
+ }
+ }
}
+
+ PendingTaskEvent pending =
+ new PendingTaskEvent(task, organizer, PendingTaskEvent.EVENT_VANISHED);
+ mPendingTaskEvents.add(pending);
}
@Override
@@ -518,30 +580,76 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
}
- void dispatchPendingTaskInfoChanges() {
- if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+ void dispatchPendingEvents() {
+ if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
+ || mPendingTaskEvents.isEmpty()) {
return;
}
- for (int i = 0, n = mPendingTaskInfoChanges.size(); i < n; ++i) {
- dispatchTaskInfoChanged(mPendingTaskInfoChanges.get(i), false /* force */);
+
+ for (int i = 0, n = mPendingTaskEvents.size(); i < n; i++) {
+ PendingTaskEvent event = mPendingTaskEvents.get(i);
+ final Task task = event.mTask;
+ final TaskOrganizerState state;
+ switch (event.mEventType) {
+ case PendingTaskEvent.EVENT_APPEARED:
+ state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
+ if (state != null && task.taskAppearedReady()) {
+ state.mOrganizer.onTaskAppeared(task);
+ }
+ break;
+ case PendingTaskEvent.EVENT_VANISHED:
+ state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
+ if (state != null) {
+ state.mOrganizer.onTaskVanished(task);
+ }
+ break;
+ case PendingTaskEvent.EVENT_INFO_CHANGED:
+ dispatchTaskInfoChanged(event.mTask, event.mForce);
+ break;
+ case PendingTaskEvent.EVENT_ROOT_BACK_PRESSED:
+ state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
+ if (state != null) {
+ state.mOrganizer.onBackPressedOnTaskRoot(task);
+ }
+ break;
+ }
}
- mPendingTaskInfoChanges.clear();
+ mPendingTaskEvents.clear();
}
- void dispatchTaskInfoChanged(Task task, boolean force) {
- if (!force && mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
- // Defer task info reporting while layout is deferred. This is because layout defer
- // blocks tend to do lots of re-ordering which can mess up animations in receivers.
- mPendingTaskInfoChanges.remove(task);
- mPendingTaskInfoChanges.add(task);
+ void onTaskInfoChanged(Task task, boolean force) {
+ if (!task.mTaskAppearedSent) {
+ // Skip if task still not appeared.
return;
}
+
+ // Defer task info reporting while layout is deferred. This is because layout defer
+ // blocks tend to do lots of re-ordering which can mess up animations in receivers.
+ PendingTaskEvent pending = getPendingLifecycleTaskEvent(task);
+ if (pending == null) {
+ pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_INFO_CHANGED);
+ } else {
+ if (pending.mEventType != PendingTaskEvent.EVENT_INFO_CHANGED) {
+ // If queued event is appeared, it means task still not appeared so ignore
+ // this info changed. If queued event is vanished, it means task should
+ // will vanished early so do not need this info changed.
+ return;
+ }
+ // Remove and add for re-ordering.
+ mPendingTaskEvents.remove(pending);
+ }
+ pending.mForce = force;
+ mPendingTaskEvents.add(pending);
+ }
+
+ private void dispatchTaskInfoChanged(Task task, boolean force) {
RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task);
if (mTmpTaskInfo == null) {
mTmpTaskInfo = new RunningTaskInfo();
}
mTmpTaskInfo.configuration.unset();
task.fillTaskInfo(mTmpTaskInfo);
+
boolean changed = !mTmpTaskInfo.equalsForTaskOrganizer(lastInfo);
if (!changed) {
int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
@@ -705,11 +813,48 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return false;
}
- final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
- state.mOrganizer.onBackPressedOnTaskRoot(task);
+ PendingTaskEvent pendingVanished =
+ getPendingTaskEvent(task, PendingTaskEvent.EVENT_VANISHED);
+ if (pendingVanished != null) {
+ // This task will vanish before this callback so just ignore.
+ return false;
+ }
+
+ PendingTaskEvent pending = getPendingTaskEvent(
+ task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
+ if (pending == null) {
+ pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
+ } else {
+ // Pending already exist, remove and add for re-ordering.
+ mPendingTaskEvents.remove(pending);
+ }
+ mPendingTaskEvents.add(pending);
return true;
}
+ @Nullable
+ private PendingTaskEvent getPendingTaskEvent(Task task, int type) {
+ for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
+ PendingTaskEvent entry = mPendingTaskEvents.get(i);
+ if (task.mTaskId == entry.mTask.mTaskId && type == entry.mEventType) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ PendingTaskEvent getPendingLifecycleTaskEvent(Task task) {
+ for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
+ PendingTaskEvent entry = mPendingTaskEvents.get(i);
+ if (task.mTaskId == entry.mTask.mTaskId && entry.isLifecycleEvent()) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.print(prefix); pw.println("TaskOrganizerController:");
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index c4eb63581153..52ed2788d795 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -222,6 +222,7 @@ public class WindowAnimator {
mService.destroyPreservedSurfaceLocked();
+ mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
executeAfterPrepareSurfacesRunnables();
if (DEBUG_WINDOW_TRACE) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index fe7bdd8f620a..d8be2c1a21a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -80,6 +80,8 @@ import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
+import com.android.server.wm.TaskOrganizerController.PendingTaskEvent;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -150,10 +152,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.removeImmediately();
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskVanished(any());
}
@@ -162,15 +168,21 @@ public class WindowOrganizerTests extends WindowTestsBase {
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.setHasBeenVisible(true);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertTrue(stack.getHasBeenVisible());
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.removeImmediately();
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskVanished(any());
}
@@ -195,12 +207,16 @@ public class WindowOrganizerTests extends WindowTestsBase {
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false /* fakeDraw */);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertTaskVanished(organizer, false /* expectVanished */, stack);
assertFalse(stack.isOrganized());
}
@@ -210,11 +226,16 @@ public class WindowOrganizerTests extends WindowTestsBase {
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
stack.setTaskOrganizer(null);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+
verify(organizer).onTaskVanished(any());
assertFalse(stack.isOrganized());
}
@@ -224,11 +245,16 @@ public class WindowOrganizerTests extends WindowTestsBase {
final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+
assertTaskVanished(organizer, true /* expectVanished */, stack);
assertFalse(stack.isOrganized());
}
@@ -243,6 +269,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
final Task task3 = createTask(stack3);
final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
// verify that tasks are returned and taskAppeared is not called
assertContainsTasks(existingTasks, stack, stack2, stack3);
@@ -254,6 +282,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
// Now we replace the registration and verify the new organizer receives existing tasks
final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>();
final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertContainsTasks(existingTasks2, stack, stack2, stack3);
verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
any(SurfaceControl.class));
@@ -265,6 +295,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
// Now we unregister the second one, the first one should automatically be reregistered
// so we verify that it's now seeing changes.
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(3))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTaskVanished(organizer2, true /* expectVanished */, stack, stack2, stack3);
@@ -599,6 +631,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
RunningTaskInfo info1 = task.getTaskInfo();
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
lastReportedTiles.clear();
called[0] = false;
@@ -673,6 +707,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
RunningTaskInfo info2 = task2.getTaskInfo();
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
final int initialRootTaskCount = mWm.mAtmService.mTaskOrganizerController.getRootTasks(
mDisplayContent.mDisplayId, null /* activityTypes */).size();
@@ -856,6 +892,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
.setAspectRatio(new Rational(3, 4)).build();
mWm.mAtmService.mActivityClientController.setPictureInPictureParams(record.token, p2);
waitUntilHandlersIdle();
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertNotNull(o.mChangedInfo);
assertNotNull(o.mChangedInfo.pictureInPictureParams);
final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatioRational();
@@ -895,16 +933,24 @@ public class WindowOrganizerTests extends WindowTestsBase {
stack.setTaskOrganizer(organizer);
// setHasBeenVisible was already called once by the set-up code.
stack.setHasBeenVisible(true);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.setTaskOrganizer(null);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1)).onTaskVanished(any());
stack.setTaskOrganizer(organizer);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(2))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
stack.removeImmediately();
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(2)).onTaskVanished(any());
}
@@ -923,6 +969,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
// Verify a back pressed does not call the organizer
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, never()).onBackPressedOnTaskRoot(any());
// Enable intercepting back
@@ -931,6 +979,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
// Verify now that the back press does call the organizer
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
// Disable intercepting back
@@ -939,6 +989,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
// Verify now that the back press no longer calls the organizer
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
+ // Ensure events dispatch to organizer.
+ mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
}
@@ -1019,6 +1071,151 @@ public class WindowOrganizerTests extends WindowTestsBase {
assertTrue(task2.isOrganized());
}
+ @Test
+ public void testAppearDeferThenInfoChange() {
+ final ITaskOrganizer organizer = registerMockOrganizer();
+ final Task stack = createStack();
+
+ // Assume layout defer
+ mWm.mWindowPlacerLocked.deferLayout();
+
+ final Task task = createTask(stack);
+ final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
+ waitUntilHandlersIdle();
+
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ assertEquals(1, pendingEvents.size());
+ assertEquals(PendingTaskEvent.EVENT_APPEARED, pendingEvents.get(0).mEventType);
+ assertEquals("TestDescription",
+ pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
+ }
+
+ @Test
+ public void testAppearDeferThenVanish() {
+ final ITaskOrganizer organizer = registerMockOrganizer();
+ final Task stack = createStack();
+
+ // Assume layout defer
+ mWm.mWindowPlacerLocked.deferLayout();
+
+ final Task task = createTask(stack);
+
+ stack.removeImmediately();
+ waitUntilHandlersIdle();
+
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ assertEquals(0, pendingEvents.size());
+ }
+
+ @Test
+ public void testInfoChangeDeferMultiple() {
+ final ITaskOrganizer organizer = registerMockOrganizer();
+ final Task stack = createStack();
+ final Task task = createTask(stack);
+ final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+ // Assume layout defer
+ mWm.mWindowPlacerLocked.deferLayout();
+
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
+ waitUntilHandlersIdle();
+
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ assertEquals(1, pendingEvents.size());
+ assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
+ assertEquals("TestDescription",
+ pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
+
+ record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription2"));
+ waitUntilHandlersIdle();
+
+ pendingEvents = getTaskPendingEvent(stack);
+ assertEquals(1, pendingEvents.size());
+ assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
+ assertEquals("TestDescription2",
+ pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
+ }
+
+ @Test
+ public void testInfoChangDeferThenVanish() {
+ final ITaskOrganizer organizer = registerMockOrganizer();
+ final Task stack = createStack();
+ final Task task = createTask(stack);
+ final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+ // Assume layout defer
+ mWm.mWindowPlacerLocked.deferLayout();
+
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
+
+ stack.removeImmediately();
+ waitUntilHandlersIdle();
+
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ assertEquals(1, pendingEvents.size());
+ assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
+ assertEquals("TestDescription",
+ pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
+ }
+
+ @Test
+ public void testVanishDeferThenInfoChange() {
+ final ITaskOrganizer organizer = registerMockOrganizer();
+ final Task stack = createStack();
+ final Task task = createTask(stack);
+ final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+ // Assume layout defer
+ mWm.mWindowPlacerLocked.deferLayout();
+
+ stack.removeImmediately();
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ waitUntilHandlersIdle();
+
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ assertEquals(1, pendingEvents.size());
+ assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
+ }
+
+ @Test
+ public void testVanishDeferThenBackOnRoot() {
+ final ITaskOrganizer organizer = registerMockOrganizer();
+ final Task stack = createStack();
+ final Task task = createTask(stack);
+ final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+ // Assume layout defer
+ mWm.mWindowPlacerLocked.deferLayout();
+
+ stack.removeImmediately();
+ mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(record.token);
+ waitUntilHandlersIdle();
+
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ assertEquals(1, pendingEvents.size());
+ assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
+ }
+
+ private ArrayList<PendingTaskEvent> getTaskPendingEvent(Task task) {
+ ArrayList<PendingTaskEvent> total =
+ mWm.mAtmService.mTaskOrganizerController.getPendingEventList();
+ ArrayList<PendingTaskEvent> result = new ArrayList();
+
+ for (int i = 0; i < total.size(); i++) {
+ PendingTaskEvent entry = total.get(i);
+ if (entry.mTask.mTaskId == task.mTaskId) {
+ result.add(entry);
+ }
+ }
+
+ return result;
+ }
+
/**
* Verifies that task vanished is called for a specific task.
*/