Check idle activity from all activity container
The home task could be:
TaskHome
- TaskFragment
- ActivityB
- ActivityA
Then forAllLeafTaskFragments won't iterate ActivityA under TaskHome
because it is a leaf Task but not a leaf TaskFragment. So separate
the procedure to forAllLeafTasks + forAllLeafTaskFragments.
Fix: 360946107
Flag: EXEMPT bugfix
Test: atest RootWindowContainerTests#testAllResumedActivitiesIdle
Change-Id: I2bb4bc7d141163d47f16c0e895afa451f46157d5
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 4ca4730..862f84d 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3426,6 +3426,25 @@
return null;
}
+ /** Returns the top direct activity if it should be idle but has not yet been reported. */
+ @Nullable
+ private static ActivityRecord getNotYetIdleActivity(@NonNull TaskFragment visibleTf) {
+ for (int i = visibleTf.getChildCount() - 1; i >= 0; i--) {
+ final ActivityRecord r = visibleTf.getChildAt(i).asActivityRecord();
+ if (r == null || r.finishing) {
+ continue;
+ }
+ if (!r.idle && (r.isState(RESUMED)
+ // Its process is not attached yet and it may resume later.
+ || (r.app == null && r.isFocusable()))) {
+ return r;
+ }
+ // Only check the top running activity.
+ break;
+ }
+ return null;
+ }
+
boolean allResumedActivitiesIdle() {
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
@@ -3434,19 +3453,31 @@
continue;
}
- final boolean foundNotIdle = display.forAllLeafTaskFragments(tf -> {
- if (!tf.isVisibleRequested()) {
+ final boolean foundNotIdle = display.forAllLeafTasks(task -> {
+ if (!task.isVisibleRequested()) {
return false;
}
- // Note that only activities that will be resumed can report idle.
- final ActivityRecord r = tf.topRunningActivity();
- if (r != null && !r.idle && (r.isState(RESUMED)
- // Its process is not attached yet and it may resume later.
- || (r.app == null && r.isFocusable()))) {
- ProtoLog.d(WM_DEBUG_STATES, "allResumedActivitiesIdle: %s not idle", r);
+ final ActivityRecord notIdle = getNotYetIdleActivity(task);
+ if (notIdle != null) {
+ ProtoLog.d(WM_DEBUG_STATES, "allResumedActivitiesIdle: %s not idle", notIdle);
return true;
}
- return false;
+ if (task.isLeafTaskFragment()) {
+ // The task doesn't contain child TaskFragment.
+ return false;
+ }
+ return task.forAllLeafTaskFragments(tf -> {
+ if (!tf.isVisibleRequested()) {
+ return false;
+ }
+ final ActivityRecord tfNotIdle = getNotYetIdleActivity(tf);
+ if (tfNotIdle != null) {
+ ProtoLog.d(WM_DEBUG_STATES, "allResumedActivitiesIdle: %s not idle",
+ tfNotIdle);
+ return true;
+ }
+ return false;
+ });
});
if (foundNotIdle) {
return false;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 4ab2fcf..f1db713 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -224,6 +224,22 @@
activity1.idle = false;
activity1.setVisibleRequested(false);
assertThat(mWm.mRoot.allResumedActivitiesIdle()).isTrue();
+
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(activity2.getTask()).build();
+ final ActivityRecord activity3 = new ActivityBuilder(mAtm).build();
+ taskFragment.addChild(activity3);
+ taskFragment.setVisibleRequested(true);
+ activity3.setState(RESUMED, "test");
+ activity3.idle = true;
+ assertThat(mWm.mRoot.allResumedActivitiesIdle()).isTrue();
+
+ activity3.idle = false;
+ assertThat(mWm.mRoot.allResumedActivitiesIdle()).isFalse();
+
+ activity2.idle = false;
+ activity3.idle = true;
+ assertThat(mWm.mRoot.allResumedActivitiesIdle()).isFalse();
}
@Test