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

This commit is contained in:
Chris Li
2022-05-03 13:33:54 +00:00
committed by Android (Google) Code Review
2 changed files with 50 additions and 16 deletions

View File

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

View File

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