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

Commit 597b031c authored by Chris Li's avatar Chris Li Committed by Android (Google) Code Review
Browse files

Merge "Make sure empty TaskFragment notify organizer" into tm-dev

parents 1d1d37ca 9ebaba81
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}.