Run keyguard occlusion update after transitions

Earlier code was calling applyKeyguardOcclusionChange as soon as the
transition starts, which is not very effective because some of the
transitions only update keyguard occluded state at the end of the
animation and race behind this call.

If we wait for all transitions to finish playing before validating
keyguard occlusion, the last word always comes from
applyKeyguardOcclusionChange which synchronises the source of truth
in KeyguardController over to SystemUI.

Test: atest android.server.wm.KeyguardTests
Bug: 275650364
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:140a05907d905e38aa5690320d26c90ca29bf772)
Merged-In: I016b72b87baadb63f3f5f83112901315f29d2f0a
Change-Id: I016b72b87baadb63f3f5f83112901315f29d2f0a
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 54f87d0..a2bd781 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3569,14 +3569,16 @@
 
     @Override
     public int applyKeyguardOcclusionChange() {
-        if (mKeyguardOccludedChanged) {
-            if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded changed occluded="
-                    + mPendingKeyguardOccluded);
-            if (setKeyguardOccludedLw(mPendingKeyguardOccluded)) {
-                return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER;
-            }
+        if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded commit occluded="
+                + mPendingKeyguardOccluded);
+
+        // TODO(b/276433230): Explicitly save before/after for occlude state in each
+        // Transition so we don't need to update SysUI every time.
+        if (setKeyguardOccludedLw(mPendingKeyguardOccluded)) {
+            return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER;
+        } else {
+            return 0;
         }
-        return 0;
     }
 
     /**
@@ -3854,6 +3856,7 @@
     private boolean setKeyguardOccludedLw(boolean isOccluded) {
         if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded);
         mKeyguardOccludedChanged = false;
+        mPendingKeyguardOccluded = isOccluded;
         mKeyguardDelegate.setOccluded(isOccluded, true /* notify */);
         return mKeyguardDelegate.isShowing();
     }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 683767e..adc81f8 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1016,6 +1016,7 @@
             dc.removeImeSurfaceImmediately();
             dc.handleCompleteDeferredRemoval();
         }
+        validateKeyguardOcclusion();
         validateVisibility();
 
         mState = STATE_FINISHED;
@@ -1172,8 +1173,6 @@
             if (mRecentsDisplayId != INVALID_DISPLAY) break;
         }
 
-        handleNonAppWindowsInTransition(mType, mFlags);
-
         // The callback is only populated for custom activity-level client animations
         sendRemoteCallback(mClientAnimationStartCallback);
 
@@ -1477,19 +1476,6 @@
         }
     }
 
-    private void handleNonAppWindowsInTransition(
-            @TransitionType int transit, @TransitionFlags int flags) {
-        if ((flags & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) {
-            // If the occlusion changed but the transition isn't an occlude/unocclude transition,
-            // then we have to notify KeyguardService directly. This can happen if there is
-            // another ongoing transition when the app changes occlusion OR if the app dies or
-            // is killed. Both of these are common during tests.
-            if (transit != TRANSIT_KEYGUARD_OCCLUDE && transit != TRANSIT_KEYGUARD_UNOCCLUDE) {
-                mController.mAtm.mWindowManager.mPolicy.applyKeyguardOcclusionChange();
-            }
-        }
-    }
-
     private void reportStartReasonsToLogger() {
         // Record transition start in metrics logger. We just assume everything is "DRAWN"
         // at this point since splash-screen is a presentation (shell) detail.
@@ -2182,6 +2168,13 @@
         return mainWin.getAttrs().rotationAnimation;
     }
 
+    private void validateKeyguardOcclusion() {
+        if ((mFlags & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) {
+            mController.mStateValidators.add(
+                mController.mAtm.mWindowManager.mPolicy::applyKeyguardOcclusionChange);
+        }
+    }
+
     private void validateVisibility() {
         for (int i = mTargets.size() - 1; i >= 0; --i) {
             if (reduceMode(mTargets.get(i).mReadyMode) != TRANSIT_CLOSE) {