diff --git a/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml
index 5add19bba51b5..941df96cb9417 100644
--- a/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml
+++ b/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml
@@ -18,19 +18,10 @@
-->
-
-
+ android:zAdjustment="top"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
-
-
+ android:shareInterpolator="false"
+ android:zAdjustment="top"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
\ No newline at end of file
diff --git a/core/res/res/anim-ldrtl/task_close_exit.xml b/core/res/res/anim-ldrtl/task_close_exit.xml
index 71a44ae7d2fcf..8c0aaa8174300 100644
--- a/core/res/res/anim-ldrtl/task_close_exit.xml
+++ b/core/res/res/anim-ldrtl/task_close_exit.xml
@@ -15,19 +15,9 @@
-->
-
-
+ android:shareInterpolator="false"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
-
-
+ android:shareInterpolator="false"
+ android:zAdjustment="top"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
-
-
-
\ No newline at end of file
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
+
diff --git a/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml b/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml
index 5fccd6df14a57..69631f6525e30 100644
--- a/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml
+++ b/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml
@@ -16,20 +16,10 @@
-->
-
-
+ android:shareInterpolator="false"
+ android:zAdjustment="top"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
@@ -75,4 +38,4 @@
android:toAlpha="1.0"
android:startOffset="717"
android:duration="200"/>
-
\ No newline at end of file
+
diff --git a/core/res/res/anim-ldrtl/task_open_exit.xml b/core/res/res/anim-ldrtl/task_open_exit.xml
index 025e1bdc05c95..f455334ced788 100644
--- a/core/res/res/anim-ldrtl/task_open_exit.xml
+++ b/core/res/res/anim-ldrtl/task_open_exit.xml
@@ -15,19 +15,9 @@
-->
-
-
+ android:shareInterpolator="false"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
-
-
+ android:background="@color/overview_background">
-
-
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
-
-
+ android:shareInterpolator="false"
+ android:zAdjustment="top"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
\ No newline at end of file
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index afc3256cb6173..4b1e89ca0e3a7 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -17,19 +17,9 @@
-->
-
-
+ android:shareInterpolator="false"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
-
-
+
+
-
-
+ android:shareInterpolator="false"
+ android:zAdjustment="top"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
\ No newline at end of file
diff --git a/core/res/res/anim/task_open_enter_cross_profile_apps.xml b/core/res/res/anim/task_open_enter_cross_profile_apps.xml
index 702f7ba162aae..dc316ff20f940 100644
--- a/core/res/res/anim/task_open_enter_cross_profile_apps.xml
+++ b/core/res/res/anim/task_open_enter_cross_profile_apps.xml
@@ -18,20 +18,10 @@
-->
-
-
+ android:shareInterpolator="false"
+ android:zAdjustment="top"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 691317d2e6e01..f8ab65517d5a2 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -17,19 +17,9 @@
-->
-
-
+ android:shareInterpolator="false"
+ android:hasRoundedCorners="true"
+ android:background="@color/overview_background">
-
-
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="500"/>
+
+
+
+
\ No newline at end of file
diff --git a/core/res/res/color/overview_background_dark.xml b/core/res/res/color/overview_background_dark.xml
new file mode 100644
index 0000000000000..84f4fdff4e1ad
--- /dev/null
+++ b/core/res/res/color/overview_background_dark.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 2e4578c394309..783fabe20a6d7 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -33,4 +33,6 @@
#5DBA80
#8AB4F8
+
+ @color/overview_background_dark
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 3c6c23b08091f..c7bf8ecfe949c 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -59,11 +59,30 @@ class SurfaceAnimator {
@VisibleForTesting
final Animatable mAnimatable;
private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
+
+ /**
+ * Static callback to run on all animations started through this SurfaceAnimator
+ * when an animation on a Surface is finished or cancelled without restart.
+ */
@VisibleForTesting
@Nullable
final OnAnimationFinishedCallback mStaticAnimationFinishedCallback;
+
+ /**
+ * Callback unique to each animation (i.e. AnimationAdapter). To be run when an animation on a
+ * Surface is finished or cancelled without restart.
+ */
@Nullable
- private OnAnimationFinishedCallback mAnimationFinishedCallback;
+ private OnAnimationFinishedCallback mSurfaceAnimationFinishedCallback;
+
+ /**
+ * The callback is triggered after the SurfaceAnimator sends a cancel call to the underlying
+ * AnimationAdapter.
+ * NOTE: Must be called wherever we call onAnimationCancelled on mAnimation.
+ */
+ @Nullable
+ private Runnable mAnimationCancelledCallback;
+
private boolean mAnimationStartDelayed;
/**
@@ -100,7 +119,7 @@ class SurfaceAnimator {
return;
}
final OnAnimationFinishedCallback animationFinishCallback =
- mAnimationFinishedCallback;
+ mSurfaceAnimationFinishedCallback;
reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
if (staticAnimationFinishedCallback != null) {
staticAnimationFinishedCallback.onAnimationFinished(type, anim);
@@ -130,15 +149,19 @@ class SurfaceAnimator {
* This is important as it will start with the leash hidden or visible before
* handing it to the component that is responsible to run the animation.
* @param animationFinishedCallback The callback being triggered when the animation finishes.
+ * @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
+ * cancel call to the underlying AnimationAdapter.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback,
+ @Nullable Runnable animationCancelledCallback,
@Nullable SurfaceFreezer freezer) {
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
mAnimation = anim;
mAnimationType = type;
- mAnimationFinishedCallback = animationFinishedCallback;
+ mSurfaceAnimationFinishedCallback = animationFinishedCallback;
+ mAnimationCancelledCallback = animationCancelledCallback;
final SurfaceControl surface = mAnimatable.getSurfaceControl();
if (surface == null) {
Slog.w(TAG, "Unable to start animation, surface is null or no children.");
@@ -160,15 +183,10 @@ class SurfaceAnimator {
mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
}
- void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
- @AnimationType int type,
- @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
- startAnimation(t, anim, hidden, type, animationFinishedCallback, null /* freezer */);
- }
-
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type) {
- startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
+ startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */,
+ null /* animationCancelledCallback */, null /* freezer */);
}
/**
@@ -278,7 +296,8 @@ class SurfaceAnimator {
mLeash = from.mLeash;
mAnimation = from.mAnimation;
mAnimationType = from.mAnimationType;
- mAnimationFinishedCallback = from.mAnimationFinishedCallback;
+ mSurfaceAnimationFinishedCallback = from.mSurfaceAnimationFinishedCallback;
+ mAnimationCancelledCallback = from.mAnimationCancelledCallback;
// Cancel source animation, but don't let animation runner cancel the animation.
from.cancelAnimation(t, false /* restarting */, false /* forwardCancel */);
@@ -306,11 +325,16 @@ class SurfaceAnimator {
final SurfaceControl leash = mLeash;
final AnimationAdapter animation = mAnimation;
final @AnimationType int animationType = mAnimationType;
- final OnAnimationFinishedCallback animationFinishedCallback = mAnimationFinishedCallback;
+ final OnAnimationFinishedCallback animationFinishedCallback =
+ mSurfaceAnimationFinishedCallback;
+ final Runnable animationCancelledCallback = mAnimationCancelledCallback;
reset(t, false);
if (animation != null) {
if (!mAnimationStartDelayed && forwardCancel) {
animation.onAnimationCancelled(leash);
+ if (animationCancelledCallback != null) {
+ animationCancelledCallback.run();
+ }
}
if (!restarting) {
if (mStaticAnimationFinishedCallback != null) {
@@ -335,7 +359,7 @@ class SurfaceAnimator {
private void reset(Transaction t, boolean destroyLeash) {
mService.mAnimationTransferMap.remove(mAnimation);
mAnimation = null;
- mAnimationFinishedCallback = null;
+ mSurfaceAnimationFinishedCallback = null;
mAnimationType = ANIMATION_TYPE_NONE;
if (mLeash == null) {
return;
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index d450dbffe4a1a..ee4c629189dc6 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -42,6 +42,9 @@ import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static java.lang.Integer.MIN_VALUE;
+
+import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
@@ -79,6 +82,22 @@ final class TaskDisplayArea extends DisplayArea {
DisplayContent mDisplayContent;
+ /**
+ * A color layer that serves as a solid color background to certain animations.
+ */
+ private SurfaceControl mColorBackgroundLayer;
+
+ /**
+ * This counter is used to make sure we don't prematurely clear the background color in the
+ * case that background color animations are interleaved.
+ * NOTE: The last set color will remain until the counter is reset to 0, which means that an
+ * animation background color may sometime remain after the animation has finished through an
+ * animation with a different background color if an animation starts after and ends before
+ * another where both set different background colors. However, this is not a concern as
+ * currently all task animation backgrounds are the same color.
+ */
+ private int mColorLayerCounter = 0;
+
/**
* A control placed at the appropriate level for transitions to occur.
*/
@@ -961,6 +980,11 @@ final class TaskDisplayArea extends DisplayArea {
void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
if (getParent() != null) {
super.onParentChanged(newParent, oldParent, () -> {
+ mColorBackgroundLayer = makeChildSurface(null)
+ .setColorLayer()
+ .setName("colorBackgroundLayer")
+ .setCallsite("TaskDisplayArea.onParentChanged")
+ .build();
mAppAnimationLayer = makeChildSurface(null)
.setName("animationLayer")
.setCallsite("TaskDisplayArea.onParentChanged")
@@ -977,6 +1001,7 @@ final class TaskDisplayArea extends DisplayArea {
.setName("splitScreenDividerAnchor")
.setCallsite("TaskDisplayArea.onParentChanged")
.build();
+
getSyncTransaction()
.show(mAppAnimationLayer)
.show(mBoostedAppAnimationLayer)
@@ -986,11 +1011,13 @@ final class TaskDisplayArea extends DisplayArea {
} else {
super.onParentChanged(newParent, oldParent);
mWmService.mTransactionFactory.get()
+ .remove(mColorBackgroundLayer)
.remove(mAppAnimationLayer)
.remove(mBoostedAppAnimationLayer)
.remove(mHomeAppAnimationLayer)
.remove(mSplitScreenDividerAnchor)
.apply();
+ mColorBackgroundLayer = null;
mAppAnimationLayer = null;
mBoostedAppAnimationLayer = null;
mHomeAppAnimationLayer = null;
@@ -998,6 +1025,39 @@ final class TaskDisplayArea extends DisplayArea {
}
}
+ void setBackgroundColor(@ColorInt int color) {
+ if (mColorBackgroundLayer == null) {
+ return;
+ }
+
+ float r = ((color >> 16) & 0xff) / 255.0f;
+ float g = ((color >> 8) & 0xff) / 255.0f;
+ float b = ((color >> 0) & 0xff) / 255.0f;
+ float a = ((color >> 24) & 0xff) / 255.0f;
+
+ mColorLayerCounter++;
+
+ getPendingTransaction().setLayer(mColorBackgroundLayer, MIN_VALUE)
+ .setColor(mColorBackgroundLayer, new float[]{r, g, b})
+ .setAlpha(mColorBackgroundLayer, a)
+ .setWindowCrop(mColorBackgroundLayer, getSurfaceWidth(), getSurfaceHeight())
+ .setPosition(mColorBackgroundLayer, 0, 0)
+ .show(mColorBackgroundLayer);
+
+ scheduleAnimation();
+ }
+
+ void clearBackgroundColor() {
+ mColorLayerCounter--;
+
+ // Only clear the color layer if we have received the same amounts of clear as set
+ // requests.
+ if (mColorLayerCounter == 0) {
+ getPendingTransaction().hide(mColorBackgroundLayer);
+ scheduleAnimation();
+ }
+ }
+
@Override
void migrateToNewSurfaceControl(SurfaceControl.Transaction t) {
super.migrateToNewSurfaceControl(t);
@@ -1006,6 +1066,7 @@ final class TaskDisplayArea extends DisplayArea {
}
// As TaskDisplayArea is getting a new surface, reparent and reorder the child surfaces.
+ t.reparent(mColorBackgroundLayer, mSurfaceControl);
t.reparent(mAppAnimationLayer, mSurfaceControl);
t.reparent(mBoostedAppAnimationLayer, mSurfaceControl);
t.reparent(mHomeAppAnimationLayer, mSurfaceControl);
@@ -2148,6 +2209,11 @@ final class TaskDisplayArea extends DisplayArea {
mPreferredTopFocusableRootTask = null;
}
+ @Override
+ TaskDisplayArea getTaskDisplayArea() {
+ return this;
+ }
+
@Override
boolean isTaskDisplayArea() {
return true;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b1c7e196b70c2..d9a8883e299ed 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -850,6 +850,12 @@ class WindowContainer extends ConfigurationContainer<
return parent != null ? parent.getRootDisplayArea() : null;
}
+ @Nullable
+ TaskDisplayArea getTaskDisplayArea() {
+ WindowContainer parent = getParent();
+ return parent != null ? parent.getTaskDisplayArea() : null;
+ }
+
boolean isAttached() {
return getDisplayArea() != null;
}
@@ -2495,10 +2501,13 @@ class WindowContainer extends ConfigurationContainer<
* some point but the meaning is too weird to work for all containers.
* @param type The type of animation defined as {@link AnimationType}.
* @param animationFinishedCallback The callback being triggered when the animation finishes.
+ * @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
+ * cancel call to the underlying AnimationAdapter.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
- @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+ @Nullable OnAnimationFinishedCallback animationFinishedCallback,
+ @Nullable Runnable animationCancelledCallback) {
if (DEBUG_ANIM) {
Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim);
}
@@ -2506,7 +2515,14 @@ class WindowContainer extends ConfigurationContainer<
// TODO: This should use isVisible() but because isVisible has a really weird meaning at
// the moment this doesn't work for all animatable window containers.
mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
- mSurfaceFreezer);
+ animationCancelledCallback, mSurfaceFreezer);
+ }
+
+ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
+ @AnimationType int type,
+ @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+ startAnimation(t, anim, hidden, type, animationFinishedCallback,
+ null /* adapterAnimationCancelledCallback */);
}
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@@ -2714,8 +2730,27 @@ class WindowContainer extends ConfigurationContainer<
if (sources != null) {
mSurfaceAnimationSources.addAll(sources);
}
+
+ TaskDisplayArea taskDisplayArea = getTaskDisplayArea();
+ int backgroundColor = adapter.getBackgroundColor();
+
+ boolean shouldSetBackgroundColor = taskDisplayArea != null && backgroundColor != 0;
+
+ if (shouldSetBackgroundColor) {
+ taskDisplayArea.setBackgroundColor(backgroundColor);
+ }
+
+ Runnable clearColorBackground = () -> {
+ if (shouldSetBackgroundColor) {
+ taskDisplayArea.clearBackgroundColor();
+ }
+ };
+
startAnimation(getPendingTransaction(), adapter, !isVisible(),
- ANIMATION_TYPE_APP_TRANSITION);
+ ANIMATION_TYPE_APP_TRANSITION,
+ (type, anim) -> clearColorBackground.run(),
+ clearColorBackground);
+
if (adapter.getShowWallpaper()) {
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}