diff options
| author | 2023-06-30 10:05:58 +0000 | |
|---|---|---|
| committer | 2023-07-11 15:28:30 +0000 | |
| commit | e9817b700d1c5a51ec04b27a8664ca9ab89af49d (patch) | |
| tree | d067722cf09d491cea80ef986e2e5fd264b3d4e4 | |
| parent | e2663930518bf15f70c303cf55626faadc98db35 (diff) | |
Move "max to height" roundness logic to Roundable.kt
The sum of top and bottom corner radii should be at max the clipped
height of the roundable view.
This logic was spread out between the ExpandableOutlineView and the
ActivateableNotificationView. This CL moves it to the Roundable.kt.
Bug: b/243302608
Test: post HUNs and observe the appear/disappear animations
Test: see the corners changing as Notifs scroll into the Shelf
Change-Id: I3a615e81f7bfbb9e9f512d0b3ce745c019ea637f
8 files changed, 152 insertions, 7 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt index 212f2c215989..1cf9c1e1f299 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt @@ -3,7 +3,10 @@ package com.android.systemui.statusbar.notification import android.util.FloatProperty import android.view.View import androidx.annotation.FloatRange +import com.android.systemui.Dependency import com.android.systemui.R +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags import com.android.systemui.statusbar.notification.stack.AnimationProperties import com.android.systemui.statusbar.notification.stack.StackStateAnimator import kotlin.math.abs @@ -20,6 +23,8 @@ interface Roundable { /** Properties required for a Roundable */ val roundableState: RoundableState + val clipHeight: Int + /** Current top roundness */ @get:FloatRange(from = 0.0, to = 1.0) @JvmDefault @@ -40,12 +45,16 @@ interface Roundable { /** Current top corner in pixel, based on [topRoundness] and [maxRadius] */ @JvmDefault val topCornerRadius: Float - get() = topRoundness * maxRadius + get() = + if (roundableState.newHeadsUpAnimFlagEnabled) roundableState.topCornerRadius + else topRoundness * maxRadius /** Current bottom corner in pixel, based on [bottomRoundness] and [maxRadius] */ @JvmDefault val bottomCornerRadius: Float - get() = bottomRoundness * maxRadius + get() = + if (roundableState.newHeadsUpAnimFlagEnabled) roundableState.bottomCornerRadius + else bottomRoundness * maxRadius /** Get and update the current radii */ @JvmDefault @@ -320,14 +329,20 @@ interface Roundable { * @param roundable Target of the radius animation * @param maxRadius Max corner radius in pixels */ -class RoundableState( +class RoundableState +@JvmOverloads +constructor( internal val targetView: View, private val roundable: Roundable, maxRadius: Float, + private val featureFlags: FeatureFlags = Dependency.get(FeatureFlags::class.java) ) { internal var maxRadius = maxRadius private set + internal val newHeadsUpAnimFlagEnabled + get() = featureFlags.isEnabled(Flags.IMPROVED_HUN_ANIMATIONS) + /** Animatable for top roundness */ private val topAnimatable = topAnimatable(roundable) @@ -344,6 +359,41 @@ class RoundableState( internal var bottomRoundness = 0f private set + internal val topCornerRadius: Float + get() { + val height = roundable.clipHeight + val topRadius = topRoundness * maxRadius + val bottomRadius = bottomRoundness * maxRadius + + if (height == 0) { + return 0f + } else if (topRadius + bottomRadius > height) { + // The sum of top and bottom corner radii should be at max the clipped height + val overShoot = topRadius + bottomRadius - height + return topRadius - (overShoot * topRoundness / (topRoundness + bottomRoundness)) + } + + return topRadius + } + + internal val bottomCornerRadius: Float + get() { + val height = roundable.clipHeight + val topRadius = topRoundness * maxRadius + val bottomRadius = bottomRoundness * maxRadius + + if (height == 0) { + return 0f + } else if (topRadius + bottomRadius > height) { + // The sum of top and bottom corner radii should be at max the clipped height + val overShoot = topRadius + bottomRadius - height + return bottomRadius - + (overShoot * bottomRoundness / (topRoundness + bottomRoundness)) + } + + return bottomRadius + } + /** Last requested top roundness associated by [SourceType] */ internal val topRoundnessMap = mutableMapOf<SourceType, Float>() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 27510d47b5ab..908c11a1d076 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -566,12 +566,20 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView @Override public float getTopCornerRadius() { + if (isNewHeadsUpAnimFlagEnabled()) { + return super.getTopCornerRadius(); + } + float fraction = getInterpolatedAppearAnimationFraction(); return MathUtils.lerp(0, super.getTopCornerRadius(), fraction); } @Override public float getBottomCornerRadius() { + if (isNewHeadsUpAnimFlagEnabled()) { + return super.getBottomCornerRadius(); + } + float fraction = getInterpolatedAppearAnimationFraction(); return MathUtils.lerp(0, super.getBottomCornerRadius(), fraction); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java index 9aa50e989ff1..7f23c1b89b51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java @@ -28,7 +28,10 @@ import android.util.IndentingPrintWriter; import android.view.View; import android.view.ViewOutlineProvider; +import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.statusbar.notification.RoundableState; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; import com.android.systemui.util.DumpUtilsKt; @@ -47,12 +50,14 @@ public abstract class ExpandableOutlineView extends ExpandableView { private float mOutlineAlpha = -1f; private boolean mAlwaysRoundBothCorners; private Path mTmpPath = new Path(); + private final FeatureFlags mFeatureFlags; /** * {@code false} if the children views of the {@link ExpandableOutlineView} are translated when * it is moved. Otherwise, the translation is set on the {@code ExpandableOutlineView} itself. */ protected boolean mDismissUsingRowTranslationX = true; + private float[] mTmpCornerRadii = new float[8]; private final ViewOutlineProvider mProvider = new ViewOutlineProvider() { @@ -81,6 +86,15 @@ public abstract class ExpandableOutlineView extends ExpandableView { return mRoundableState; } + @Override + public int getClipHeight() { + if (mCustomOutline) { + return mOutlineRect.height(); + } + + return super.getClipHeight(); + } + protected Path getClipPath(boolean ignoreTranslation) { int left; int top; @@ -112,7 +126,7 @@ public abstract class ExpandableOutlineView extends ExpandableView { return EMPTY_PATH; } float bottomRadius = mAlwaysRoundBothCorners ? getMaxRadius() : getBottomCornerRadius(); - if (topRadius + bottomRadius > height) { + if (!isNewHeadsUpAnimFlagEnabled() && (topRadius + bottomRadius > height)) { float overShoot = topRadius + bottomRadius - height; float currentTopRoundness = getTopRoundness(); float currentBottomRoundness = getBottomRoundness(); @@ -153,6 +167,7 @@ public abstract class ExpandableOutlineView extends ExpandableView { super(context, attrs); setOutlineProvider(mProvider); initDimens(); + mFeatureFlags = Dependency.get(FeatureFlags.class); } @Override @@ -360,4 +375,9 @@ public abstract class ExpandableOutlineView extends ExpandableView { } }); } + + // TODO(b/290365128) replace with ViewRefactorFlag + protected boolean isNewHeadsUpAnimFlagEnabled() { + return mFeatureFlags.isEnabled(Flags.IMPROVED_HUN_ANIMATIONS); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index f98624409e56..c4c116ba0613 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -93,6 +93,12 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro return mRoundableState; } + @Override + public int getClipHeight() { + int clipHeight = Math.max(mActualHeight - mClipTopAmount - mClipBottomAmount, 0); + return Math.max(clipHeight, mMinimumHeightForClipping); + } + private void initDimens() { mContentShift = getResources().getDimensionPixelSize( R.dimen.shelf_transform_content_shift); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java index ef5e86f06ef0..87205e2df9c3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java @@ -120,6 +120,11 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper imple } @Override + public int getClipHeight() { + return mView.getHeight(); + } + + @Override public void applyRoundnessAndInvalidate() { if (mRoundnessChangedListener != null) { // We cannot apply the rounded corner to this View, so our parents (in drawChild()) will diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt index 04308b47abc9..a8d8a8e03ed5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt @@ -30,8 +30,8 @@ import com.android.systemui.statusbar.notification.row.ExpandableView */ class MediaContainerView(context: Context, attrs: AttributeSet?) : ExpandableView(context, attrs) { + override var clipHeight = 0 var cornerRadius = 0f - var clipHeight = 0 var clipRect = RectF() var clipPath = Path() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index dad806418f2d..626f851d9d11 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -192,6 +192,11 @@ public class NotificationChildrenContainer extends ViewGroup } @Override + public int getClipHeight() { + return Math.max(mActualHeight - mClipBottomAmount, 0); + } + + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = Math.min(mAttachedChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt index 89faa239c5a2..a56fb2c515a8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt @@ -3,7 +3,11 @@ package com.android.systemui.statusbar.notification import android.view.View import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @@ -15,8 +19,9 @@ import org.mockito.Mockito.verify @SmallTest @RunWith(JUnit4::class) class RoundableTest : SysuiTestCase() { - val targetView: View = mock() - val roundable = FakeRoundable(targetView) + private val targetView: View = mock() + private val featureFlags = FakeFeatureFlags() + private val roundable = FakeRoundable(targetView = targetView, featureFlags = featureFlags) @Test fun defaultConfig_shouldNotHaveRoundedCorner() { @@ -144,16 +149,62 @@ class RoundableTest : SysuiTestCase() { assertEquals(0.2f, roundable.roundableState.bottomRoundness) } + @Test + fun getCornerRadii_radius_maxed_to_height() { + whenever(targetView.height).thenReturn(10) + featureFlags.set(Flags.IMPROVED_HUN_ANIMATIONS, true) + roundable.requestRoundness(1f, 1f, SOURCE1) + + assertCornerRadiiEquals(5f, 5f) + } + + @Test + fun getCornerRadii_topRadius_maxed_to_height() { + whenever(targetView.height).thenReturn(5) + featureFlags.set(Flags.IMPROVED_HUN_ANIMATIONS, true) + roundable.requestRoundness(1f, 0f, SOURCE1) + + assertCornerRadiiEquals(5f, 0f) + } + + @Test + fun getCornerRadii_bottomRadius_maxed_to_height() { + whenever(targetView.height).thenReturn(5) + featureFlags.set(Flags.IMPROVED_HUN_ANIMATIONS, true) + roundable.requestRoundness(0f, 1f, SOURCE1) + + assertCornerRadiiEquals(0f, 5f) + } + + @Test + fun getCornerRadii_radii_kept() { + whenever(targetView.height).thenReturn(100) + featureFlags.set(Flags.IMPROVED_HUN_ANIMATIONS, true) + roundable.requestRoundness(1f, 1f, SOURCE1) + + assertCornerRadiiEquals(MAX_RADIUS, MAX_RADIUS) + } + + private fun assertCornerRadiiEquals(top: Float, bottom: Float) { + assertEquals("topCornerRadius", top, roundable.topCornerRadius) + assertEquals("bottomCornerRadius", bottom, roundable.bottomCornerRadius) + } + class FakeRoundable( targetView: View, radius: Float = MAX_RADIUS, + featureFlags: FeatureFlags ) : Roundable { override val roundableState = RoundableState( targetView = targetView, roundable = this, maxRadius = radius, + featureFlags = featureFlags ) + + override val clipHeight: Int + get() = roundableState.targetView.height } companion object { |