Remove token behind fullscreen activity from unknown visibility

When launching activity while keyguard is locked, their window tokens
will be added into unknown visibility controller to smooth the transition.
But if there are multiple starting activities without attached process,
only the last started activity will be resumed. Then the prior activities
are left in unknown visibility and cause transition timeout.

It is resolved by removing the unknown visibility records that won't be
visible when resuming top activity. Also consolidate shouldBeVisible and
shouldBeVisibleIgnoringKeyguard to reduce duplicated checking.

Bug: 123540470
Bug: 141826987
Test: atest ActivityStackTests# \
            testClearUnknownAppVisibilityBehindFullscreenActivity

Change-Id: Ie6d11e856a2b81a39222a0d96644712ce8ddf955
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0d95706..eeee062 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4439,34 +4439,30 @@
         removeStartingWindow();
     }
 
-    void notifyUnknownVisibilityLaunched() {
-
+    /**
+     * Suppress transition until the new activity becomes ready, otherwise the keyguard can appear
+     * for a short amount of time before the new process with the new activity had the ability to
+     * set its showWhenLocked flags.
+     */
+    void notifyUnknownVisibilityLaunchedForKeyguardTransition() {
         // No display activities never add a window, so there is no point in waiting them for
         // relayout.
-        if (!noDisplay && getDisplayContent() != null) {
-            getDisplayContent().mUnknownAppVisibilityController.notifyLaunched(this);
-        }
-    }
-
-    /**
-     * @return true if the input activity should be made visible, ignoring any effect Keyguard
-     * might have on the visibility
-     *
-     * TODO(b/123540470): Combine this method and {@link #shouldBeVisible(boolean)}.
-     *
-     * @see {@link ActivityStack#checkKeyguardVisibility}
-     */
-    boolean shouldBeVisibleIgnoringKeyguard(boolean behindFullscreenActivity) {
-        if (!okToShowLocked()) {
-            return false;
+        if (noDisplay || !mStackSupervisor.getKeyguardController().isKeyguardLocked()) {
+            return;
         }
 
-        return !behindFullscreenActivity || mLaunchTaskBehind;
+        mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(this);
     }
 
-    boolean shouldBeVisible(boolean behindFullscreenActivity) {
+    /** @return {@code true} if this activity should be made visible. */
+    boolean shouldBeVisible(boolean behindFullscreenActivity, boolean ignoringKeyguard) {
         // Check whether activity should be visible without Keyguard influence
-        visibleIgnoringKeyguard = shouldBeVisibleIgnoringKeyguard(behindFullscreenActivity);
+        visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
+                && okToShowLocked();
+
+        if (ignoringKeyguard) {
+            return visibleIgnoringKeyguard;
+        }
 
         final ActivityStack stack = getActivityStack();
         if (stack == null) {
@@ -4495,9 +4491,9 @@
             return false;
         }
 
-        // TODO: Use real value of behindFullscreenActivity calculated using the same logic in
-        // ActivityStack#ensureActivitiesVisibleLocked().
-        return shouldBeVisible(!stack.shouldBeVisible(null /* starting */));
+        final boolean behindFullscreenActivity = stack.checkBehindFullscreenActivity(
+                this, null /* handleBehindFullscreenActivity */);
+        return shouldBeVisible(behindFullscreenActivity, false /* ignoringKeyguard */);
     }
 
     void makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient) {
@@ -5538,12 +5534,26 @@
         }
     }
 
-    void removeOrphanedStartingWindow(boolean behindFullscreenActivity) {
-        if (mStartingWindowState == STARTING_WINDOW_SHOWN && behindFullscreenActivity) {
+    /**
+     * If any activities below the top running one are in the INITIALIZING state and they have a
+     * starting window displayed then remove that starting window. It is possible that the activity
+     * in this state will never resumed in which case that starting window will be orphaned.
+     * <p>
+     * It should only be called if this activity is behind other fullscreen activity.
+     */
+    void cancelInitializing() {
+        if (mStartingWindowState == STARTING_WINDOW_SHOWN) {
+            // Remove orphaned starting window.
             if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
             mStartingWindowState = STARTING_WINDOW_REMOVED;
             removeStartingWindow();
         }
+        if (isState(INITIALIZING) && !shouldBeVisible(
+                true /* behindFullscreenActivity */, true /* ignoringKeyguard */)) {
+            // Remove the unknown visibility record because an invisible activity shouldn't block
+            // the keyguard transition.
+            mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
+        }
     }
 
     void postWindowRemoveStartingWindowCleanup(WindowState win) {