Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09e17a63 authored by Winson Chung's avatar Winson Chung
Browse files

Support adding task listeners for incoming tasks

- The task/transition paths currently have no guaranteed order, if
  a task listener is registered before a task appears, we store it
  as a pending listener which will be fully registered once the task
  next appears.  This pending listener is always removed whenever the
  listener is unregistered, and priority of the launch cookie is >
  than the pending listener (and the pending listener will be removed
  if a launch cookie listener is used).

Bug: 385674612
Flag: EXEMPT bugfix
Test: atest ShellTaskOrganizerTests
Change-Id: Id07d7df4be90beb9271ba0de772a41814e3bf728
parent 52c9d1d3
Loading
Loading
Loading
Loading
+53 −8
Original line number Diff line number Diff line
@@ -171,6 +171,9 @@ public class ShellTaskOrganizer extends TaskOrganizer {
    /** @see #setPendingLaunchCookieListener */
    private final ArrayMap<IBinder, TaskListener> mLaunchCookieToListener = new ArrayMap<>();

    /** @see #setPendingTaskListener(int, TaskListener)  */
    private final ArrayMap<Integer, TaskListener> mPendingTaskToListener = new ArrayMap<>();

    // Keeps track of taskId's with visible locusIds. Used to notify any {@link LocusIdListener}s
    // that might be set.
    private final SparseArray<LocusId> mVisibleTasksWithLocusId = new SparseArray<>();
@@ -365,7 +368,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
    }

    /**
     * Adds a listener for a specific task id.
     * Adds a listener for a specific task id.  This only applies if
     */
    public void addListenerForTaskId(TaskListener listener, int taskId) {
        synchronized (mLock) {
@@ -383,7 +386,12 @@ public class ShellTaskOrganizer extends TaskOrganizer {

            final TaskAppearedInfo info = mTasks.get(taskId);
            if (info == null) {
                throw new IllegalArgumentException("addListenerForTaskId unknown taskId=" + taskId);
                ProtoLog.v(WM_SHELL_TASK_ORG, "Queueing pending listener");
                // The caller may have received a transition with the task before the organizer
                // was notified of the task appearing, so set a pending task listener for the
                // task to be retrieved when the task actually appears
                mPendingTaskToListener.put(taskId, listener);
                return;
            }

            final TaskListener oldListener = getTaskListener(info.getTaskInfo());
@@ -423,6 +431,14 @@ public class ShellTaskOrganizer extends TaskOrganizer {
    public void removeListener(TaskListener listener) {
        synchronized (mLock) {
            ProtoLog.v(WM_SHELL_TASK_ORG, "Remove listener=%s", listener);

            // Remove all occurrences of the pending listener
            for (int i = mPendingTaskToListener.size() - 1; i >= 0; --i) {
                if (mPendingTaskToListener.valueAt(i) == listener) {
                    mPendingTaskToListener.removeAt(i);
                }
            }

            final int index = mTaskListeners.indexOfValue(listener);
            if (index == -1) {
                Log.w(TAG, "No registered listener found");
@@ -438,7 +454,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
                tasks.add(data);
            }

            // Remove listener, there can be the multiple occurrences, so search the whole list.
            // Remove occurrences of the listener
            for (int i = mTaskListeners.size() - 1; i >= 0; --i) {
                if (mTaskListeners.valueAt(i) == listener) {
                    mTaskListeners.removeAt(i);
@@ -456,9 +472,11 @@ public class ShellTaskOrganizer extends TaskOrganizer {

    /**
     * Associated a listener to a pending launch cookie so we can route the task later once it
     * appears.
     * appears.  If both this and a pending task-id listener is set, then this will take priority.
     */
    public void setPendingLaunchCookieListener(IBinder cookie, TaskListener listener) {
        ProtoLog.v(WM_SHELL_TASK_ORG, "setPendingLaunchCookieListener(): cookie=%s listener=%s",
                cookie, listener);
        synchronized (mLock) {
            mLaunchCookieToListener.put(cookie, listener);
        }
@@ -904,7 +922,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
    }

    private TaskListener getTaskListener(RunningTaskInfo runningTaskInfo,
            boolean removeLaunchCookieIfNeeded) {
            boolean removePendingIfNeeded) {

        final int taskId = runningTaskInfo.taskId;
        TaskListener listener;
@@ -916,15 +934,34 @@ public class ShellTaskOrganizer extends TaskOrganizer {
            listener = mLaunchCookieToListener.get(cookie);
            if (listener == null) continue;

            if (removeLaunchCookieIfNeeded) {
            if (removePendingIfNeeded) {
                ProtoLog.v(WM_SHELL_TASK_ORG, "Migrating cookie listener to task: taskId=%d",
                        runningTaskInfo.taskId);
                        taskId);
                // Remove the cookie and add the listener.
                mLaunchCookieToListener.remove(cookie);
                if (mPendingTaskToListener.containsKey(taskId)
                        && mPendingTaskToListener.get(taskId) != listener) {
                    Log.w(TAG, "Conflicting pending task listeners reported for taskId=" + taskId);
                }
                mPendingTaskToListener.remove(taskId);
                mTaskListeners.put(taskId, listener);
            }
            return listener;
        }

        // Next priority goes to the pending task id listener
        if (mPendingTaskToListener.containsKey(taskId)) {
            listener = mPendingTaskToListener.get(taskId);
            if (listener != null) {
                if (removePendingIfNeeded) {
                    ProtoLog.v(WM_SHELL_TASK_ORG, "Migrating pending listener to task: taskId=%d",
                            taskId);
                    mPendingTaskToListener.remove(taskId);
                    mTaskListeners.put(taskId, listener);
                }
                return listener;
            }
        }

        // Next priority goes to taskId specific listeners.
        listener = mTaskListeners.get(taskId);
@@ -1025,13 +1062,21 @@ public class ShellTaskOrganizer extends TaskOrganizer {
            }

            pw.println();
            pw.println(innerPrefix + mLaunchCookieToListener.size() + " Launch Cookies");
            pw.println(innerPrefix + mLaunchCookieToListener.size()
                    + " Pending launch cookies listeners");
            for (int i = mLaunchCookieToListener.size() - 1; i >= 0; --i) {
                final IBinder key = mLaunchCookieToListener.keyAt(i);
                final TaskListener listener = mLaunchCookieToListener.valueAt(i);
                pw.println(innerPrefix + "#" + i + " cookie=" + key + " listener=" + listener);
            }

            pw.println();
            pw.println(innerPrefix + mPendingTaskToListener.size() + " Pending task listeners");
            for (int i = mPendingTaskToListener.size() - 1; i >= 0; --i) {
                final int taskId = mPendingTaskToListener.keyAt(i);
                final TaskListener listener = mPendingTaskToListener.valueAt(i);
                pw.println(innerPrefix + "#" + i + " taskId=" + taskId + " listener=" + listener);
            }
        }
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -123,8 +123,9 @@ public class BubbleTaskViewListener implements TaskView.Listener {
        // Post to keep the lifecycle normal
        // TODO - currently based on type, really it's what the "launch item" is.
        mParentView.post(() -> {
            ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s",
                    getBubbleKey());
            ProtoLog.d(WM_SHELL_BUBBLES,
                    "onInitialized: calling startActivity, bubble=%s hasPreparingTransition=%b",
                    getBubbleKey(), mBubble.getPreparingTransition() != null);
            try {
                options.setTaskAlwaysOnTop(true /* alwaysOnTop */);
                options.setPendingIntentBackgroundActivityStartMode(
+3 −1
Original line number Diff line number Diff line
@@ -690,7 +690,9 @@ public class BubbleTransitions {
            mTaskViewTransitions.prepareOpenAnimation(tv, true /* new */, startT, mFinishT,
                    (ActivityManager.RunningTaskInfo) mTaskInfo, mTaskLeash, mFinishWct);
            // Add the task view task listener manually since we aren't going through
            // TaskViewTransitions (which normally sets up the listener via a pending launch cookie
            // TaskViewTransitions (which normally sets up the listener via a pending launch cookie)
            // Note: In this path, because a new task is being started, the transition may receive
            // the transition for the task before the organizer does
            mTaskOrganizer.addListenerForTaskId(tv, mTaskInfo.taskId);

            if (mFinishWct.isEmpty()) {
+28 −0
Original line number Diff line number Diff line
@@ -296,6 +296,34 @@ public class ShellTaskOrganizerTests extends ShellTestCase {
        assertEquals(1, task1Listener.appeared.size());
    }

    @Test
    public void testAddPendingListenerForTaskId() {
        RunningTaskInfo task1 = createTaskInfo(/* taskId= */ 1, WINDOWING_MODE_MULTI_WINDOW);
        TrackingTaskListener listener = new TrackingTaskListener();

        // Add the listener first, then report the task to the organizer
        mOrganizer.addListenerForTaskId(listener, 1);
        assertFalse(mOrganizer.hasTaskListener(1));
        mOrganizer.onTaskAppeared(task1, /* leash= */ null);

        // Verify that the listener got notified anyways
        assertTrue(listener.appeared.contains(task1));
    }

    @Test
    public void testRemovePendingListenerForTaskId() {
        RunningTaskInfo task1 = createTaskInfo(/* taskId= */ 1, WINDOWING_MODE_MULTI_WINDOW);
        TrackingTaskListener listener = new TrackingTaskListener();

        // Add the listener, remove the listener, then report the task to the organizer
        mOrganizer.addListenerForTaskId(listener, 1);
        mOrganizer.removeListener(listener);
        mOrganizer.onTaskAppeared(task1, /* leash= */ null);

        // Verify that the pending listener does not get notified
        assertFalse(listener.appeared.contains(task1));
    }

    @Test
    public void testAddListenerForTaskId_afterTypeListener() {
        RunningTaskInfo task1 = createTaskInfo(/* taskId= */ 1, WINDOWING_MODE_MULTI_WINDOW);