diff options
21 files changed, 97 insertions, 25 deletions
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index e0950948afb8..3b60aee8f604 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -207,6 +207,7 @@ public abstract class Animation implements Cloneable { private float mScaleFactor = 1f; private boolean mShowWallpaper; + private boolean mHasRoundedCorners; private boolean mMore = true; private boolean mOneMoreTime = true; @@ -263,6 +264,8 @@ public abstract class Animation implements Cloneable { a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false)); setShowWallpaper( a.getBoolean(com.android.internal.R.styleable.Animation_showWallpaper, false)); + setHasRoundedCorners( + a.getBoolean(com.android.internal.R.styleable.Animation_hasRoundedCorners, false)); final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0); @@ -678,6 +681,19 @@ public abstract class Animation implements Cloneable { } /** + * If this is a window animation, the window will have rounded corners matching the display + * corner radius. + * + * @param hasRoundedCorners Whether the window should have rounded corners or not. + * @attr ref android.R.styleable#Animation_hasRoundedCorners + * @see com.android.internal.policy.ScreenDecorationsUtils#getWindowCornerRadius(Resources) + * @hide + */ + public void setHasRoundedCorners(boolean hasRoundedCorners) { + mHasRoundedCorners = hasRoundedCorners; + } + + /** * Gets the acceleration curve type for this animation. * * @return the {@link Interpolator} associated to this animation @@ -804,6 +820,16 @@ public abstract class Animation implements Cloneable { } /** + * @return if a window animation should have rounded corners or not. + * + * @attr ref android.R.styleable#Animation_hasRoundedCorners + * @hide + */ + public boolean hasRoundedCorners() { + return mHasRoundedCorners; + } + + /** * <p>Indicates whether or not this animation will affect the transformation * matrix. For instance, a fade animation will not affect the matrix whereas * a scale animation will.</p> 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 6f3dc8c7de0e..5add19bba51b 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,7 +18,9 @@ --> <!-- This should be kept in sync with task_open_enter.xml --> <set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" android:zAdjustment="top"> + android:hasRoundedCorners="true" + android:shareInterpolator="false" + android:zAdjustment="top"> <alpha android:fromAlpha="1" diff --git a/core/res/res/anim-ldrtl/task_close_enter.xml b/core/res/res/anim-ldrtl/task_close_enter.xml index 7abada332fb6..e00141a8c155 100644 --- a/core/res/res/anim-ldrtl/task_close_enter.xml +++ b/core/res/res/anim-ldrtl/task_close_enter.xml @@ -16,6 +16,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha diff --git a/core/res/res/anim-ldrtl/task_close_exit.xml b/core/res/res/anim-ldrtl/task_close_exit.xml index a017820a4b3e..71a44ae7d2fc 100644 --- a/core/res/res/anim-ldrtl/task_close_exit.xml +++ b/core/res/res/anim-ldrtl/task_close_exit.xml @@ -16,6 +16,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha diff --git a/core/res/res/anim-ldrtl/task_open_enter.xml b/core/res/res/anim-ldrtl/task_open_enter.xml index 0433664717eb..7815f7d661d0 100644 --- a/core/res/res/anim-ldrtl/task_open_enter.xml +++ b/core/res/res/anim-ldrtl/task_open_enter.xml @@ -18,6 +18,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha 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 45ca80e00e22..5fccd6df14a5 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 @@ -18,6 +18,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha diff --git a/core/res/res/anim-ldrtl/task_open_exit.xml b/core/res/res/anim-ldrtl/task_open_exit.xml index f50494d81eb5..025e1bdc05c9 100644 --- a/core/res/res/anim-ldrtl/task_open_exit.xml +++ b/core/res/res/anim-ldrtl/task_open_exit.xml @@ -16,6 +16,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha diff --git a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml index 4c2559f1e47d..2cfeecf4685d 100644 --- a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml +++ b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml @@ -18,7 +18,9 @@ --> <!-- This should be kept in sync with task_open_enter.xml --> <set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" android:zAdjustment="top"> + android:shareInterpolator="false" + android:hasRoundedCorners="true" + android:zAdjustment="top"> <alpha android:fromAlpha="1" diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml index b059aa9cb28c..487ff5c748d3 100644 --- a/core/res/res/anim/task_close_enter.xml +++ b/core/res/res/anim/task_close_enter.xml @@ -18,6 +18,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml index c9ade227819b..afc3256cb617 100644 --- a/core/res/res/anim/task_close_exit.xml +++ b/core/res/res/anim/task_close_exit.xml @@ -18,6 +18,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml index 5c618594364f..0aafc1c0b91c 100644 --- a/core/res/res/anim/task_open_enter.xml +++ b/core/res/res/anim/task_open_enter.xml @@ -20,6 +20,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha 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 644104721463..702f7ba162aa 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 @@ -20,6 +20,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml index 9394c577da78..691317d2e6e0 100644 --- a/core/res/res/anim/task_open_exit.xml +++ b/core/res/res/anim/task_open_exit.xml @@ -18,6 +18,7 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" + android:hasRoundedCorners="true" android:showWallpaper="true"> <alpha diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 088669da7b91..743496fdffb5 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -6488,6 +6488,9 @@ <!-- Special option for window animations: show the wallpaper behind when running this animation. --> <attr name="showWallpaper" format="boolean" /> + <!-- Special option for window animations: whether window should have rounded corners. + @see ScreenDecorationsUtils#getWindowCornerRadius(Resources) --> + <attr name="hasRoundedCorners" format="boolean" /> </declare-styleable> <declare-styleable name="AnimationSet"> diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java index 5519729c17f5..bbbf11d2a7a2 100644 --- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java +++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java @@ -118,7 +118,8 @@ class AppWindowThumbnail implements Animatable { anim.scaleCurrentDuration(mAppToken.mWmService.getTransitionAnimationScaleLocked()); mSurfaceAnimator.startAnimation(t, new LocalAnimationAdapter( new WindowAnimationSpec(anim, position, - mAppToken.getDisplayContent().mAppTransition.canSkipFirstFrame()), + mAppToken.getDisplayContent().mAppTransition.canSkipFirstFrame(), + mAppToken.mWmService.mWindowCornerRadius), mAppToken.mWmService.mSurfaceAnimationRunner), false /* hidden */); } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 88c8b953a2e9..f5592e057df6 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -2526,7 +2526,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree new WindowAnimationSpec(a, mTmpPoint, mTmpRect, getDisplayContent().mAppTransition.canSkipFirstFrame(), appStackClipMode, - true /* isAppAnimation */), + true /* isAppAnimation */, + mWmService.mWindowCornerRadius), mWmService.mSurfaceAnimationRunner); if (a.getZAdjustment() == Animation.ZORDER_TOP) { mNeedsZBoost = true; diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java index 98c77ac719f9..57311e19bc76 100644 --- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java +++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java @@ -17,10 +17,10 @@ package com.android.server.wm; import static com.android.server.wm.AnimationAdapter.STATUS_BAR_TRANSITION_DURATION; -import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; -import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; import static com.android.server.wm.AnimationSpecProto.WINDOW; import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION; +import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; +import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; import android.graphics.Point; import android.graphics.Rect; @@ -51,18 +51,22 @@ public class WindowAnimationSpec implements AnimationSpec { private final Rect mStackBounds = new Rect(); private int mStackClipMode; private final Rect mTmpRect = new Rect(); + private final float mWindowCornerRadius; - public WindowAnimationSpec(Animation animation, Point position, boolean canSkipFirstFrame) { + public WindowAnimationSpec(Animation animation, Point position, boolean canSkipFirstFrame, + float windowCornerRadius) { this(animation, position, null /* stackBounds */, canSkipFirstFrame, STACK_CLIP_NONE, - false /* isAppAnimation */); + false /* isAppAnimation */, windowCornerRadius); } public WindowAnimationSpec(Animation animation, Point position, Rect stackBounds, - boolean canSkipFirstFrame, int stackClipMode, boolean isAppAnimation) { + boolean canSkipFirstFrame, int stackClipMode, boolean isAppAnimation, + float windowCornerRadius) { mAnimation = animation; if (position != null) { mPosition.set(position.x, position.y); } + mWindowCornerRadius = windowCornerRadius; mCanSkipFirstFrame = canSkipFirstFrame; mIsAppAnimation = isAppAnimation; mStackClipMode = stackClipMode; @@ -101,6 +105,9 @@ public class WindowAnimationSpec implements AnimationSpec { mTmpRect.intersect(tmp.transformation.getClipRect()); t.setWindowCrop(leash, mTmpRect); } + if (mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) { + t.setCornerRadius(leash, mWindowCornerRadius); + } } @Override diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e19c7c66815c..aa4f54f8bfcb 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -234,6 +234,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IResultReceiver; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; +import com.android.internal.policy.ScreenDecorationsUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.LatencyTracker; @@ -751,24 +752,27 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayManager mDisplayManager; final ActivityTaskManagerService mAtmService; - // Indicates whether this device supports wide color gamut / HDR rendering + /** Corner radius that windows should have in order to match the display. */ + final float mWindowCornerRadius; + + /** Indicates whether this device supports wide color gamut / HDR rendering */ private boolean mHasWideColorGamutSupport; private boolean mHasHdrSupport; - // Who is holding the screen on. + /** Who is holding the screen on. */ private Session mHoldingScreenOn; private PowerManager.WakeLock mHoldingScreenWakeLock; - // Whether or not a layout can cause a wake up when theater mode is enabled. + /** Whether or not a layout can cause a wake up when theater mode is enabled. */ boolean mAllowTheaterModeWakeFromLayout; final TaskPositioningController mTaskPositioningController; final DragDropController mDragDropController; - // For frozen screen animations. + /** For frozen screen animations. */ private int mExitAnimId, mEnterAnimId; - // The display that the rotation animation is applying to. + /** The display that the rotation animation is applying to. */ private int mFrozenDisplayId; /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this @@ -975,7 +979,7 @@ public class WindowManagerService extends IWindowManager.Stub mInputManager = inputManager; // Must be before createDisplayContentLocked. mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mDisplayWindowSettings = new DisplayWindowSettings(this); - + mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context.getResources()); mTransactionFactory = transactionFactory; mTransaction = mTransactionFactory.make(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 706901bb9785..805fc915893a 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -4458,7 +4458,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP anim.restrictDuration(MAX_ANIMATION_DURATION); anim.scaleCurrentDuration(mWmService.getWindowAnimationScaleLocked()); final AnimationAdapter adapter = new LocalAnimationAdapter( - new WindowAnimationSpec(anim, mSurfacePosition, false /* canSkipFirstFrame */), + new WindowAnimationSpec(anim, mSurfacePosition, false /* canSkipFirstFrame */, + mWmService.mWindowCornerRadius), mWmService.mSurfaceAnimationRunner); startAnimation(mPendingTransaction, adapter); commitPendingTransaction(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java index 6cce9f088ee4..c48348992196 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java @@ -213,7 +213,8 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase { final Animation a = new TranslateAnimation(-10, 10, 0, 0); a.initialize(0, 0, 0, 0); a.setDuration(50); - return new WindowAnimationSpec(a, new Point(0, 0), false /* canSkipFirstFrame */); + return new WindowAnimationSpec(a, new Point(0, 0), false /* canSkipFirstFrame */, + 0 /* windowCornerRadius */); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java index 9a825e068584..897f0a2c6e81 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java @@ -24,6 +24,8 @@ import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.when; import android.graphics.Point; import android.graphics.Rect; @@ -56,7 +58,7 @@ public class WindowAnimationSpecTest { Animation a = createClipRectAnimation(windowCrop, windowCrop); WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null, mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE, - true /* isAppAnimation */); + true /* isAppAnimation */, 0 /* windowCornerRadius */); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(rect -> rect.equals(windowCrop))); @@ -66,7 +68,7 @@ public class WindowAnimationSpecTest { public void testApply_clipAfter() { WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null, mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM, - true /* isAppAnimation */); + true /* isAppAnimation */, 0 /* windowCornerRadius */); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty)); } @@ -76,8 +78,7 @@ public class WindowAnimationSpecTest { // Stack bounds is (0, 0, 10, 10) position is (20, 40) WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, new Point(20, 40), mStackBounds, false /* canSkipFirstFrame */, - STACK_CLIP_AFTER_ANIM, - true /* isAppAnimation */); + STACK_CLIP_AFTER_ANIM, true /* isAppAnimation */, 0 /* windowCornerRadius */); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty)); } @@ -87,7 +88,7 @@ public class WindowAnimationSpecTest { // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 0, 0) WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null, mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM, - true /* isAppAnimation */); + true /* isAppAnimation */, 0 /* windowCornerRadius */); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(rect -> rect.equals(mStackBounds))); @@ -101,19 +102,32 @@ public class WindowAnimationSpecTest { a.initialize(0, 0, 0, 0); WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null, null, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM, - true /* isAppAnimation */); + true /* isAppAnimation */, 0 /* windowCornerRadius */); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty)); } @Test + public void testApply_setCornerRadius() { + final float windowCornerRadius = 30f; + WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null, + mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM, + true /* isAppAnimation */, windowCornerRadius); + windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); + verify(mTransaction, never()).setCornerRadius(eq(mSurfaceControl), eq(windowCornerRadius)); + when(mAnimation.hasRoundedCorners()).thenReturn(true); + windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); + verify(mTransaction).setCornerRadius(eq(mSurfaceControl), eq(windowCornerRadius)); + } + + @Test public void testApply_clipBeforeSmallerAnimationClip() { // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 5, 5) Rect windowCrop = new Rect(0, 0, 5, 5); Animation a = createClipRectAnimation(windowCrop, windowCrop); WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null, mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM, - true /* isAppAnimation */); + true /* isAppAnimation */, 0 /* windowCornerRadius */); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(rect -> rect.equals(windowCrop))); @@ -126,7 +140,7 @@ public class WindowAnimationSpecTest { Animation a = createClipRectAnimation(windowCrop, windowCrop); WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null, mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM, - true /* isAppAnimation */); + true /* isAppAnimation */, 0 /* windowCornerRadius */); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(rect -> rect.equals(mStackBounds))); |