Add non app windows to remote animation target.

Bug: 175686682
Test: atest RemoteAnimationControllerTest

Change-Id: I1a27af174536d3cebad5a7368d31f9f8290a0974
This commit is contained in:
Issei Suzuki
2021-02-05 14:36:53 +01:00
parent e7dfae7e7b
commit 336c4401e8
7 changed files with 290 additions and 30 deletions

View File

@@ -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",

View File

@@ -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,

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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());

View File

@@ -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);

View File

@@ -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.