Loading core/java/android/window/BackNavigationInfo.java +27 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.graphics.Color; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -111,6 +112,8 @@ public final class BackNavigationInfo implements Parcelable { @Nullable private final CustomAnimationInfo mCustomAnimationInfo; private final int mLetterboxColor; /** * Create a new {@link BackNavigationInfo} instance. * Loading @@ -124,13 +127,15 @@ public final class BackNavigationInfo implements Parcelable { @Nullable IOnBackInvokedCallback onBackInvokedCallback, boolean isPrepareRemoteAnimation, boolean isAnimationCallback, @Nullable CustomAnimationInfo customAnimationInfo) { @Nullable CustomAnimationInfo customAnimationInfo, int letterboxColor) { mType = type; mOnBackNavigationDone = onBackNavigationDone; mOnBackInvokedCallback = onBackInvokedCallback; mPrepareRemoteAnimation = isPrepareRemoteAnimation; mAnimationCallback = isAnimationCallback; mCustomAnimationInfo = customAnimationInfo; mLetterboxColor = letterboxColor; } private BackNavigationInfo(@NonNull Parcel in) { Loading @@ -140,6 +145,7 @@ public final class BackNavigationInfo implements Parcelable { mPrepareRemoteAnimation = in.readBoolean(); mAnimationCallback = in.readBoolean(); mCustomAnimationInfo = in.readTypedObject(CustomAnimationInfo.CREATOR); mLetterboxColor = in.readInt(); } /** @hide */ Loading @@ -151,6 +157,7 @@ public final class BackNavigationInfo implements Parcelable { dest.writeBoolean(mPrepareRemoteAnimation); dest.writeBoolean(mAnimationCallback); dest.writeTypedObject(mCustomAnimationInfo, flags); dest.writeInt(mLetterboxColor); } /** Loading Loading @@ -192,6 +199,13 @@ public final class BackNavigationInfo implements Parcelable { return mAnimationCallback; } /** * @return Letterbox color * @hide */ public int getLetterboxColor() { return mLetterboxColor; } /** * Callback to be called when the back preview is finished in order to notify the server that * it can clean up the resources created for the animation. Loading Loading @@ -387,6 +401,8 @@ public final class BackNavigationInfo implements Parcelable { private CustomAnimationInfo mCustomAnimationInfo; private boolean mAnimationCallback = false; private int mLetterboxColor = Color.TRANSPARENT; /** * @see BackNavigationInfo#getType() */ Loading Loading @@ -453,6 +469,14 @@ public final class BackNavigationInfo implements Parcelable { return this; } /** * @param color Non-transparent if there contain letterbox color. */ public Builder setLetterboxColor(int color) { mLetterboxColor = color; return this; } /** * Builds and returns an instance of {@link BackNavigationInfo} */ Loading @@ -461,7 +485,8 @@ public final class BackNavigationInfo implements Parcelable { mOnBackInvokedCallback, mPrepareRemoteAnimation, mAnimationCallback, mCustomAnimationInfo); mCustomAnimationInfo, mLetterboxColor); } } } libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt +99 −10 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.content.Context import android.content.res.Configuration import android.graphics.Color import android.graphics.Matrix import android.graphics.PointF import android.graphics.Rect Loading @@ -35,6 +36,7 @@ import android.view.animation.DecelerateInterpolator import android.view.animation.Interpolator import android.window.BackEvent import android.window.BackMotionEvent import android.window.BackNavigationInfo import android.window.BackProgressAnimator import android.window.IOnBackInvokedCallback import com.android.internal.jank.Cuj Loading Loading @@ -67,6 +69,7 @@ class CrossActivityBackAnimation @Inject constructor( private val currentEnteringRect = RectF() private val backAnimRect = Rect() private val cropRect = Rect() private var cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) Loading Loading @@ -95,6 +98,10 @@ class CrossActivityBackAnimation @Inject constructor( private var maxScrimAlpha: Float = 0f private var isLetterboxed = false private var enteringHasSameLetterbox = false private var leftLetterboxLayer: SurfaceControl? = null private var rightLetterboxLayer: SurfaceControl? = null private var letterboxColor: Int = 0 override fun onConfigurationChanged(newConfiguration: Configuration) { cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) Loading @@ -115,8 +122,12 @@ class CrossActivityBackAnimation @Inject constructor( transaction.setAnimationTransaction() isLetterboxed = closingTarget!!.taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed if (isLetterboxed) { // Include letterbox in back animation enteringHasSameLetterbox = isLetterboxed && closingTarget!!.localBounds.equals(enteringTarget!!.localBounds) if (isLetterboxed && !enteringHasSameLetterbox) { // Play animation with letterboxes, if closing and entering target have mismatching // letterboxes backAnimRect.set(closingTarget!!.windowConfiguration.bounds) } else { // otherwise play animation on localBounds only Loading Loading @@ -144,12 +155,25 @@ class CrossActivityBackAnimation @Inject constructor( targetEnteringRect.set(startEnteringRect) targetEnteringRect.scaleCentered(MAX_SCALE) // Draw background with task background color. // Draw background with task background color (or letterbox color). val backgroundColor = if (isLetterboxed) { letterboxColor } else { enteringTarget!!.taskInfo.taskDescription!!.backgroundColor } background.ensureBackground( closingTarget!!.windowConfiguration.bounds, enteringTarget!!.taskInfo.taskDescription!!.backgroundColor, transaction closingTarget!!.windowConfiguration.bounds, backgroundColor, transaction ) ensureScrimLayer() if (isLetterboxed && enteringHasSameLetterbox) { // crop left and right letterboxes cropRect.set(closingTarget!!.localBounds.left, 0, closingTarget!!.localBounds.right, closingTarget!!.windowConfiguration.bounds.height()) // and add fake letterbox square surfaces instead ensureLetterboxes() } else { cropRect.set(backAnimRect) } applyTransaction() } Loading Loading @@ -249,18 +273,25 @@ class CrossActivityBackAnimation @Inject constructor( } finishCallback = null removeScrimLayer() removeLetterbox() isLetterboxed = false enteringHasSameLetterbox = false } private fun applyTransform(leash: SurfaceControl?, rect: RectF, alpha: Float) { if (leash == null || !leash.isValid) return val scale = rect.width() / backAnimRect.width() transformMatrix.reset() transformMatrix.setScale(scale, scale) val scalePivotX = if (isLetterboxed && enteringHasSameLetterbox) { closingTarget!!.localBounds.left.toFloat() } else { 0f } transformMatrix.setScale(scale, scale, scalePivotX, 0f) transformMatrix.postTranslate(rect.left, rect.top) transaction.setAlpha(leash, alpha) .setMatrix(leash, transformMatrix, tmpFloat9) .setCrop(leash, backAnimRect) .setCrop(leash, cropRect) .setCornerRadius(leash, cornerRadius) } Loading Loading @@ -297,15 +328,73 @@ class CrossActivityBackAnimation @Inject constructor( } private fun removeScrimLayer() { scrimLayer?.let { if (removeLayer(scrimLayer)) applyTransaction() scrimLayer = null } /** * Adds two "fake" letterbox square surfaces to the left and right of the localBounds of the * closing target */ private fun ensureLetterboxes() { closingTarget?.let { t -> if (t.localBounds.left != 0 && leftLetterboxLayer == null) { val bounds = Rect(0, t.windowConfiguration.bounds.top, t.localBounds.left, t.windowConfiguration.bounds.bottom) leftLetterboxLayer = ensureLetterbox(bounds) } if (t.localBounds.right != t.windowConfiguration.bounds.right && rightLetterboxLayer == null) { val bounds = Rect(t.localBounds.right, t.windowConfiguration.bounds.top, t.windowConfiguration.bounds.right, t.windowConfiguration.bounds.bottom) rightLetterboxLayer = ensureLetterbox(bounds) } } } private fun ensureLetterbox(bounds: Rect): SurfaceControl { val letterboxBuilder = SurfaceControl.Builder() .setName("Cross-Activity back animation letterbox") .setCallsite("CrossActivityBackAnimation") .setColorLayer() .setOpaque(true) .setHidden(false) rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, letterboxBuilder) val layer = letterboxBuilder.build() val colorComponents = floatArrayOf(Color.red(letterboxColor) / 255f, Color.green(letterboxColor) / 255f, Color.blue(letterboxColor) / 255f) transaction .setColor(layer, colorComponents) .setCrop(layer, bounds) .setRelativeLayer(layer, closingTarget!!.leash, 1) .show(layer) return layer } private fun removeLetterbox() { if (removeLayer(leftLetterboxLayer) || removeLayer(rightLetterboxLayer)) applyTransaction() leftLetterboxLayer = null rightLetterboxLayer = null } private fun removeLayer(layer: SurfaceControl?): Boolean { layer?.let { if (it.isValid) { transaction.remove(it) applyTransaction() return true } } scrimLayer = null return false } override fun prepareNextAnimation( animationInfo: BackNavigationInfo.CustomAnimationInfo?, letterboxColor: Int ): Boolean { this.letterboxColor = letterboxColor return false } private inner class Callback : IOnBackInvokedCallback.Default() { override fun onBackStarted(backMotionEvent: BackMotionEvent) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java +2 −1 Original line number Diff line number Diff line Loading @@ -271,7 +271,8 @@ public class CustomizeActivityAnimation extends ShellBackAnimation { /** Load customize animation before animation start. */ @Override public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo) { public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo, int letterboxColor) { if (animationInfo == null) { return false; } Loading libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java +3 −2 Original line number Diff line number Diff line Loading @@ -42,11 +42,12 @@ public abstract class ShellBackAnimation { public abstract BackAnimationRunner getRunner(); /** * Prepare the next animation with customized animation. * Prepare the next animation. * * @return true if this type of back animation should override the default. */ public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo) { public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo, int letterboxColor) { return false; } Loading libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java +4 −1 Original line number Diff line number Diff line Loading @@ -154,11 +154,14 @@ public class ShellBackAnimationRegistry { if (type == BackNavigationInfo.TYPE_CROSS_ACTIVITY && mAnimationDefinition.contains(type)) { if (mCustomizeActivityAnimation != null && mCustomizeActivityAnimation.prepareNextAnimation( backNavigationInfo.getCustomAnimationInfo())) { backNavigationInfo.getCustomAnimationInfo(), 0)) { mAnimationDefinition.get(type).resetWaitingAnimation(); mAnimationDefinition.set( BackNavigationInfo.TYPE_CROSS_ACTIVITY, mCustomizeActivityAnimation.getRunner()); } else if (mDefaultCrossActivityAnimation != null) { mDefaultCrossActivityAnimation.prepareNextAnimation(null, backNavigationInfo.getLetterboxColor()); } } BackAnimationRunner runner = mAnimationDefinition.get(type); Loading Loading
core/java/android/window/BackNavigationInfo.java +27 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.graphics.Color; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -111,6 +112,8 @@ public final class BackNavigationInfo implements Parcelable { @Nullable private final CustomAnimationInfo mCustomAnimationInfo; private final int mLetterboxColor; /** * Create a new {@link BackNavigationInfo} instance. * Loading @@ -124,13 +127,15 @@ public final class BackNavigationInfo implements Parcelable { @Nullable IOnBackInvokedCallback onBackInvokedCallback, boolean isPrepareRemoteAnimation, boolean isAnimationCallback, @Nullable CustomAnimationInfo customAnimationInfo) { @Nullable CustomAnimationInfo customAnimationInfo, int letterboxColor) { mType = type; mOnBackNavigationDone = onBackNavigationDone; mOnBackInvokedCallback = onBackInvokedCallback; mPrepareRemoteAnimation = isPrepareRemoteAnimation; mAnimationCallback = isAnimationCallback; mCustomAnimationInfo = customAnimationInfo; mLetterboxColor = letterboxColor; } private BackNavigationInfo(@NonNull Parcel in) { Loading @@ -140,6 +145,7 @@ public final class BackNavigationInfo implements Parcelable { mPrepareRemoteAnimation = in.readBoolean(); mAnimationCallback = in.readBoolean(); mCustomAnimationInfo = in.readTypedObject(CustomAnimationInfo.CREATOR); mLetterboxColor = in.readInt(); } /** @hide */ Loading @@ -151,6 +157,7 @@ public final class BackNavigationInfo implements Parcelable { dest.writeBoolean(mPrepareRemoteAnimation); dest.writeBoolean(mAnimationCallback); dest.writeTypedObject(mCustomAnimationInfo, flags); dest.writeInt(mLetterboxColor); } /** Loading Loading @@ -192,6 +199,13 @@ public final class BackNavigationInfo implements Parcelable { return mAnimationCallback; } /** * @return Letterbox color * @hide */ public int getLetterboxColor() { return mLetterboxColor; } /** * Callback to be called when the back preview is finished in order to notify the server that * it can clean up the resources created for the animation. Loading Loading @@ -387,6 +401,8 @@ public final class BackNavigationInfo implements Parcelable { private CustomAnimationInfo mCustomAnimationInfo; private boolean mAnimationCallback = false; private int mLetterboxColor = Color.TRANSPARENT; /** * @see BackNavigationInfo#getType() */ Loading Loading @@ -453,6 +469,14 @@ public final class BackNavigationInfo implements Parcelable { return this; } /** * @param color Non-transparent if there contain letterbox color. */ public Builder setLetterboxColor(int color) { mLetterboxColor = color; return this; } /** * Builds and returns an instance of {@link BackNavigationInfo} */ Loading @@ -461,7 +485,8 @@ public final class BackNavigationInfo implements Parcelable { mOnBackInvokedCallback, mPrepareRemoteAnimation, mAnimationCallback, mCustomAnimationInfo); mCustomAnimationInfo, mLetterboxColor); } } }
libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt +99 −10 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.content.Context import android.content.res.Configuration import android.graphics.Color import android.graphics.Matrix import android.graphics.PointF import android.graphics.Rect Loading @@ -35,6 +36,7 @@ import android.view.animation.DecelerateInterpolator import android.view.animation.Interpolator import android.window.BackEvent import android.window.BackMotionEvent import android.window.BackNavigationInfo import android.window.BackProgressAnimator import android.window.IOnBackInvokedCallback import com.android.internal.jank.Cuj Loading Loading @@ -67,6 +69,7 @@ class CrossActivityBackAnimation @Inject constructor( private val currentEnteringRect = RectF() private val backAnimRect = Rect() private val cropRect = Rect() private var cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) Loading Loading @@ -95,6 +98,10 @@ class CrossActivityBackAnimation @Inject constructor( private var maxScrimAlpha: Float = 0f private var isLetterboxed = false private var enteringHasSameLetterbox = false private var leftLetterboxLayer: SurfaceControl? = null private var rightLetterboxLayer: SurfaceControl? = null private var letterboxColor: Int = 0 override fun onConfigurationChanged(newConfiguration: Configuration) { cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) Loading @@ -115,8 +122,12 @@ class CrossActivityBackAnimation @Inject constructor( transaction.setAnimationTransaction() isLetterboxed = closingTarget!!.taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed if (isLetterboxed) { // Include letterbox in back animation enteringHasSameLetterbox = isLetterboxed && closingTarget!!.localBounds.equals(enteringTarget!!.localBounds) if (isLetterboxed && !enteringHasSameLetterbox) { // Play animation with letterboxes, if closing and entering target have mismatching // letterboxes backAnimRect.set(closingTarget!!.windowConfiguration.bounds) } else { // otherwise play animation on localBounds only Loading Loading @@ -144,12 +155,25 @@ class CrossActivityBackAnimation @Inject constructor( targetEnteringRect.set(startEnteringRect) targetEnteringRect.scaleCentered(MAX_SCALE) // Draw background with task background color. // Draw background with task background color (or letterbox color). val backgroundColor = if (isLetterboxed) { letterboxColor } else { enteringTarget!!.taskInfo.taskDescription!!.backgroundColor } background.ensureBackground( closingTarget!!.windowConfiguration.bounds, enteringTarget!!.taskInfo.taskDescription!!.backgroundColor, transaction closingTarget!!.windowConfiguration.bounds, backgroundColor, transaction ) ensureScrimLayer() if (isLetterboxed && enteringHasSameLetterbox) { // crop left and right letterboxes cropRect.set(closingTarget!!.localBounds.left, 0, closingTarget!!.localBounds.right, closingTarget!!.windowConfiguration.bounds.height()) // and add fake letterbox square surfaces instead ensureLetterboxes() } else { cropRect.set(backAnimRect) } applyTransaction() } Loading Loading @@ -249,18 +273,25 @@ class CrossActivityBackAnimation @Inject constructor( } finishCallback = null removeScrimLayer() removeLetterbox() isLetterboxed = false enteringHasSameLetterbox = false } private fun applyTransform(leash: SurfaceControl?, rect: RectF, alpha: Float) { if (leash == null || !leash.isValid) return val scale = rect.width() / backAnimRect.width() transformMatrix.reset() transformMatrix.setScale(scale, scale) val scalePivotX = if (isLetterboxed && enteringHasSameLetterbox) { closingTarget!!.localBounds.left.toFloat() } else { 0f } transformMatrix.setScale(scale, scale, scalePivotX, 0f) transformMatrix.postTranslate(rect.left, rect.top) transaction.setAlpha(leash, alpha) .setMatrix(leash, transformMatrix, tmpFloat9) .setCrop(leash, backAnimRect) .setCrop(leash, cropRect) .setCornerRadius(leash, cornerRadius) } Loading Loading @@ -297,15 +328,73 @@ class CrossActivityBackAnimation @Inject constructor( } private fun removeScrimLayer() { scrimLayer?.let { if (removeLayer(scrimLayer)) applyTransaction() scrimLayer = null } /** * Adds two "fake" letterbox square surfaces to the left and right of the localBounds of the * closing target */ private fun ensureLetterboxes() { closingTarget?.let { t -> if (t.localBounds.left != 0 && leftLetterboxLayer == null) { val bounds = Rect(0, t.windowConfiguration.bounds.top, t.localBounds.left, t.windowConfiguration.bounds.bottom) leftLetterboxLayer = ensureLetterbox(bounds) } if (t.localBounds.right != t.windowConfiguration.bounds.right && rightLetterboxLayer == null) { val bounds = Rect(t.localBounds.right, t.windowConfiguration.bounds.top, t.windowConfiguration.bounds.right, t.windowConfiguration.bounds.bottom) rightLetterboxLayer = ensureLetterbox(bounds) } } } private fun ensureLetterbox(bounds: Rect): SurfaceControl { val letterboxBuilder = SurfaceControl.Builder() .setName("Cross-Activity back animation letterbox") .setCallsite("CrossActivityBackAnimation") .setColorLayer() .setOpaque(true) .setHidden(false) rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, letterboxBuilder) val layer = letterboxBuilder.build() val colorComponents = floatArrayOf(Color.red(letterboxColor) / 255f, Color.green(letterboxColor) / 255f, Color.blue(letterboxColor) / 255f) transaction .setColor(layer, colorComponents) .setCrop(layer, bounds) .setRelativeLayer(layer, closingTarget!!.leash, 1) .show(layer) return layer } private fun removeLetterbox() { if (removeLayer(leftLetterboxLayer) || removeLayer(rightLetterboxLayer)) applyTransaction() leftLetterboxLayer = null rightLetterboxLayer = null } private fun removeLayer(layer: SurfaceControl?): Boolean { layer?.let { if (it.isValid) { transaction.remove(it) applyTransaction() return true } } scrimLayer = null return false } override fun prepareNextAnimation( animationInfo: BackNavigationInfo.CustomAnimationInfo?, letterboxColor: Int ): Boolean { this.letterboxColor = letterboxColor return false } private inner class Callback : IOnBackInvokedCallback.Default() { override fun onBackStarted(backMotionEvent: BackMotionEvent) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java +2 −1 Original line number Diff line number Diff line Loading @@ -271,7 +271,8 @@ public class CustomizeActivityAnimation extends ShellBackAnimation { /** Load customize animation before animation start. */ @Override public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo) { public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo, int letterboxColor) { if (animationInfo == null) { return false; } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java +3 −2 Original line number Diff line number Diff line Loading @@ -42,11 +42,12 @@ public abstract class ShellBackAnimation { public abstract BackAnimationRunner getRunner(); /** * Prepare the next animation with customized animation. * Prepare the next animation. * * @return true if this type of back animation should override the default. */ public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo) { public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo, int letterboxColor) { return false; } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java +4 −1 Original line number Diff line number Diff line Loading @@ -154,11 +154,14 @@ public class ShellBackAnimationRegistry { if (type == BackNavigationInfo.TYPE_CROSS_ACTIVITY && mAnimationDefinition.contains(type)) { if (mCustomizeActivityAnimation != null && mCustomizeActivityAnimation.prepareNextAnimation( backNavigationInfo.getCustomAnimationInfo())) { backNavigationInfo.getCustomAnimationInfo(), 0)) { mAnimationDefinition.get(type).resetWaitingAnimation(); mAnimationDefinition.set( BackNavigationInfo.TYPE_CROSS_ACTIVITY, mCustomizeActivityAnimation.getRunner()); } else if (mDefaultCrossActivityAnimation != null) { mDefaultCrossActivityAnimation.prepareNextAnimation(null, backNavigationInfo.getLetterboxColor()); } } BackAnimationRunner runner = mAnimationDefinition.get(type); Loading