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

Commit 7752715c authored by Rob Carr's avatar Rob Carr Committed by Android (Google) Code Review
Browse files

Merge "TaskOrganizer: Implement lifetime changes for testing."

parents cd240190 7d7c8abe
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -356,6 +356,8 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
    // TODO(task-hierarchy): remove when tiles can be actual parents
    TaskTile mTile = null;

    private int mLastTaskOrganizerWindowingMode = -1;

    private final Handler mHandler;

    private class ActivityStackHandler extends Handler {
@@ -794,6 +796,13 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
        }

        final int windowingMode = getWindowingMode();
        if (windowingMode == mLastTaskOrganizerWindowingMode) {
            // If our windowing mode hasn't actually changed, then just stick
            // with our old organizer. This lets us implement the semantic
            // where SysUI can continue to manage it's old tasks
            // while CTS temporarily takes over the registration.
            return;
        }
        /*
         * Different windowing modes may be managed by different task organizers. If
         * getTaskOrganizer returns null, we still call setTaskOrganizer to
@@ -802,6 +811,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
        final ITaskOrganizer org =
            mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
        setTaskOrganizer(org);
        mLastTaskOrganizerWindowingMode = windowingMode;
    }

    @Override
+73 −52
Original line number Diff line number Diff line
@@ -74,11 +74,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
        @Override
        public void binderDied() {
            synchronized (mGlobalLock) {
                final TaskOrganizerState state = mTaskOrganizerStates.get(mTaskOrganizer);
                for (int i = 0; i < state.mOrganizedTasks.size(); i++) {
                    state.mOrganizedTasks.get(i).taskOrganizerDied();
                }
                mTaskOrganizerStates.remove(mTaskOrganizer);
                final TaskOrganizerState state =
                    mTaskOrganizerStates.get(mTaskOrganizer.asBinder());
                state.releaseTasks();
                mTaskOrganizerStates.remove(mTaskOrganizer.asBinder());
                if (mTaskOrganizersForWindowingMode.get(mWindowingMode) == mTaskOrganizer) {
                    mTaskOrganizersForWindowingMode.remove(mWindowingMode);
                }
@@ -89,26 +88,76 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
    class TaskOrganizerState {
        ITaskOrganizer mOrganizer;
        DeathRecipient mDeathRecipient;
        int mWindowingMode;

        ArrayList<Task> mOrganizedTasks = new ArrayList<>();

        // Save the TaskOrganizer which we replaced registration for
        // so it can be re-registered if we unregister.
        TaskOrganizerState mReplacementFor;
        boolean mDisposed = false;


        TaskOrganizerState(ITaskOrganizer organizer, int windowingMode,
                TaskOrganizerState replacing) {
            mOrganizer = organizer;
            mDeathRecipient = new DeathRecipient(organizer, windowingMode);
            try {
                organizer.asBinder().linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                Slog.e(TAG, "TaskOrganizer failed to register death recipient");
            }
            mWindowingMode = windowingMode;
            mReplacementFor = replacing;
        }

        void addTask(Task t) {
            mOrganizedTasks.add(t);
            try {
                mOrganizer.taskAppeared(t.getTaskInfo());
            } catch (Exception e) {
                Slog.e(TAG, "Exception sending taskAppeared callback" + e);
            }
        }

        void removeTask(Task t) {
            try {
                mOrganizer.taskVanished(t.getRemoteToken());
            } catch (Exception e) {
                Slog.e(TAG, "Exception sending taskVanished callback" + e);
            }
            mOrganizedTasks.remove(t);
        }

        TaskOrganizerState(ITaskOrganizer organizer, DeathRecipient deathRecipient) {
            mOrganizer = organizer;
            mDeathRecipient = deathRecipient;
        void dispose() {
            mDisposed = true;
            releaseTasks();
            handleReplacement();
        }

        void releaseTasks() {
            for (int i = mOrganizedTasks.size() - 1; i >= 0; i--) {
                final Task t = mOrganizedTasks.get(i);
                t.taskOrganizerDied();
                removeTask(t);
            }
        }

        void handleReplacement() {
            if (mReplacementFor != null && !mReplacementFor.mDisposed) {
                mTaskOrganizersForWindowingMode.put(mWindowingMode, mReplacementFor);
            }
        }

        void unlinkDeath() {
            mDisposed = true;
            mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0);
        }
    };


    final HashMap<Integer, TaskOrganizerState> mTaskOrganizersForWindowingMode = new HashMap();
    final HashMap<ITaskOrganizer, TaskOrganizerState> mTaskOrganizerStates = new HashMap();
    final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap();

    final HashMap<Integer, ITaskOrganizer> mTaskOrganizersByPendingSyncId = new HashMap();

@@ -128,17 +177,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
        mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
    }

    private void clearIfNeeded(int windowingMode) {
        final TaskOrganizerState oldState = mTaskOrganizersForWindowingMode.get(windowingMode);
        if (oldState != null) {
            oldState.mOrganizer.asBinder().unlinkToDeath(oldState.mDeathRecipient, 0);
        }
    }

    /**
     * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
     * If there was already a TaskOrganizer for this windowing mode it will be evicted
     * and receive taskVanished callbacks in the process.
     * but will continue to organize it's existing tasks.
     */
    @Override
    public void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
