Merge "Use queue to defer all task events"

This commit is contained in:
Tony Huang
2021-01-19 07:18:53 +00:00
committed by Android (Google) Code Review
8 changed files with 419 additions and 82 deletions

View File

@@ -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()));

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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");
}

View File

@@ -5009,7 +5009,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");
@@ -5035,7 +5034,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;
}
@@ -7686,7 +7685,7 @@ class Task extends WindowContainer<WindowContainer> {
void dispatchTaskInfoChangedIfNeeded(boolean force) {
if (isOrganized()) {
mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, force);
mAtmService.mTaskOrganizerController.onTaskInfoChanged(this, force);
}
}

View File

@@ -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,16 +480,40 @@ 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
public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) {
enforceTaskPermission("createRootTask()");
@@ -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:");

View File

@@ -222,6 +222,7 @@ public class WindowAnimator {
mService.destroyPreservedSurfaceLocked();
mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
executeAfterPrepareSurfacesRunnables();
if (DEBUG_WINDOW_TRACE) {

View File

@@ -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.
*/