Handle keyguard occlude/unocclude in shell transitions

Turns out this can just be checked when the transition starts.
However, added a flag so that shell knows.

Bug: 162500279
Test: enable shell transitions, lock screen, then open camera and
      close camera.
Change-Id: I57703ed8040172496f7091cdae11489df8724c53
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index b9afbc9..36f75c6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -418,6 +418,12 @@
     int TRANSIT_FLAG_OPEN_BEHIND = 0x20;
 
     /**
+     * Transition flag: The keyguard is locked throughout the whole transition.
+     * @hide
+     */
+    int TRANSIT_FLAG_KEYGUARD_LOCKED = 0x40;
+
+    /**
      * @hide
      */
     @IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = {
@@ -426,7 +432,8 @@
             TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER,
             TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION,
             TRANSIT_FLAG_APP_CRASHED,
-            TRANSIT_FLAG_OPEN_BEHIND
+            TRANSIT_FLAG_OPEN_BEHIND,
+            TRANSIT_FLAG_KEYGUARD_LOCKED
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface TransitionFlags {}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index b4e7d6a..2146272 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -65,18 +65,22 @@
     public @interface TransitionMode {}
 
     private final @WindowManager.TransitionOldType int mType;
+    private final @WindowManager.TransitionFlags int mFlags;
     private final ArrayList<Change> mChanges = new ArrayList<>();
 
     private SurfaceControl mRootLeash;
     private final Point mRootOffset = new Point();
 
     /** @hide */
-    public TransitionInfo(@WindowManager.TransitionOldType int type) {
+    public TransitionInfo(@WindowManager.TransitionOldType int type,
+            @WindowManager.TransitionFlags int flags) {
         mType = type;
+        mFlags = flags;
     }
 
     private TransitionInfo(Parcel in) {
         mType = in.readInt();
+        mFlags = in.readInt();
         in.readList(mChanges, null /* classLoader */);
         mRootLeash = new SurfaceControl();
         mRootLeash.readFromParcel(in);
@@ -87,6 +91,7 @@
     /** @hide */
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mType);
+        dest.writeInt(mFlags);
         dest.writeList(mChanges);
         mRootLeash.writeToParcel(dest, flags);
         mRootOffset.writeToParcel(dest, flags);
@@ -122,6 +127,10 @@
         return mType;
     }
 
+    public int getFlags() {
+        return mFlags;
+    }
+
     /**
      * @return a surfacecontrol that can serve as a parent surfacecontrol for all the changing
      * participants to animate within. This will generally be placed at the highest-z-order
@@ -170,7 +179,8 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("{t=" + mType + " ro=" + mRootOffset + " c=[");
+        sb.append("{t=" + mType + " f=" + Integer.toHexString(mFlags)
+                + " ro=" + mRootOffset + " c=[");
         for (int i = 0; i < mChanges.size(); ++i) {
             if (i > 0) {
                 sb.append(',');
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8beec35eb..f7af722 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3193,7 +3193,8 @@
         }
     }
 
-    private int handleStartTransitionForKeyguardLw(boolean keyguardGoingAway, long duration) {
+    @Override
+    public int applyKeyguardOcclusionChange() {
         if (mKeyguardOccludedChanged) {
             if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded changed occluded="
                     + mPendingKeyguardOccluded);
@@ -3202,6 +3203,12 @@
                 return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER;
             }
         }
+        return 0;
+    }
+
+    private int handleStartTransitionForKeyguardLw(boolean keyguardGoingAway, long duration) {
+        final int res = applyKeyguardOcclusionChange();
+        if (res != 0) return res;
         if (keyguardGoingAway) {
             if (DEBUG_KEYGUARD) Slog.d(TAG, "Starting keyguard exit animation");
             startKeyguardExitAnimation(SystemClock.uptimeMillis(), duration);
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 6934e5c..977b31e 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -172,6 +172,9 @@
      */
     void onKeyguardOccludedChangedLw(boolean occluded);
 
+    /** Applies a keyguard occlusion change if one happened. */
+    int applyKeyguardOcclusionChange();
+
     /**
      * Interface to the Window Manager state associated with a particular
      * window. You can hold on to an instance of this interface from the call
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 0cdd055..cd6a2d7 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 
 import android.annotation.IntDef;
@@ -282,9 +283,13 @@
         mState = STATE_PLAYING;
         mController.moveToPlaying(this);
 
+        if (mController.mAtm.mTaskSupervisor.getKeyguardController().isKeyguardLocked()) {
+            mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED;
+        }
+
         // Resolve the animating targets from the participants
         mTargets = calculateTargets(mParticipants, mChanges);
-        final TransitionInfo info = calculateTransitionInfo(mType, mTargets, mChanges);
+        final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges);
         mRootLeash = info.getRootLeash();
 
         handleNonAppWindowsInTransition(displayId, mType, mFlags);
@@ -337,6 +342,9 @@
             mController.mAtm.mWindowManager.mPolicy.startKeyguardExitAnimation(
                     SystemClock.uptimeMillis(), 0 /* duration */);
         }
+        if ((flags & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) {
+            mController.mAtm.mWindowManager.mPolicy.applyKeyguardOcclusionChange();
+        }
     }
 
     @Override
@@ -587,9 +595,9 @@
      */
     @VisibleForTesting
     @NonNull