@@ -153,24 +195,25 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (mGlobalLock) {
                clearIfNeeded(windowingMode);
                DeathRecipient dr = new DeathRecipient(organizer, windowingMode);
                try {
                    organizer.asBinder().linkToDeath(dr, 0);
                } catch (RemoteException e) {
                    Slog.e(TAG, "TaskOrganizer failed to register death recipient");
                }

                final TaskOrganizerState state = new TaskOrganizerState(organizer, dr);
                final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode,
                        mTaskOrganizersForWindowingMode.get(windowingMode));
                mTaskOrganizersForWindowingMode.put(windowingMode, state);

                mTaskOrganizerStates.put(organizer, state);
                mTaskOrganizerStates.put(organizer.asBinder(), state);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

    void unregisterTaskOrganizer(ITaskOrganizer organizer) {
        final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
        state.unlinkDeath();
        if (mTaskOrganizersForWindowingMode.get(state.mWindowingMode) == state) {
            mTaskOrganizersForWindowingMode.remove(state.mWindowingMode);
        }
        state.dispose();
    }

    ITaskOrganizer getTaskOrganizer(int windowingMode) {
        final TaskOrganizerState state = mTaskOrganizersForWindowingMode.get(windowingMode);
        if (state == null) {
@@ -179,35 +222,13 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
        return state.mOrganizer;
    }

    private void sendTaskAppeared(ITaskOrganizer organizer, Task task) {
        try {
            organizer.taskAppeared(task.getTaskInfo());
        } catch (Exception e) {
            Slog.e(TAG, "Exception sending taskAppeared callback" + e);
        }
    }

    private void sendTaskVanished(ITaskOrganizer organizer, Task task) {
        try {
            organizer.taskVanished(task.getRemoteToken());
        } catch (Exception e) {
            Slog.e(TAG, "Exception sending taskVanished callback" + e);
        }
    }

    void onTaskAppeared(ITaskOrganizer organizer, Task task) {
        TaskOrganizerState state = mTaskOrganizerStates.get(organizer);

        TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
        state.addTask(task);
        sendTaskAppeared(organizer, task);
    }

    void onTaskVanished(ITaskOrganizer organizer, Task task) {
        final TaskOrganizerState state = mTaskOrganizerStates.get(organizer);
        sendTaskVanished(organizer, task);

        // This could trigger TaskAppeared for other tasks in the same stack so make sure
        // we do this AFTER sending taskVanished.
        final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
        state.removeTask(task);
    }

+46 −0
Original line number Diff line number Diff line
@@ -138,6 +138,52 @@ public class TaskOrganizerTests extends WindowTestsBase {
        assertFalse(stack.isControlledByTaskOrganizer());
    }

    @Test
    public void testUnregisterOrganizer() throws RemoteException {
        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
        final Task task = createTaskInStack(stack, 0 /* userId */);
        final ITaskOrganizer organizer = registerMockOrganizer();

        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        verify(organizer).taskAppeared(any());
        assertTrue(stack.isControlledByTaskOrganizer());

        mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
        verify(organizer).taskVanished(any());
        assertFalse(stack.isControlledByTaskOrganizer());
    }

    @Test
    public void testUnregisterOrganizerReturnsRegistrationToPrevious() throws RemoteException {
        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
        final Task task = createTaskInStack(stack, 0 /* userId */);
        final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent);
        final Task task2 = createTaskInStack(stack2, 0 /* userId */);
        final ActivityStack stack3 = createTaskStackOnDisplay(mDisplayContent);
        final Task task3 = createTaskInStack(stack3, 0 /* userId */);
        final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);

        // First organizer is registered, verify a task appears when changing windowing mode
        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        verify(organizer, times(1)).taskAppeared(any());
        assertTrue(stack.isControlledByTaskOrganizer());

        // Now we replace the registration and1 verify the new organizer receives tasks
        // newly entering the windowing mode.
        final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
        stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        verify(organizer2).taskAppeared(any());
        assertTrue(stack2.isControlledByTaskOrganizer());

        // 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);

        stack3.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        verify(organizer, times(2)).taskAppeared(any());
        assertTrue(stack3.isControlledByTaskOrganizer());
    }

    @Test
    public void testRegisterTaskOrganizerStackWindowingModeChanges() throws RemoteException {
        final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);