Merge "Make sure empty TaskFragment notify organizer" into tm-dev
This commit is contained in:
@@ -181,7 +181,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
|
||||||
tf.getName());
|
tf.getName());
|
||||||
try {
|
try {
|
||||||
mOrganizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
|
mOrganizer.onTaskFragmentInfoChanged(info);
|
||||||
mLastSentTaskFragmentInfos.put(tf, info);
|
mLastSentTaskFragmentInfos.put(tf, info);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.d(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
|
Slog.d(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
|
||||||
@@ -424,6 +424,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
}
|
}
|
||||||
// Remove and add for re-ordering.
|
// Remove and add for re-ordering.
|
||||||
mPendingTaskFragmentEvents.remove(pendingEvent);
|
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);
|
mPendingTaskFragmentEvents.add(pendingEvent);
|
||||||
}
|
}
|
||||||
@@ -654,26 +658,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldSendEventWhenTaskInvisible(@NonNull Task task,
|
private boolean shouldSendEventWhenTaskInvisible(@NonNull PendingTaskFragmentEvent event) {
|
||||||
@NonNull PendingTaskFragmentEvent event) {
|
|
||||||
final TaskFragmentOrganizerState state =
|
final TaskFragmentOrganizerState state =
|
||||||
mTaskFragmentOrganizerState.get(event.mTaskFragmentOrg.asBinder());
|
mTaskFragmentOrganizerState.get(event.mTaskFragmentOrg.asBinder());
|
||||||
final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos.get(event.mTaskFragment);
|
final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos.get(event.mTaskFragment);
|
||||||
final TaskFragmentInfo info = event.mTaskFragment.getTaskFragmentInfo();
|
final TaskFragmentInfo info = event.mTaskFragment.getTaskFragmentInfo();
|
||||||
// Send an info changed callback if this event is for the last activities to finish in a
|
// 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,
|
// TaskFragment so that the {@link TaskFragmentOrganizer} can delete this TaskFragment.
|
||||||
// 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.
|
|
||||||
return event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED
|
return event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED
|
||||||
&& (task.topRunningActivity() == null || info.isTaskFragmentClearedForPip())
|
&& lastInfo != null && lastInfo.hasRunningActivity() && info.isEmpty();
|
||||||
&& lastInfo != null
|
|
||||||
&& lastInfo.getRunningActivityCount() > 0 && info.getRunningActivityCount() == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatchPendingEvents() {
|
void dispatchPendingEvents() {
|
||||||
@@ -690,7 +683,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
|
final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
|
||||||
if (task != null && (task.lastActiveTime <= event.mDeferTime
|
if (task != null && (task.lastActiveTime <= event.mDeferTime
|
||||||
|| !(isTaskVisible(task, visibleTasks, invisibleTasks)
|
|| !(isTaskVisible(task, visibleTasks, invisibleTasks)
|
||||||
|| shouldSendEventWhenTaskInvisible(task, event)))) {
|
|| shouldSendEventWhenTaskInvisible(event)))) {
|
||||||
// Defer sending events to the TaskFragment until the host task is active again.
|
// Defer sending events to the TaskFragment until the host task is active again.
|
||||||
event.mDeferTime = task.lastActiveTime;
|
event.mDeferTime = task.lastActiveTime;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -778,6 +778,47 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
verify(mOrganizer).onTaskFragmentInfoChanged(any());
|
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
|
* When an embedded {@link TaskFragment} is removed, we should clean up the reference in the
|
||||||
* {@link WindowOrganizerController}.
|
* {@link WindowOrganizerController}.
|
||||||
|
|||||||
Reference in New Issue
Block a user