From 4a7c927360578ecdf2f184a6dd4f3730135a99c7 Mon Sep 17 00:00:00 2001 From: Pablo Gamito Date: Thu, 2 Dec 2021 17:47:20 +0100 Subject: [PATCH 1/2] Add API to show background behind animating windows For the new style of Material 3 activity transitions (go/t-activity-transitions) we fully fade in and out activity windows to a solid background color (that of the activity's theme). This means we need to provide a way for activity transitions to show a solid background color behind the animating windows to fill any space that would otherwise be black. This ability should be available both to system transitions but also to apps that want to create transitions in a similar style without necessarily using exactly the system one. The API provides a way to specify if a background should be shown behind the animation or not. If a background is requested it is up to the transition handler to drawn this background appropriately based on the type of transition and task/activity info. Test: atest CtsWindowManagerDeviceTestCases:AnimationBackgroundTests Bug: 202844659 Change-Id: Iddee6583fb1ad83e3ec238a89030b8c284e04d03 --- core/api/current.txt | 3 ++ .../android/view/animation/Animation.java | 45 +++++++++++++++++++ core/res/res/values/attrs.xml | 3 ++ core/res/res/values/public.xml | 1 + 4 files changed, 52 insertions(+) diff --git a/core/api/current.txt b/core/api/current.txt index 9e7bc69152702..967199e685d1b 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1314,6 +1314,7 @@ package android { field public static final int shouldDisableView = 16843246; // 0x10101ee field public static final int shouldUseDefaultUnfoldTransition = 16844364; // 0x101064c field public static final int showAsAction = 16843481; // 0x10102d9 + field public static final int showBackground; field public static final int showClockAndComplications; field public static final int showDefault = 16843258; // 0x10101fa field public static final int showDividers = 16843561; // 0x1010329 @@ -52454,6 +52455,7 @@ package android.view.animation { method public int getRepeatCount(); method public int getRepeatMode(); method protected float getScaleFactor(); + method public boolean getShowBackground(); method public long getStartOffset(); method public long getStartTime(); method public boolean getTransformation(long, android.view.animation.Transformation); @@ -52479,6 +52481,7 @@ package android.view.animation { method public void setInterpolator(android.view.animation.Interpolator); method public void setRepeatCount(int); method public void setRepeatMode(int); + method public void setShowBackground(boolean); method public void setStartOffset(long); method public void setStartTime(long); method public void setZAdjustment(int); diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index b1d618eff40a6..ab749ee284a86 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -209,6 +209,13 @@ public abstract class Animation implements Cloneable { private boolean mShowWallpaper; private boolean mHasRoundedCorners; + /** + * Whether to show a background behind the windows during the animation. + * @see #getShowBackground() + * @see #setShowBackground(boolean) + */ + private boolean mShowBackground; + private boolean mMore = true; private boolean mOneMoreTime = true; @@ -266,6 +273,8 @@ public abstract class Animation implements Cloneable { a.getBoolean(com.android.internal.R.styleable.Animation_showWallpaper, false)); setHasRoundedCorners( a.getBoolean(com.android.internal.R.styleable.Animation_hasRoundedCorners, false)); + setShowBackground( + a.getBoolean(com.android.internal.R.styleable.Animation_showBackground, false)); final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0); @@ -697,6 +706,24 @@ public abstract class Animation implements Cloneable { mHasRoundedCorners = hasRoundedCorners; } + /** + * If showBackground is {@code true} and this animation is applied on a window, then the windows + * in the animation will animate with the background associated with this window behind them. + * + * The background comes from the {@link android.R.styleable#Theme_colorBackground} that is + * applied to this window through its theme. + * + * If multiple animating windows have showBackground set to {@code true} during an animation, + * the top most window with showBackground set to {@code true} and a valid background color + * takes precedence. + * + * @param showBackground Whether to show a background behind the windows during the animation. + * @attr ref android.R.styleable#Animation_showBackground + */ + public void setShowBackground(boolean showBackground) { + mShowBackground = showBackground; + } + /** * Gets the acceleration curve type for this animation. * @@ -837,6 +864,24 @@ public abstract class Animation implements Cloneable { return mHasRoundedCorners; } + /** + * If showBackground is {@code true} and this animation is applied on a window, then the windows + * in the animation will animate with the background associated with this window behind them. + * + * The background comes from the {@link android.R.styleable#Theme_colorBackground} that is + * applied to this window through its theme. + * + * If multiple animating windows have showBackground set to {@code true} during an animation, + * the top most window with showBackground set to {@code true} and a valid background color + * takes precedence. + * + * @return if the background of this window should be shown behind the animating windows. + * @attr ref android.R.styleable#Animation_showBackground + */ + public boolean getShowBackground() { + return mShowBackground; + } + /** *

Indicates whether or not this animation will affect the transformation * matrix. For instance, a fade animation will not affect the matrix whereas diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index d2dc6005f3f3a..a08bca3b3fe94 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -6884,6 +6884,9 @@ + + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index dfeeccf80423c..e801ac0ba71a6 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3254,6 +3254,7 @@ + From 157738c8a05bc69afad7d131aaaee042fe03bbf9 Mon Sep 17 00:00:00 2001 From: Pablo Gamito Date: Wed, 1 Dec 2021 19:55:59 +0100 Subject: [PATCH 2/2] Support backgrounds during animations in shell This is required for the go/t-activity-transitions where we want to allow apps to fade to a clear background color and fade back in from the background to another activity Test: atest FlickerTests Bug: 202844659 Change-Id: Iea18a8e7d32a63da55ab3430c47f903da5cff807 --- core/java/android/window/TransitionInfo.java | 15 ++++++ .../transition/DefaultTransitionHandler.java | 47 +++++++++++-------- .../com/android/server/wm/Transition.java | 9 ++++ 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 915c8fb9a6dd1..fd1e848221938 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -36,6 +36,7 @@ import static android.view.WindowManager.TransitionFlags; import static android.view.WindowManager.TransitionType; import static android.view.WindowManager.transitTypeToString; +import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -366,6 +367,7 @@ public final class TransitionInfo implements Parcelable { private int mStartRotation = ROTATION_UNDEFINED; private int mEndRotation = ROTATION_UNDEFINED; private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; + private @ColorInt int mBackgroundColor; public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) { mContainer = container; @@ -387,6 +389,7 @@ public final class TransitionInfo implements Parcelable { mStartRotation = in.readInt(); mEndRotation = in.readInt(); mRotationAnimation = in.readInt(); + mBackgroundColor = in.readInt(); } /** Sets the parent of this change's container. The parent must be a participant or null. */ @@ -446,6 +449,11 @@ public final class TransitionInfo implements Parcelable { mRotationAnimation = anim; } + /** Sets the background color of this change's container. */ + public void setBackgroundColor(@ColorInt int backgroundColor) { + mBackgroundColor = backgroundColor; + } + /** @return the container that is changing. May be null if non-remotable (eg. activity) */ @Nullable public WindowContainerToken getContainer() { @@ -526,6 +534,12 @@ public final class TransitionInfo implements Parcelable { return mRotationAnimation; } + /** @return get the background color of this change's container. */ + @ColorInt + public int getBackgroundColor() { + return mBackgroundColor; + } + /** @hide */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { @@ -542,6 +556,7 @@ public final class TransitionInfo implements Parcelable { dest.writeInt(mStartRotation); dest.writeInt(mEndRotation); dest.writeInt(mRotationAnimation); + dest.writeInt(mBackgroundColor); } @NonNull diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 11b23875437f9..5054e60d09f88 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -291,8 +291,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */); }; - boolean requireBackgroundForTransition = false; - + @ColorInt int backgroundColorForTransition = 0; final int wallpaperTransit = getWallpaperTransitType(info); for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); @@ -352,8 +351,19 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { Animation a = loadAnimation(info, change, wallpaperTransit); if (a != null) { - if (changeRequiresBackground(info, change)) { - requireBackgroundForTransition = true; + if (isTask) { + final @TransitionType int type = info.getType(); + final boolean isOpenOrCloseTransition = type == TRANSIT_OPEN + || type == TRANSIT_CLOSE + || type == TRANSIT_TO_FRONT + || type == TRANSIT_TO_BACK; + if (isOpenOrCloseTransition) { + // Use the overview background as the background for the animation + final Context uiContext = ActivityThread.currentActivityThread() + .getSystemUiContext(); + backgroundColorForTransition = + uiContext.getColor(R.color.overview_background); + } } float cornerRadius = 0; @@ -365,6 +375,15 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { ScreenDecorationsUtils.getWindowCornerRadius(displayContext); } + if (a.getShowBackground()) { + // use the window's background color if provided as the background color for the + // animation - the top most window with a valid background color and + // showBackground set takes precedence. + if (change.getBackgroundColor() != 0) { + backgroundColorForTransition = change.getBackgroundColor(); + } + } + startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish, mTransactionPool, mMainExecutor, mAnimExecutor, null /* position */, cornerRadius, change.getEndAbsBounds()); @@ -376,8 +395,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } } - if (requireBackgroundForTransition) { - addBackgroundToTransition(info.getRootLeash(), startTransaction, finishTransaction); + if (backgroundColorForTransition != 0) { + addBackgroundToTransition(info.getRootLeash(), backgroundColorForTransition, + startTransaction, finishTransaction); } startTransaction.apply(); @@ -388,24 +408,13 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { return true; } - private boolean changeRequiresBackground(TransitionInfo info, - TransitionInfo.Change change) { - final boolean isTask = change.getTaskInfo() != null; - final @TransitionType int type = info.getType(); - final boolean isOpenOrCloseTransition = type == TRANSIT_OPEN || type == TRANSIT_CLOSE - || type == TRANSIT_TO_FRONT || type == TRANSIT_TO_BACK; - return isTask && isOpenOrCloseTransition; - } - private void addBackgroundToTransition( @NonNull SurfaceControl rootLeash, + @ColorInt int color, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction ) { - final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext(); - final @ColorInt int overviewBackgroundColor = - uiContext.getColor(R.color.overview_background); - final Color bgColor = Color.valueOf(overviewBackgroundColor); + final Color bgColor = Color.valueOf(color); final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() }; final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder() diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index a4771082b3e93..b13c9a9e3e14e 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -79,6 +79,7 @@ import android.window.RemoteTransition; import android.window.TransitionInfo; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.graphics.ColorUtils; import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledLambda; @@ -1271,6 +1272,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe change.setAllowEnterPip(topMostActivity != null && topMostActivity.checkEnterPictureInPictureAppOpsState()); } + final ActivityRecord activityRecord = target.asActivityRecord(); + if (activityRecord != null) { + final Task arTask = activityRecord.getTask(); + final int backgroundColor = ColorUtils.setAlphaComponent( + arTask.getTaskDescription().getBackgroundColor(), 255); + change.setBackgroundColor(backgroundColor); + } + out.addChange(change); }