summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tony Huang <tonyychuang@google.com> 2021-01-15 03:02:15 +0000
committer Tony Huang <tonyychuang@google.com> 2021-01-18 11:44:19 +0800
commit28fb865b01094fe0dcad7e0f5fa89fa45a96ba51 (patch)
tree3d9c430da73084278c76ca6da7a9b5fbc4725b17
parent7d6b3cc8fc0dc5df63c3cf7f5cb3e0470602445d (diff)
Use queue to defer all task events
It has two layer defer currently, it should only remain queue events method. Remove using of mDeferTaskOrgCallbacksConsumer and extand using of queue method to onTaskAppeared, onTaskVanished and onBackPressedOnTaskRoot. Bug: 171749427 Bug: 177551997 Test: check split screen, PiP and bubbles work normally Test: atest WmTests:WindowOrganizerTests Test: atest CtsHarmfulAppWarningHostTestCases Change-Id: Ic8fea93117f45b60f15b06773eefbbde11e48fd5
-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.
*/