Merge "Polish activity transition for letterbox" into tm-qpr-dev am: c3a33cde83

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18320843

Change-Id: I92dc418580d4503ee80ae9d94520d4b5d2c92009
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Pablo Gamito
2022-08-22 17:02:57 +00:00
committed by Automerger Merge Worker
9 changed files with 244 additions and 74 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 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) {
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="

View File

@@ -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,16 +458,20 @@ class SurfaceAnimationRunner {
.setHidden(true)
.setCallsite("DefaultTransitionHandler#startAnimation")
.setOpaque(true)
.setBufferSize(edgeBounds.width(), edgeBounds.height())
.setBufferSize(extensionRect.width(), extensionRect.height())
.build();
final Surface surface = new Surface(edgeExtensionLayer);
surface.attachAndQueueBufferWithColorSpace(edgeBuffer.getHardwareBuffer(),
edgeBuffer.getColorSpace());
surface.release();
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 float scaleX = getScaleXForExtensionSurface(edgeBounds, extensionRect);
final float scaleY = getScaleYForExtensionSurface(edgeBounds, extensionRect);
final Surface surface = new Surface(edgeExtensionLayer);
Canvas c = surface.lockHardwareCanvas();
c.drawRect(extensionRect, paint);
surface.unlockCanvasAndPost(c);
surface.release();
synchronized (mEdgeExtensionLock) {
if (!mEdgeExtensions.containsKey(leash)) {
@@ -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;

View File

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

View File

@@ -6053,7 +6053,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
boolean hasWallpaperForLetterboxBackground() {
return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox();
return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroundForLetterbox();
}
/**

View File

@@ -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);
}
@@ -204,6 +206,22 @@ public class LetterboxTest {
verify(mTransaction).setAlpha(mSurfaces.fullWindowSurface, mDarkScrimAlpha);
}
@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));