Add non app windows to remote animation target.

Bug: 175686682
Test: atest RemoteAnimationControllerTest

Change-Id: I1a27af174536d3cebad5a7368d31f9f8290a0974
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index ded4a27..fc15cff 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -259,6 +259,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1834214907": {
+      "message": "createNonAppWindowAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
     "-1824578273": {
       "message": "Reporting new frame to %s: %s",
       "level": "VERBOSE",
@@ -811,6 +817,18 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
+    "-1153814764": {
+      "message": "onAnimationCancelled",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
+    },
+    "-1144293044": {
+      "message": "SURFACE SET FREEZE LAYER: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
     "-1142279614": {
       "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
       "level": "VERBOSE",
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6a441f1..4ccd57d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -56,13 +56,11 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
 import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -2292,25 +2290,6 @@
         return attrs.type == TYPE_NOTIFICATION_SHADE;
     }
 
-    @Override
-    public boolean canBeHiddenByKeyguardLw(WindowState win) {
-
-        // Keyguard visibility of window from activities are determined over activity visibility.
-        if (win.getAppToken() != null) {
-            return false;
-        }
-        switch (win.getAttrs().type) {
-            case TYPE_NOTIFICATION_SHADE:
-            case TYPE_STATUS_BAR:
-            case TYPE_NAVIGATION_BAR:
-            case TYPE_WALLPAPER:
-                return false;
-            default:
-                // Hide only windows below the keyguard host window.
-                return getWindowLayerLw(win) < getWindowLayerFromTypeLw(TYPE_NOTIFICATION_SHADE);
-        }
-    }
-
     /** {@inheritDoc} */
     @Override
     public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index db33e75..b5a9aca 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -672,7 +672,22 @@
     /**
      * @return whether {@param win} can be hidden by Keyguard
      */
-    public boolean canBeHiddenByKeyguardLw(WindowState win);
+    default boolean canBeHiddenByKeyguardLw(WindowState win) {
+        // Keyguard visibility of window from activities are determined over activity visibility.
+        if (win.getAppToken() != null) {
+            return false;
+        }
+        switch (win.getAttrs().type) {
+            case TYPE_NOTIFICATION_SHADE:
+            case TYPE_STATUS_BAR:
+            case TYPE_NAVIGATION_BAR:
+            case TYPE_WALLPAPER:
+                return false;
+            default:
+                // Hide only windows below the keyguard host window.
+                return getWindowLayerLw(win) < getWindowLayerFromTypeLw(TYPE_NOTIFICATION_SHADE);
+        }
+    }
 
     /**
      * Called when the system would like to show a UI to indicate that an
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
new file mode 100644
index 0000000..5d6d513
--- /dev/null
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
+import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
+
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.util.proto.ProtoOutputStream;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.server.policy.WindowManagerPolicy;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+class NonAppWindowAnimationAdapter implements AnimationAdapter {
+
+    private final WindowState mWindow;
+    private RemoteAnimationTarget mTarget;
+    private SurfaceControl mCapturedLeash;
+
+    private long mDurationHint;
+    private long mStatusBarTransitionDelay;
+
+    @Override
+    public boolean getShowWallpaper() {
+        return false;
+    }
+
+    NonAppWindowAnimationAdapter(WindowState w,
+            long durationHint, long statusBarTransitionDelay) {
+        mWindow = w;
+        mDurationHint = durationHint;
+        mStatusBarTransitionDelay = statusBarTransitionDelay;
+    }
+
+    /**
+     * Creates and starts remote animations for all the visible non app windows.
+     *
+     * @return RemoteAnimationTarget[] targets for all the visible non app windows
+     */
+    public static RemoteAnimationTarget[] startNonAppWindowAnimationsForKeyguardExit(
+            WindowManagerService service, long durationHint, long statusBarTransitionDelay) {
+        final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
+
+        final WindowManagerPolicy policy = service.mPolicy;
+        service.mRoot.forAllWindows(nonAppWindow -> {
+            if (nonAppWindow.mActivityRecord == null && policy.canBeHiddenByKeyguardLw(nonAppWindow)
+                    && nonAppWindow.wouldBeVisibleIfPolicyIgnored() && !nonAppWindow.isVisible()) {
+                final NonAppWindowAnimationAdapter nonAppAdapter = new NonAppWindowAnimationAdapter(
+                        nonAppWindow, durationHint, statusBarTransitionDelay);
+                nonAppWindow.startAnimation(nonAppWindow.getPendingTransaction(),
+                        nonAppAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
+                targets.add(nonAppAdapter.createRemoteAnimationTarget());
+            }
+        }, true /* traverseTopToBottom */);
+        return targets.toArray(new RemoteAnimationTarget[targets.size()]);
+    }
+
+    /**
+     * Create a remote animation target for this animation adapter.
+     */
+    RemoteAnimationTarget createRemoteAnimationTarget() {
+        mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false,
+                new Rect(), null, mWindow.getPrefixOrderIndex(), mWindow.getLastSurfacePosition(),
+                mWindow.getBounds(), null, mWindow.getWindowConfiguration(), true, null, null,
+                null);
+        return mTarget;
+    }
+
+    @Override
+    public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
+            int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
+        mCapturedLeash = animationLeash;
+    }
+
+    @Override
+    public long getDurationHint() {
+        return mDurationHint;
+    }
+
+    @Override
+    public long getStatusBarTransitionsStartTime() {
+        return SystemClock.uptimeMillis() + mStatusBarTransitionDelay;
+    }
+
+    /**
+     * @return the leash for this animation (only valid after the non app window surface animation
+     * has started).
+     */
+    SurfaceControl getLeash() {
+        return mCapturedLeash;
+    }
+
+    @Override
+    public void onAnimationCancelled(SurfaceControl animationLeash) {
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationCancelled");
+    }
+
+    @Override
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix);
+        pw.print("token=");
+        pw.println(mWindow.mToken);
+        if (mTarget != null) {
+            pw.print(prefix);
+            pw.println("Target:");
+            mTarget.dump(pw, prefix + "  ");
+        } else {
+            pw.print(prefix);
+            pw.println("Target: null");
+        }
+    }
+
+    @Override
+    public void dumpDebug(ProtoOutputStream proto) {
+        final long token = proto.start(REMOTE);
+        if (mTarget != null) {
+            mTarget.dumpDebug(proto, TARGET);
+        }
+        proto.end(token);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 392f27e..42cb96f 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
@@ -126,7 +129,7 @@
         final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
 
         // TODO(bc-unlock): Create the remote non app animation targets (if any)
-        final RemoteAnimationTarget[] nonAppTargets = new RemoteAnimationTarget[0];
+        final RemoteAnimationTarget[] nonAppTargets = createNonAppWindowAnimations(transit);
 
         mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
             try {
@@ -215,6 +218,17 @@
                 }, mPendingWallpaperAnimations);
     }
 
