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

Commit c6d436c0 authored by Chris Li's avatar Chris Li Committed by Automerger Merge Worker
Browse files

Merge "Make sure empty TaskFragment notify organizer" into tm-dev am: 597b031c am: 81eca7ea

parents 22e38062 81eca7ea
Loading
Loading
Loading
Loading
+9 −16
Original line number Diff line number Diff line
@@ -181,7 +181,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
                    tf.getName());
            try {
                mOrganizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
                mOrganizer.onTaskFragmentInfoChanged(info);
                mLastSentTaskFragmentInfos.put(tf, info);
            } catch (RemoteException e) {
                Slog.d(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
@@ -424,6 +424,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
            }
            // Remove and add for re-ordering.
            mPendingTaskFragmentEvents.remove(pendingEvent);
            // Reset the defer time when TaskFragment is changed, so that it can check again if
            // the event should be sent to the organizer, for example the TaskFragment may become
            // empty.
            pendingEvent.mDeferTime = 0;
        }
        mPendingTaskFragmentEvents.add(pendingEvent);
    }
@@ -654,26 +658,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
        return null;
    }

    private boolean shouldSendEventWhenTaskInvisible(@NonNull Task task,
            @NonNull PendingTaskFragmentEvent event) {
    private boolean shouldSendEventWhenTaskInvisible(@NonNull PendingTaskFragmentEvent event) {
        final TaskFragmentOrganizerState state =
                mTaskFragmentOrganizerState.get(event.mTaskFragmentOrg.asBinder());
        final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos.get(event.mTaskFragment);
        final TaskFragmentInfo info = event.mTaskFragment.getTaskFragmentInfo();
        // Send an info changed callback if this event is for the last activities to finish in a
        // Task so that the {@link TaskFragmentOrganizer} can delete this TaskFragment. Otherwise,
        // the Task may be removed before it becomes visible again to send this event because it no
        // longer has activities. As a result, the organizer will never get this info changed event
        // and will not delete the TaskFragment because the organizer thinks the TaskFragment still
        // has running activities.
        // Another case is when an organized TaskFragment became empty because the last running
        // activity is reparented to a new Task due to enter PiP. We also want to notify the
        // organizer, so it can remove the empty TaskFragment and update the paired TaskFragment
        // without causing the extra delay.
        // TaskFragment so that the {@link TaskFragmentOrganizer} can delete this TaskFragment.
        return event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED
                && (task.topRunningActivity() == null || info.isTaskFragmentClearedForPip())
                && lastInfo != null
                && lastInfo.getRunningActivityCount() > 0 && info.getRunningActivityCount() == 0;
                && lastInfo != null && lastInfo.hasRunningActivity() && info.isEmpty();
    }

    void dispatchPendingEvents() {
@@ -690,7 +683,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
            final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
            if (task != null && (task.lastActiveTime <= event.mDeferTime
                    || !(isTaskVisible(task, visibleTasks, invisibleTasks)
                    || shouldSendEventWhenTaskInvisible(task, event)))) {
                    || shouldSendEventWhenTaskInvisible(event)))) {
                // Defer sending events to the TaskFragment until the host task is active again.
                event.mDeferTime = task.lastActiveTime;
                continue;
+41 −0
Original line number Diff line number Diff line
@@ -778,6 +778,47 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
        verify(mOrganizer).onTaskFragmentInfoChanged(any());
    }

    /**
     * Tests that a task fragment info changed event is sent if the TaskFragment becomes empty
     * even if the Task is invisible.
     */
    @Test
    public void testPendingTaskFragmentInfoChangedEvent_emptyTaskFragment() {
        // Create a TaskFragment with an activity, all within a parent task
        final Task task = createTask(mDisplayContent);
        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
                .setParentTask(task)
                .setOrganizer(mOrganizer)
                .setFragmentToken(mFragmentToken)
                .createActivityCount(1)
                .build();
        final ActivityRecord embeddedActivity = taskFragment.getTopNonFinishingActivity();
        // Add another activity in the Task so that it always contains a non-finishing activitiy.
        final ActivityRecord nonEmbeddedActivity = createActivityRecord(task);
        assertTrue(task.shouldBeVisible(null));

        // Dispatch pending info changed event from creating the activity
        mController.registerOrganizer(mIOrganizer);
        taskFragment.mTaskFragmentAppearedSent = true;
        mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
        mController.dispatchPendingEvents();
        verify(mOrganizer).onTaskFragmentInfoChanged(any());

        // Verify the info changed callback is not called when the task is invisible
        reset(mOrganizer);
        doReturn(false).when(task).shouldBeVisible(any());
        mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
        mController.dispatchPendingEvents();
        verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());

        // Finish the embedded activity, and verify the info changed callback is called because the
        // TaskFragment is becoming empty.
        embeddedActivity.finishing = true;
        mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
        mController.dispatchPendingEvents();
        verify(mOrganizer).onTaskFragmentInfoChanged(any());
    }

    /**
     * When an embedded {@link TaskFragment} is removed, we should clean up the reference in the
     * {@link WindowOrganizerController}.