diff options
| author | 2022-08-22 17:01:37 +0000 | |
|---|---|---|
| committer | 2022-08-22 17:01:37 +0000 | |
| commit | c3a33cde83195ae4af0b27f545fda19751565044 (patch) | |
| tree | a61985b359433beb54622fbe90dd5d6a8f2c2720 | |
| parent | bc18e29662ae488b5c6990d33719d6f4b9d17868 (diff) | |
| parent | 6576af6bbee4126ab9ed3c05b5731ae6cabe5aee (diff) | |
Merge "Polish activity transition for letterbox" into tm-qpr-dev
9 files changed, 244 insertions, 74 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index bd88c41b5268..2e3096265b53 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -660,6 +660,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean mUseTransferredAnimation; + /** Whether we need to setup the animation to animate only within the letterbox. */ + private boolean mNeedsLetterboxedAnimation; + /** * @see #currentLaunchCanTurnScreenOn() */ @@ -1762,8 +1765,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mLetterboxUiController.layoutLetterbox(winHint); } - boolean hasWallpaperBackgroudForLetterbox() { - return mLetterboxUiController.hasWallpaperBackgroudForLetterbox(); + boolean hasWallpaperBackgroundForLetterbox() { + return mLetterboxUiController.hasWallpaperBackgroundForLetterbox(); + } + + void updateLetterboxSurface(WindowState winHint, Transaction t) { + mLetterboxUiController.updateLetterboxSurface(winHint, t); } void updateLetterboxSurface(WindowState winHint) { @@ -5334,6 +5341,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A commitVisibility(visible, performLayout, false /* fromTransition */); } + void setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation) { + mNeedsLetterboxedAnimation = needsLetterboxedAnimation; + } + + boolean isNeedsLetterboxedAnimation() { + return mNeedsLetterboxedAnimation; + } + + boolean isInLetterboxAnimation() { + return mNeedsLetterboxedAnimation && isAnimating(); + } + /** * Post process after applying an app transition animation. * @@ -7261,6 +7280,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A .setParent(getAnimationLeashParent()) .setName(getSurfaceControl() + " - animation-bounds") .setCallsite("ActivityRecord.createAnimationBoundsLayer"); + if (mNeedsLetterboxedAnimation) { + // Needs to be an effect layer to support rounded corners + builder.setEffectLayer(); + } final SurfaceControl boundsLayer = builder.build(); t.show(boundsLayer); return boundsLayer; @@ -7298,6 +7321,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAnimatingActivityRegistry.notifyStarting(this); } + if (mNeedsLetterboxedAnimation) { + updateLetterboxSurface(findMainWindow(), t); + mNeedsAnimationBoundsLayer = true; + } + // If the animation needs to be cropped then an animation bounds layer is created as a // child of the root pinned task or animation layer. The leash is then reparented to this // new layer. @@ -7320,6 +7348,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A t.setLayer(leash, 0); t.setLayer(mAnimationBoundsLayer, getLastLayer()); + if (mNeedsLetterboxedAnimation) { + final int cornerRadius = mLetterboxUiController + .getRoundedCornersRadius(findMainWindow()); + + final Rect letterboxInnerBounds = new Rect(); + getLetterboxInnerBounds(letterboxInnerBounds); + + t.setCornerRadius(mAnimationBoundsLayer, cornerRadius) + .setCrop(mAnimationBoundsLayer, letterboxInnerBounds); + } + // Reparent leash to animation bounds layer. t.reparent(leash, mAnimationBoundsLayer); } @@ -7433,6 +7472,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAnimationBoundsLayer = null; } + mNeedsAnimationBoundsLayer = false; + if (mNeedsLetterboxedAnimation) { + mNeedsLetterboxedAnimation = false; + updateLetterboxSurface(findMainWindow(), t); + } + if (mAnimatingActivityRegistry != null) { mAnimatingActivityRegistry.notifyFinished(this); } @@ -7445,7 +7490,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished"); mTransit = TRANSIT_OLD_UNSET; mTransitFlags = 0; - mNeedsAnimationBoundsLayer = false; setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER, "ActivityRecord"); diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index fb9d7e602210..5ac5f2e4bdaf 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -81,9 +81,11 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.graphics.Rect; import android.os.Trace; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.Pair; import android.util.Slog; import android.view.Display; import android.view.RemoteAnimationAdapter; @@ -1028,6 +1030,32 @@ public class AppTransitionController { return; } + if (AppTransition.isActivityTransitOld(transit)) { + final ArrayList<Pair<ActivityRecord, Rect>> closingLetterboxes = new ArrayList(); + for (int i = 0; i < closingApps.size(); ++i) { + ActivityRecord closingApp = closingApps.valueAt(i); + if (closingApp.areBoundsLetterboxed()) { + final Rect insets = closingApp.getLetterboxInsets(); + closingLetterboxes.add(new Pair(closingApp, insets)); + } + } + + for (int i = 0; i < openingApps.size(); ++i) { + ActivityRecord openingApp = openingApps.valueAt(i); + if (openingApp.areBoundsLetterboxed()) { + final Rect openingInsets = openingApp.getLetterboxInsets(); + for (Pair<ActivityRecord, Rect> closingLetterbox : closingLetterboxes) { + final Rect closingInsets = closingLetterbox.second; + if (openingInsets.equals(closingInsets)) { + ActivityRecord closingApp = closingLetterbox.first; + openingApp.setNeedsLetterboxedAnimation(true); + closingApp.setNeedsLetterboxedAnimation(true); + } + } + } + } + } + final ArraySet<WindowContainer> openingWcs = getAnimationTargets( openingApps, closingApps, true /* visible */); final ArraySet<WindowContainer> closingWcs = getAnimationTargets( diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index df3109ad33c7..27550d9e8186 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -56,6 +56,7 @@ public class Letterbox { private final Supplier<Boolean> mHasWallpaperBackgroundSupplier; private final Supplier<Integer> mBlurRadiusSupplier; private final Supplier<Float> mDarkScrimAlphaSupplier; + private final Supplier<SurfaceControl> mParentSurfaceSupplier; private final Rect mOuter = new Rect(); private final Rect mInner = new Rect(); @@ -87,7 +88,8 @@ public class Letterbox { Supplier<Integer> blurRadiusSupplier, Supplier<Float> darkScrimAlphaSupplier, IntConsumer doubleTapCallbackX, - IntConsumer doubleTapCallbackY) { + IntConsumer doubleTapCallbackY, + Supplier<SurfaceControl> parentSurface) { mSurfaceControlFactory = surfaceControlFactory; mTransactionFactory = transactionFactory; mAreCornersRounded = areCornersRounded; @@ -97,6 +99,7 @@ public class Letterbox { mDarkScrimAlphaSupplier = darkScrimAlphaSupplier; mDoubleTapCallbackX = doubleTapCallbackX; mDoubleTapCallbackY = doubleTapCallbackY; + mParentSurfaceSupplier = parentSurface; } /** @@ -121,7 +124,6 @@ public class Letterbox { mFullWindowSurface.layout(outer.left, outer.top, outer.right, outer.bottom, surfaceOrigin); } - /** * Gets the insets between the outer and inner rects. */ @@ -333,6 +335,7 @@ public class Letterbox { private SurfaceControl mSurface; private Color mColor; private boolean mHasWallpaperBackground; + private SurfaceControl mParentSurface; private final Rect mSurfaceFrameRelative = new Rect(); private final Rect mLayoutFrameGlobal = new Rect(); @@ -403,10 +406,12 @@ public class Letterbox { } mColor = mColorSupplier.get(); + mParentSurface = mParentSurfaceSupplier.get(); t.setColor(mSurface, getRgbColorArray()); t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top); t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(), mSurfaceFrameRelative.height()); + t.reparent(mSurface, mParentSurface); mHasWallpaperBackground = mHasWallpaperBackgroundSupplier.get(); updateAlphaAndBlur(t); @@ -452,12 +457,13 @@ public class Letterbox { public boolean needsApplySurfaceChanges() { return !mSurfaceFrameRelative.equals(mLayoutFrameRelative) - // If mSurfaceFrameRelative is empty then mHasWallpaperBackground and mColor - // may never be updated in applySurfaceChanges but this doesn't mean that - // update is needed. + // If mSurfaceFrameRelative is empty then mHasWallpaperBackground, mColor, + // and mParentSurface may never be updated in applySurfaceChanges but this + // doesn't mean that update is needed. || !mSurfaceFrameRelative.isEmpty() && (mHasWallpaperBackgroundSupplier.get() != mHasWallpaperBackground - || !mColorSupplier.get().equals(mColor)); + || !mColorSupplier.get().equals(mColor) + || mParentSurfaceSupplier.get() != mParentSurface); } } } diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 57c60f4ffc33..a469c6b39e7f 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -265,7 +265,7 @@ final class LetterboxConfiguration { } /** - * Overrides corners raidus for activities presented in the letterbox mode. If given value < 0, + * Overrides corners radius for activities presented in the letterbox mode. If given value < 0, * both it and a value of {@link * com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and * corners of the activity won't be rounded. @@ -275,7 +275,7 @@ final class LetterboxConfiguration { } /** - * Resets corners raidus for activities presented in the letterbox mode to {@link + * Resets corners radius for activities presented in the letterbox mode to {@link * com.android.internal.R.integer.config_letterboxActivityCornersRadius}. */ void resetLetterboxActivityCornersRadius() { @@ -291,7 +291,7 @@ final class LetterboxConfiguration { } /** - * Gets corners raidus for activities presented in the letterbox mode. + * Gets corners radius for activities presented in the letterbox mode. */ int getLetterboxActivityCornersRadius() { return mLetterboxActivityCornersRadius; @@ -318,7 +318,7 @@ final class LetterboxConfiguration { /** * Sets color of letterbox background which is used when {@link * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as - * fallback for other backfround types. + * fallback for other background types. */ void setLetterboxBackgroundColor(Color color) { mLetterboxBackgroundColorOverride = color; @@ -327,7 +327,7 @@ final class LetterboxConfiguration { /** * Sets color ID of letterbox background which is used when {@link * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as - * fallback for other backfround types. + * fallback for other background types. */ void setLetterboxBackgroundColorResourceId(int colorId) { mLetterboxBackgroundColorResourceIdOverride = colorId; diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index c8ed602b0f1d..317c93e63459 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -89,7 +89,7 @@ final class LetterboxUiController { // Taskbar expanded height. Used to determine whether to crop an app window to display rounded // corners above the taskbar. - private float mExpandedTaskBarHeight; + private final float mExpandedTaskBarHeight; private boolean mShowWallpaperForLetterboxBackground; @@ -120,7 +120,7 @@ final class LetterboxUiController { } } - boolean hasWallpaperBackgroudForLetterbox() { + boolean hasWallpaperBackgroundForLetterbox() { return mShowWallpaperForLetterboxBackground; } @@ -137,6 +137,11 @@ final class LetterboxUiController { void getLetterboxInnerBounds(Rect outBounds) { if (mLetterbox != null) { outBounds.set(mLetterbox.getInnerFrame()); + final WindowState w = mActivityRecord.findMainWindow(); + if (w == null) { + return; + } + adjustBoundsForTaskbar(w, outBounds); } else { outBounds.setEmpty(); } @@ -160,13 +165,17 @@ final class LetterboxUiController { } void updateLetterboxSurface(WindowState winHint) { + updateLetterboxSurface(winHint, mActivityRecord.getSyncTransaction()); + } + + void updateLetterboxSurface(WindowState winHint, Transaction t) { final WindowState w = mActivityRecord.findMainWindow(); if (w != winHint && winHint != null && w != null) { return; } layoutLetterbox(winHint); if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) { - mLetterbox.applySurfaceChanges(mActivityRecord.getSyncTransaction()); + mLetterbox.applySurfaceChanges(t); } } @@ -191,14 +200,22 @@ final class LetterboxUiController { mActivityRecord.mWmService.mTransactionFactory, this::shouldLetterboxHaveRoundedCorners, this::getLetterboxBackgroundColor, - this::hasWallpaperBackgroudForLetterbox, + this::hasWallpaperBackgroundForLetterbox, this::getLetterboxWallpaperBlurRadius, this::getLetterboxWallpaperDarkScrimAlpha, this::handleHorizontalDoubleTap, - this::handleVerticalDoubleTap); + this::handleVerticalDoubleTap, + this::getLetterboxParentSurface); mLetterbox.attachInput(w); } - mActivityRecord.getPosition(mTmpPoint); + + if (mActivityRecord.isInLetterboxAnimation()) { + // In this case we attach the letterbox to the task instead of the activity. + mActivityRecord.getTask().getPosition(mTmpPoint); + } else { + mActivityRecord.getPosition(mTmpPoint); + } + // Get the bounds of the "space-to-fill". The transformed bounds have the highest // priority because the activity is launched in a rotated environment. In multi-window // mode, the task-level represents this. In fullscreen-mode, the task container does @@ -215,6 +232,13 @@ final class LetterboxUiController { } } + SurfaceControl getLetterboxParentSurface() { + if (mActivityRecord.isInLetterboxAnimation()) { + return mActivityRecord.getTask().getSurfaceControl(); + } + return mActivityRecord.getSurfaceControl(); + } + private boolean shouldLetterboxHaveRoundedCorners() { // TODO(b/214030873): remove once background is drawn for transparent activities // Letterbox shouldn't have rounded corners if the activity is transparent @@ -436,7 +460,7 @@ final class LetterboxUiController { } break; case LETTERBOX_BACKGROUND_WALLPAPER: - if (hasWallpaperBackgroudForLetterbox()) { + if (hasWallpaperBackgroundForLetterbox()) { // Color is used for translucent scrim that dims wallpaper. return Color.valueOf(Color.BLACK); } @@ -459,15 +483,14 @@ final class LetterboxUiController { private void updateRoundedCorners(WindowState mainWindow) { final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface(); if (windowSurface != null && windowSurface.isValid()) { - Transaction transaction = mActivityRecord.getSyncTransaction(); - - final InsetsState insetsState = mainWindow.getInsetsState(); - final InsetsSource taskbarInsetsSource = - insetsState.peekSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR); - - if (!isLetterboxedNotForDisplayCutout(mainWindow) - || !mLetterboxConfiguration.isLetterboxActivityCornersRounded() - || taskbarInsetsSource == null) { + final Transaction transaction = mActivityRecord.getSyncTransaction(); + + if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) { + // We don't want corner radius on the window. + // In the case the ActivityRecord requires a letterboxed animation we never want + // rounded corners on the window because rounded corners are applied at the + // animation-bounds surface level and rounded corners on the window would interfere + // with that leading to unexpected rounded corner positioning during the animation. transaction .setWindowCrop(windowSurface, null) .setCornerRadius(windowSurface, 0); @@ -476,48 +499,89 @@ final class LetterboxUiController { Rect cropBounds = null; - // Rounded corners should be displayed above the taskbar. When taskbar is hidden, - // an insets frame is equal to a navigation bar which shouldn't affect position of - // rounded corners since apps are expected to handle navigation bar inset. - // This condition checks whether the taskbar is visible. - // Do not crop the taskbar inset if the window is in immersive mode - the user can - // swipe to show/hide the taskbar as an overlay. - if (taskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight - && taskbarInsetsSource.isVisible()) { + if (hasVisibleTaskbar(mainWindow)) { cropBounds = new Rect(mActivityRecord.getBounds()); // Activity bounds are in screen coordinates while (0,0) for activity's surface // control is at the top left corner of an app window so offsetting bounds // accordingly. cropBounds.offsetTo(0, 0); - // Rounded cornerners should be displayed above the taskbar. - cropBounds.bottom = - Math.min(cropBounds.bottom, taskbarInsetsSource.getFrame().top); - if (mActivityRecord.inSizeCompatMode() - && mActivityRecord.getSizeCompatScale() < 1.0f) { - cropBounds.scale(1.0f / mActivityRecord.getSizeCompatScale()); - } + // Rounded corners should be displayed above the taskbar. + adjustBoundsForTaskbarUnchecked(mainWindow, cropBounds); } transaction .setWindowCrop(windowSurface, cropBounds) - .setCornerRadius(windowSurface, getRoundedCorners(insetsState)); + .setCornerRadius(windowSurface, getRoundedCornersRadius(mainWindow)); } } - // Returns rounded corners radius based on override in + private boolean requiresRoundedCorners(WindowState mainWindow) { + final InsetsSource taskbarInsetsSource = getTaskbarInsetsSource(mainWindow); + + return isLetterboxedNotForDisplayCutout(mainWindow) + && mLetterboxConfiguration.isLetterboxActivityCornersRounded() + && taskbarInsetsSource != null; + } + + // Returns rounded corners radius the letterboxed activity should have based on override in // R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii. // Device corners can be different on the right and left sides but we use the same radius // for all corners for consistency and pick a minimal bottom one for consistency with a // taskbar rounded corners. - private int getRoundedCorners(InsetsState insetsState) { + int getRoundedCornersRadius(WindowState mainWindow) { + if (!requiresRoundedCorners(mainWindow)) { + return 0; + } + if (mLetterboxConfiguration.getLetterboxActivityCornersRadius() >= 0) { return mLetterboxConfiguration.getLetterboxActivityCornersRadius(); } + + final InsetsState insetsState = mainWindow.getInsetsState(); return Math.min( getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT), getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT)); } + /** + * Returns whether the taskbar is visible. Returns false if the window is in immersive mode, + * since the user can swipe to show/hide the taskbar as an overlay. + */ + private boolean hasVisibleTaskbar(WindowState mainWindow) { + final InsetsSource taskbarInsetsSource = getTaskbarInsetsSource(mainWindow); + + return taskbarInsetsSource != null + && taskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight + && taskbarInsetsSource.isVisible(); + } + + private InsetsSource getTaskbarInsetsSource(WindowState mainWindow) { + final InsetsState insetsState = mainWindow.getInsetsState(); + return insetsState.peekSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR); + } + + private void adjustBoundsForTaskbar(WindowState mainWindow, Rect bounds) { + // Rounded corners should be displayed above the taskbar. When taskbar is hidden, + // an insets frame is equal to a navigation bar which shouldn't affect position of + // rounded corners since apps are expected to handle navigation bar inset. + // This condition checks whether the taskbar is visible. + // Do not crop the taskbar inset if the window is in immersive mode - the user can + // swipe to show/hide the taskbar as an overlay. + if (hasVisibleTaskbar(mainWindow)) { + adjustBoundsForTaskbarUnchecked(mainWindow, bounds); + } + } + + private void adjustBoundsForTaskbarUnchecked(WindowState mainWindow, Rect bounds) { + // Rounded corners should be displayed above the taskbar. + bounds.bottom = + Math.min(bounds.bottom, getTaskbarInsetsSource(mainWindow).getFrame().top); + if (mActivityRecord.inSizeCompatMode() + && mActivityRecord.getSizeCompatScale() < 1.0f) { + bounds.scale(1.0f / mActivityRecord.getSizeCompatScale()); + } + } + private int getInsetsStateCornerRadius( InsetsState insetsState, @RoundedCorner.Position int position) { RoundedCorner corner = insetsState.getRoundedCorners().getRoundedCorner(position); @@ -592,7 +656,7 @@ final class LetterboxUiController { + letterboxBackgroundTypeToString( mLetterboxConfiguration.getLetterboxBackgroundType())); pw.println(prefix + " letterboxCornerRadius=" - + getRoundedCorners(mainWin.getInsetsState())); + + getRoundedCornersRadius(mainWin)); if (mLetterboxConfiguration.getLetterboxBackgroundType() == LETTERBOX_BACKGROUND_WALLPAPER) { pw.println(prefix + " isLetterboxWallpaperBlurSupported=" diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java index c7f8a1e2068a..f3670e49f01e 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java @@ -27,7 +27,10 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.Nullable; +import android.graphics.BitmapShader; +import android.graphics.Canvas; import android.graphics.Insets; +import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.hardware.power.Boost; @@ -374,43 +377,45 @@ class SurfaceAnimationRunner { final int targetSurfaceWidth = bounds.width(); if (maxExtensionInsets.left < 0) { - final Rect edgeBounds = new Rect(0, 0, 1, targetSurfaceHeight); + final Rect edgeBounds = new Rect(bounds.left, bounds.top, bounds.left + 1, + bounds.bottom); final Rect extensionRect = new Rect(0, 0, -maxExtensionInsets.left, targetSurfaceHeight); - final int xPos = maxExtensionInsets.left; - final int yPos = 0; + final int xPos = bounds.left + maxExtensionInsets.left; + final int yPos = bounds.top; createExtensionSurface(leash, edgeBounds, extensionRect, xPos, yPos, "Left Edge Extension", transaction); } if (maxExtensionInsets.top < 0) { - final Rect edgeBounds = new Rect(0, 0, targetSurfaceWidth, 1); + final Rect edgeBounds = new Rect(bounds.left, bounds.top, targetSurfaceWidth, + bounds.top + 1); final Rect extensionRect = new Rect(0, 0, targetSurfaceWidth, -maxExtensionInsets.top); - final int xPos = 0; - final int yPos = maxExtensionInsets.top; + final int xPos = bounds.left; + final int yPos = bounds.top + maxExtensionInsets.top; createExtensionSurface(leash, edgeBounds, extensionRect, xPos, yPos, "Top Edge Extension", transaction); } if (maxExtensionInsets.right < 0) { - final Rect edgeBounds = new Rect(targetSurfaceWidth - 1, 0, - targetSurfaceWidth, targetSurfaceHeight); + final Rect edgeBounds = new Rect(bounds.right - 1, bounds.top, bounds.right, + bounds.bottom); final Rect extensionRect = new Rect(0, 0, -maxExtensionInsets.right, targetSurfaceHeight); - final int xPos = targetSurfaceWidth; - final int yPos = 0; + final int xPos = bounds.right; + final int yPos = bounds.top; createExtensionSurface(leash, edgeBounds, extensionRect, xPos, yPos, "Right Edge Extension", transaction); } if (maxExtensionInsets.bottom < 0) { - final Rect edgeBounds = new Rect(0, targetSurfaceHeight - 1, - targetSurfaceWidth, targetSurfaceHeight); + final Rect edgeBounds = new Rect(bounds.left, bounds.bottom - 1, + bounds.right, bounds.bottom); final Rect extensionRect = new Rect(0, 0, targetSurfaceWidth, -maxExtensionInsets.bottom); - final int xPos = maxExtensionInsets.left; - final int yPos = targetSurfaceHeight; + final int xPos = bounds.left; + final int yPos = bounds.bottom; createExtensionSurface(leash, edgeBounds, extensionRect, xPos, yPos, "Bottom Edge Extension", transaction); } @@ -453,17 +458,21 @@ class SurfaceAnimationRunner { .setHidden(true) .setCallsite("DefaultTransitionHandler#startAnimation") .setOpaque(true) - .setBufferSize(edgeBounds.width(), edgeBounds.height()) + .setBufferSize(extensionRect.width(), extensionRect.height()) .build(); + BitmapShader shader = new BitmapShader(edgeBuffer.asBitmap(), + android.graphics.Shader.TileMode.CLAMP, + android.graphics.Shader.TileMode.CLAMP); + final Paint paint = new Paint(); + paint.setShader(shader); + final Surface surface = new Surface(edgeExtensionLayer); - surface.attachAndQueueBufferWithColorSpace(edgeBuffer.getHardwareBuffer(), - edgeBuffer.getColorSpace()); + Canvas c = surface.lockHardwareCanvas(); + c.drawRect(extensionRect, paint); + surface.unlockCanvasAndPost(c); surface.release(); - final float scaleX = getScaleXForExtensionSurface(edgeBounds, extensionRect); - final float scaleY = getScaleYForExtensionSurface(edgeBounds, extensionRect); - synchronized (mEdgeExtensionLock) { if (!mEdgeExtensions.containsKey(leash)) { // The animation leash has already been removed, so we don't want to attach the @@ -472,7 +481,6 @@ class SurfaceAnimationRunner { return; } - startTransaction.setScale(edgeExtensionLayer, scaleX, scaleY); startTransaction.reparent(edgeExtensionLayer, leash); startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE); startTransaction.setPosition(edgeExtensionLayer, xPos, yPos); @@ -508,8 +516,6 @@ class SurfaceAnimationRunner { throw new RuntimeException("Unexpected edgeBounds and extensionRect heights"); } - - private static final class RunningAnimation { final AnimationSpec mAnimSpec; final SurfaceControl mLeash; diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 25193d0b5ba3..797904890f74 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -3015,6 +3015,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< final float windowCornerRadius = !inMultiWindowMode() ? getDisplayContent().getWindowCornerRadius() : 0; + if (asActivityRecord() != null + && asActivityRecord().isNeedsLetterboxedAnimation()) { + asActivityRecord().getLetterboxInnerBounds(mTmpRect); + } AnimationAdapter adapter = new LocalAnimationAdapter( new WindowAnimationSpec(a, mTmpPoint, mTmpRect, getDisplayContent().mAppTransition.canSkipFirstFrame(), diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 45eb80613646..2432afbc03ef 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -6053,7 +6053,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } boolean hasWallpaperForLetterboxBackground() { - return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox(); + return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroundForLetterbox(); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java index e502f2fbd173..d400a4c9daca 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -56,6 +56,7 @@ public class LetterboxTest { private boolean mHasWallpaperBackground = false; private int mBlurRadius = 0; private float mDarkScrimAlpha = 0.5f; + private SurfaceControl mParentSurface = mock(SurfaceControl.class); @Before public void setUp() throws Exception { @@ -63,7 +64,8 @@ public class LetterboxTest { mLetterbox = new Letterbox(mSurfaces, StubTransaction::new, () -> mAreCornersRounded, () -> Color.valueOf(mColor), () -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha, - /* doubleTapCallbackX= */ x -> {}, /* doubleTapCallbackY= */ y -> {}); + /* doubleTapCallbackX= */ x -> {}, /* doubleTapCallbackY= */ y -> {}, + () -> mParentSurface); mTransaction = spy(StubTransaction.class); } @@ -205,6 +207,22 @@ public class LetterboxTest { } @Test + public void testNeedsApplySurfaceChanges_setParentSurface() { + mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); + mLetterbox.applySurfaceChanges(mTransaction); + + verify(mTransaction).reparent(mSurfaces.top, mParentSurface); + assertFalse(mLetterbox.needsApplySurfaceChanges()); + + mParentSurface = mock(SurfaceControl.class); + + assertTrue(mLetterbox.needsApplySurfaceChanges()); + + mLetterbox.applySurfaceChanges(mTransaction); + verify(mTransaction).reparent(mSurfaces.top, mParentSurface); + } + + @Test public void testApplySurfaceChanges_cornersNotRounded_surfaceFullWindowSurfaceNotCreated() { mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); mLetterbox.applySurfaceChanges(mTransaction); |