-    static TransitionInfo calculateTransitionInfo(int type, ArraySet<WindowContainer> targets,
-            ArrayMap<WindowContainer, ChangeInfo> changes) {
-        final TransitionInfo out = new TransitionInfo(type);
+    static TransitionInfo calculateTransitionInfo(int type, int flags,
+            ArraySet<WindowContainer> targets, ArrayMap<WindowContainer, ChangeInfo> changes) {
+        final TransitionInfo out = new TransitionInfo(type, flags);
         if (targets.isEmpty()) {
             out.setRootLeash(new SurfaceControl(), 0, 0);
             return out;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index eb5f1f9..ccf2394 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -372,6 +372,11 @@
     }
 
     @Override
+    public int applyKeyguardOcclusionChange() {
+        return 0;
+    }
+
+    @Override
     public void setPipVisibilityLw(boolean visible) {
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 4909b1d..728ecdb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -74,21 +74,22 @@
         closing.mVisibleRequested = false;
         opening.mVisibleRequested = true;
 
-        int transitType = TRANSIT_OLD_TASK_OPEN;
+        int transit = TRANSIT_OLD_TASK_OPEN;
+        int flags = 0;
 
         // Check basic both tasks participating
         participants.add(oldTask);
         participants.add(newTask);
         ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
-        TransitionInfo info = Transition.calculateTransitionInfo(transitType, targets, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
         assertEquals(2, info.getChanges().size());
-        assertEquals(transitType, info.getType());
+        assertEquals(transit, info.getType());
 
         // Check that children are pruned
         participants.add(opening);
         participants.add(closing);
         targets = Transition.calculateTargets(participants, changes);
-        info = Transition.calculateTransitionInfo(transitType, targets, changes);
+        info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -96,7 +97,7 @@
         // Check combined prune and promote
         participants.remove(newTask);
         targets = Transition.calculateTargets(participants, changes);
-        info = Transition.calculateTransitionInfo(transitType, targets, changes);
+        info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -104,7 +105,7 @@
         // Check multi promote
         participants.remove(oldTask);
         targets = Transition.calculateTargets(participants, changes);
-        info = Transition.calculateTransitionInfo(transitType, targets, changes);
+        info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -138,23 +139,24 @@
         opening.mVisibleRequested = true;
         opening2.mVisibleRequested = true;
 
-        int transitType = TRANSIT_OLD_TASK_OPEN;
+        int transit = TRANSIT_OLD_TASK_OPEN;
+        int flags = 0;
 
         // Check full promotion from leaf
         participants.add(oldTask);
         participants.add(opening);
         participants.add(opening2);
         ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
-        TransitionInfo info = Transition.calculateTransitionInfo(transitType, targets, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
         assertEquals(2, info.getChanges().size());
-        assertEquals(transitType, info.getType());
+        assertEquals(transit, info.getType());
         assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
 
         // Check that unchanging but visible descendant of sibling prevents promotion
         participants.remove(opening2);
         targets = Transition.calculateTargets(participants, changes);
-        info = Transition.calculateTransitionInfo(transitType, targets, changes);
+        info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(newNestedTask.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -184,29 +186,30 @@
         showing.mVisibleRequested = true;
         showing2.mVisibleRequested = true;
 
-        int transitType = TRANSIT_OLD_TASK_OPEN;
+        int transit = TRANSIT_OLD_TASK_OPEN;
+        int flags = 0;
 
         // Check promotion to DisplayArea
         participants.add(showing);
         participants.add(showing2);
         ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
-        TransitionInfo info = Transition.calculateTransitionInfo(transitType, targets, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
         assertEquals(1, info.getChanges().size());
-        assertEquals(transitType, info.getType());
+        assertEquals(transit, info.getType());
         assertNotNull(info.getChange(tda.mRemoteToken.toWindowContainerToken()));
 
         ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
         // Check that organized tasks get reported even if not top
         showTask.mTaskOrganizer = mockOrg;
         targets = Transition.calculateTargets(participants, changes);
-        info = Transition.calculateTransitionInfo(transitType, targets, changes);
+        info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(tda.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(showTask.mRemoteToken.toWindowContainerToken()));
         // Even if DisplayArea explicitly participating
         participants.add(tda);
         targets = Transition.calculateTargets(participants, changes);
-        info = Transition.calculateTransitionInfo(transitType, targets, changes);
+        info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
         assertEquals(2, info.getChanges().size());
     }
 
@@ -231,7 +234,8 @@
 
         ArraySet<WindowContainer> targets = Transition.calculateTargets(
                 transition.mParticipants, transition.mChanges);
-        TransitionInfo info = Transition.calculateTransitionInfo(0, targets, transition.mChanges);
+        TransitionInfo info = Transition.calculateTransitionInfo(
+                0, 0, targets, transition.mChanges);
         assertEquals(2, info.getChanges().size());
         // There was an existence change on open, so it should be OPEN rather than SHOW
         assertEquals(TRANSIT_OPEN,
@@ -267,7 +271,8 @@
 
         ArraySet<WindowContainer> targets = Transition.calculateTargets(
                 transition.mParticipants, transition.mChanges);
-        TransitionInfo info = Transition.calculateTransitionInfo(0, targets, transition.mChanges);
+        TransitionInfo info = Transition.calculateTransitionInfo(
+                0, 0, targets, transition.mChanges);
         assertEquals(taskCount, info.getChanges().size());
         // verify order is top-to-bottem
         for (int i = 0; i < taskCount; ++i) {