+    private RemoteAnimationTarget[] createNonAppWindowAnimations(
+            @WindowManager.TransitionOldType int transit) {
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createNonAppWindowAnimations()");
+        return (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
+                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER)
+                ? NonAppWindowAnimationAdapter.startNonAppWindowAnimationsForKeyguardExit(mService,
+                    mRemoteAnimationAdapter.getDuration(),
+                    mRemoteAnimationAdapter.getStatusBarTransitionDelay())
+                : new RemoteAnimationTarget[0];
+    }
+
     private void onAnimationFinished() {
         ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationFinished(): mPendingAnimations=%d",
                 mPendingAnimations.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 15e045c..2fdd63e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -16,8 +16,11 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
 
@@ -94,10 +97,19 @@
         mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
     }
 
+    private WindowState createAppOverlayWindow() {
+        final WindowState win = createWindow(null /* parent */, TYPE_APPLICATION_OVERLAY,
+                "testOverlayWindow");
+        win.mActivityRecord = null;
+        win.mHasSurface = true;
+        return win;
+    }
+
     @Test
     public void testRun() throws Exception {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
         mDisplayContent.mOpeningApps.add(win.mActivityRecord);
+        final WindowState overlayWin = createAppOverlayWindow();
         try {
             final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
                     new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
@@ -109,12 +121,12 @@
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
-            final ArgumentCaptor<RemoteAnimationTarget[]> nonApsCaptor =
+            final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
                     ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
             verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_ACTIVITY_OPEN),
-                    appsCaptor.capture(), wallpapersCaptor.capture(), nonApsCaptor.capture(),
+                    appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
                     finishedCaptor.capture());
             assertEquals(1, appsCaptor.getValue().length);
             final RemoteAnimationTarget app = appsCaptor.getValue()[0];
