summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShivam Agrawal <shivamagrawal@google.com>2022-01-12 15:09:58 -0500
committerShivam Agrawal <shivamagrawal@google.com>2022-01-14 15:13:50 -0500
commit09e0a6e823a77a6fd0d1b5a1e0d16880f8b46e56 (patch)
tree50cdd67d3eed5dd1cc4f899be78ba15f3bef83bd
parent5a2d06b5f10203d952d1990a1f9154bd05e52fa5 (diff)
Send Task Fragment Info Update When Task Invisible...
...only when the Task has no more running activities. Send a TaskFragment info changed callback if the callback is for the last activities to finish in a Task so that the TaskFragmentOrganizer can delete this TaskFragment. Otherwise, the Task may be removed before it becomes visible again to send this callback 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. Bug: b/214090984 Test: atest TaskFragmentOrganizerControllerTest Test: atest ActivityEmbeddingLaunchTests Change-Id: Idb58975f4bfb6c67ed6cda3dc6b7c33abd960bbd
-rw-r--r--services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java21
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java38
2 files changed, 58 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index c7fdefc412cc..123ca889c73e 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -22,6 +22,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANI
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -497,6 +498,23 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return null;
}
+ private boolean shouldSendEventWhenTaskInvisible(@NonNull Task task,
+ @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.
+ return event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED
+ && task.topRunningActivity() == null && lastInfo != null
+ && lastInfo.getRunningActivityCount() > 0 && info.getRunningActivityCount() == 0;
+ }
+
void dispatchPendingEvents() {
if (mAtmService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
|| mPendingTaskFragmentEvents.isEmpty()) {
@@ -510,7 +528,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
final PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
if (task != null && (task.lastActiveTime <= event.mDeferTime
- || !isTaskVisible(task, visibleTasks, invisibleTasks))) {
+ || !(isTaskVisible(task, visibleTasks, invisibleTasks)
+ || shouldSendEventWhenTaskInvisible(task, event)))) {
// Defer sending events to the TaskFragment until the host task is active again.
event.mDeferTime = task.lastActiveTime;
continue;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index dcaf9d7ae434..f8c7207cefa7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -21,14 +21,17 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.testing.Assert.assertThrows;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import android.content.Intent;
@@ -471,6 +474,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
.setOrganizer(mOrganizer)
+ .setFragmentToken(mFragmentToken)
.build();
// Mock the task to invisible
@@ -485,4 +489,38 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Verifies that event was not sent
verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
}
+
+ /**
+ * Tests that a task fragment info changed event is still sent if the task is invisible only
+ * when the info changed event is because of the last activity in a task finishing.
+ */
+ @Test
+ public void testLastPendingTaskFragmentInfoChangedEventOfInvisibleTaskSent() {
+ // Create a TaskFragment with an activity, all within a parent task
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setOrganizer(mOrganizer)
+ .setFragmentToken(mFragmentToken)
+ .setCreateParentTask()
+ .createActivityCount(1)
+ .build();
+ final Task parentTask = taskFragment.getTask();
+ final ActivityRecord activity = taskFragment.getTopNonFinishingActivity();
+ assertTrue(parentTask.shouldBeVisible(null));
+
+ // Dispatch pending info changed event from creating the activity
+ mController.registerOrganizer(mIOrganizer);
+ taskFragment.mTaskFragmentAppearedSent = true;
+ mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
+ mController.dispatchPendingEvents();
+
+ // Finish the activity and verify that the task is invisible
+ activity.finishing = true;
+ assertFalse(parentTask.shouldBeVisible(null));
+
+ // Verify the info changed callback still occurred despite the task being invisible
+ reset(mOrganizer);
+ mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
+ mController.dispatchPendingEvents();
+ verify(mOrganizer).onTaskFragmentInfoChanged(any());
+ }
}