Reset the preferred top focus stack when task visibility changes

- The change in visibility of a task does not always trigger a
  stack order change, which won't trigger the previously set
  top focus stack to be reset for the next activity launch.

Bug: 154658401
Test: Verify we don't regress on b/112084174, and open an activity
      from a bubbled task
Change-Id: I8770448b3ac40c384e8e93ca7ee37f1f8aa80cf4
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index d71381e..36951ca 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1010,16 +1010,6 @@
         }
     }
 
-    boolean isTopActivityFocusable() {
-        final ActivityRecord r = topRunningActivity();
-        return r != null ? r.isFocusable()
-                : (isFocusable() && getWindowConfiguration().canReceiveKeys());
-    }
-
-    boolean isFocusableAndVisible() {
-        return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
-    }
-
     // TODO: Should each user have there own stacks?
     @Override
     void switchUser(int userId) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7d7e6aa..3d7d217 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3331,6 +3331,16 @@
         });
     }
 
+    boolean isTopActivityFocusable() {
+        final ActivityRecord r = topRunningActivity();
+        return r != null ? r.isFocusable()
+                : (isFocusable() && getWindowConfiguration().canReceiveKeys());
+    }
+
+    boolean isFocusableAndVisible() {
+        return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
+    }
+
     void positionChildAtTop(ActivityRecord child) {
         positionChildAt(child, POSITION_TOP);
     }
@@ -4626,7 +4636,14 @@
         if (mForceHiddenFlags == newFlags) {
             return false;
         }
+        final boolean wasHidden = isForceHidden();
         mForceHiddenFlags = newFlags;
+        if (wasHidden && isFocusableAndVisible()) {
+            // The change in force-hidden state will change visibility without triggering a stack
+            // order change, so we should reset the preferred top focusable stack to ensure it's not
+            // used if a new activity is started from this task.
+            getDisplayArea().resetPreferredTopFocusableStackIfBelow(this);
+        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 3dc6723..2b0de9b 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -680,6 +680,13 @@
         onStackOrderChanged(stack);
     }
 
+    void resetPreferredTopFocusableStackIfBelow(Task task) {
+        if (mPreferredTopFocusableStack != null
+                && mPreferredTopFocusableStack.compareTo(task) < 0) {
+            mPreferredTopFocusableStack = null;
+        }
+    }
+
     void positionStackAt(int position, ActivityStack child, boolean includingParents) {
         positionChildAt(position, child, includingParents);
         mDisplayContent.layoutAndAssignWindowLayersIfNeeded();