@@ -130,6 +142,7 @@
             finishedCaptor.getValue().onAnimationFinished();
             verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
                     eq(adapter));
+            assertEquals(0, nonAppsCaptor.getValue().length);
         } finally {
             mDisplayContent.mOpeningApps.clear();
         }
@@ -424,6 +437,89 @@
         }
     }
 
+    @Test
+    public void testNonAppIncluded_keygaurdGoingAway() throws Exception {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mDisplayContent.mOpeningApps.add(win.mActivityRecord);
+        // Add overlay window hidden by the keyguard.
+        final WindowState overlayWin = createAppOverlayWindow();
+        overlayWin.hide(false /* doAnimation */, false /* requestAnim */);
+        try {
+            final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
+                    win.mActivityRecord, new Point(50, 100), null,
+                    new Rect(50, 100, 150, 150), null).mAdapter;
+            adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+                    mFinishedCallback);
+            mController.goodToGo(TRANSIT_OLD_KEYGUARD_GOING_AWAY);
+            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                    ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+            verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_KEYGUARD_GOING_AWAY),
+                    appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
+                    finishedCaptor.capture());
+            assertEquals(1, appsCaptor.getValue().length);
+            final RemoteAnimationTarget app = appsCaptor.getValue()[0];
+            assertEquals(new Point(50, 100), app.position);
+            assertEquals(new Rect(50, 100, 150, 150), app.sourceContainerBounds);
+            assertEquals(win.mActivityRecord.getPrefixOrderIndex(), app.prefixOrderIndex);
+            assertEquals(win.mActivityRecord.getTask().mTaskId, app.taskId);
+            assertEquals(mMockLeash, app.leash);
+            assertEquals(false, app.isTranslucent);
+            verify(mMockTransaction).setPosition(mMockLeash, app.position.x, app.position.y);
+            verify(mMockTransaction).setWindowCrop(mMockLeash, 100, 50);
+
+            finishedCaptor.getValue().onAnimationFinished();
+            verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
+                    eq(adapter));
+            assertEquals(1, nonAppsCaptor.getValue().length);
+        } finally {
+            mDisplayContent.mOpeningApps.clear();
+        }
+    }
+
+    @Test
+    public void testNonAppIncluded_keygaurdGoingAwayToWallpaper() throws Exception {
+        final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
+                true, mDisplayContent, true /* ownerCanManageAppTokens */);
+        spyOn(mDisplayContent.mWallpaperController);
+        doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mDisplayContent.mOpeningApps.add(win.mActivityRecord);
+        // Add overlay window hidden by the keyguard.
+        final WindowState overlayWin = createAppOverlayWindow();
+        overlayWin.hide(false /* doAnimation */, false /* requestAnim */);
+        try {
+            final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
+                    win.mActivityRecord, new Point(50, 100), null,
+                    new Rect(50, 100, 150, 150), null).mAdapter;
+            adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+                    mFinishedCallback);
+            mController.goodToGo(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
+            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                    ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+            verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER),
+                    appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
+                    finishedCaptor.capture());
+            assertEquals(1, wallpapersCaptor.getValue().length);
+            assertEquals(1, nonAppsCaptor.getValue().length);
+        } finally {
+            mDisplayContent.mOpeningApps.clear();
+        }
+    }
+
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
         verify(binder, atLeast(0)).asBinder();
         verifyNoMoreInteractions(binder);
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 e4b865f..86d8eee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -91,11 +91,6 @@
         return attrs.type == TYPE_NOTIFICATION_SHADE;
     }
 
-    @Override
-    public boolean canBeHiddenByKeyguardLw(WindowState win) {
-        return false;
-    }
-
     /**
      * Sets a runnable to run when adding a splash screen which gets executed after the window has
      * been added but before returning the surface.