diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 84da930aac542af7c72b126dca818c7b3ca071d5..5633de34843327ea8e4b937a15a02a8f93268a23 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 6a441f1830d1d99850b2dac27eab3d9b8bf22f22..4ccd57ddc9773baa44bd75ee9b6c64f74522eeb3 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_ACCESSIBILITY_OVERLAY 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 db33e750d803343b344970388f51a86b1ab188dc..b5a9acacec83f4d8a9cdf9bde3df2ccda3e88c34 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 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { /** * @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 0000000000000000000000000000000000000000..5d6d51377c3f3fe9c50173a96140f9fd612bdfd6 --- /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 392f27ead2bbb13d4e5c01241318c16ba8a64f7f..42cb96f65738cb0745cc18fec4cc91343ee42fb0 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 @@ class RemoteAnimationController implements DeathRecipient { 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 @@ class RemoteAnimationController implements DeathRecipient { }, 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 15e045c85c29f808c362acce0b922a14dd6de00e..2fdd63ed93d52c5630553be76222e5816b7fa515 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 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { 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 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { 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 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { 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 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { } } + @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 e4b865fd2941ecb2700f46e45bad7a94b4513813..86d8eee878fdbfffccc9db2ea96eb42e5c9e3440 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 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { 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.