diff options
2 files changed, 137 insertions, 14 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 734bc48093b2..0d604014e8f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -326,9 +326,9 @@ public class NotificationShelf extends ActivatableNotificationView implements || child.isPinned(); boolean isLastChild = child == lastChild; final float viewStart = child.getTranslationY(); - - final float inShelfAmount = updateShelfTransformation(i, child, scrollingFast, - expandingAnimated, isLastChild); + final float shelfClipStart = getTranslationY() - mPaddingBetweenElements; + final float inShelfAmount = getAmountInShelf(i, child, scrollingFast, + expandingAnimated, isLastChild, shelfClipStart); // TODO(b/172289889) scale mPaddingBetweenElements with expansion amount if ((isLastChild && !child.isInShelf()) || aboveShelf || backgroundForceHidden) { @@ -609,10 +609,18 @@ public class NotificationShelf extends ActivatableNotificationView implements } /** - * @return the amount how much this notification is in the shelf + * @param i Index of the view in the host layout. + * @param view The current ExpandableView. + * @param scrollingFast Whether we are scrolling fast. + * @param expandingAnimated Whether we are expanding a notification. + * @param isLastChild Whether this is the last view. + * @param shelfClipStart The point at which notifications start getting clipped by the shelf. + * @return The amount how much this notification is in the shelf. + * 0f is not in shelf. 1f is completely in shelf. */ - private float updateShelfTransformation(int i, ExpandableView view, boolean scrollingFast, - boolean expandingAnimated, boolean isLastChild) { + @VisibleForTesting + public float getAmountInShelf(int i, ExpandableView view, boolean scrollingFast, + boolean expandingAnimated, boolean isLastChild, float shelfClipStart) { // Let's calculate how much the view is in the shelf float viewStart = view.getTranslationY(); @@ -635,29 +643,33 @@ public class NotificationShelf extends ActivatableNotificationView implements float viewEnd = viewStart + fullHeight; float fullTransitionAmount = 0.0f; float iconTransitionAmount = 0.0f; - float shelfStart = getTranslationY() - mPaddingBetweenElements; + + // Don't animate shelf icons during shade expansion. if (mAmbientState.isExpansionChanging() && !mAmbientState.isOnKeyguard()) { // TODO(b/172289889) handle icon placement for notification that is clipped by the shelf if (mIndexOfFirstViewInShelf != -1 && i >= mIndexOfFirstViewInShelf) { fullTransitionAmount = 1f; iconTransitionAmount = 1f; } - } else if (viewEnd >= shelfStart + + } else if (viewEnd >= shelfClipStart && (!mAmbientState.isUnlockHintRunning() || view.isInShelf()) && (mAmbientState.isShadeExpanded() || (!view.isPinned() && !view.isHeadsUpAnimatingAway()))) { - if (viewStart < shelfStart) { - float fullAmount = (shelfStart - viewStart) / fullHeight; + if (viewStart < shelfClipStart && Math.abs(viewStart - shelfClipStart) > 0.001f) { + // Partially clipped by shelf. + float fullAmount = (shelfClipStart - viewStart) / fullHeight; fullAmount = Math.min(1.0f, fullAmount); fullTransitionAmount = 1.0f - fullAmount; if (isLastChild) { // Reduce icon transform distance to completely fade in shelf icon // by the time the notification icon fades out, and vice versa - iconTransitionAmount = (shelfStart - viewStart) + iconTransitionAmount = (shelfClipStart - viewStart) / (iconTransformStart - viewStart); } else { - iconTransitionAmount = (shelfStart - iconTransformStart) / transformDistance; + iconTransitionAmount = (shelfClipStart - iconTransformStart) + / transformDistance; } iconTransitionAmount = MathUtils.constrain(iconTransitionAmount, 0.0f, 1.0f); iconTransitionAmount = 1.0f - iconTransitionAmount; @@ -772,6 +784,9 @@ public class NotificationShelf extends ActivatableNotificationView implements } private NotificationIconContainer.IconState getIconState(StatusBarIconView icon) { + if (mShelfIcons == null) { + return null; + } return mShelfIcons.getIconState(icon); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt index 4270d72770dc..3f190367f284 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt @@ -5,8 +5,9 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.NotificationShelf -import junit.framework.Assert.assertFalse -import junit.framework.Assert.assertTrue +import com.android.systemui.statusbar.StatusBarIconView +import com.android.systemui.statusbar.notification.row.ExpandableView +import junit.framework.Assert.* import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -143,6 +144,113 @@ class NotificationShelfTest : SysuiTestCase() { assertFalse(isYBelowShelfInView) } + @Test + fun getAmountInShelf_lastViewBelowShelf_completelyInShelf() { + val shelfClipStart = 0f + val viewStart = 1f + + val expandableView = mock(ExpandableView::class.java) + whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java)) + whenever(expandableView.translationY).thenReturn(viewStart) + whenever(expandableView.actualHeight).thenReturn(20) + + whenever(expandableView.minHeight).thenReturn(20) + whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY + whenever(expandableView.isInShelf).thenReturn(true) + + whenever(ambientState.isOnKeyguard).thenReturn(true) + whenever(ambientState.isExpansionChanging).thenReturn(false) + whenever(ambientState.isShadeExpanded).thenReturn(true) + + val amountInShelf = shelf.getAmountInShelf(/* i= */ 0, + /* view= */ expandableView, + /* scrollingFast= */ false, + /* expandingAnimated= */ false, + /* isLastChild= */ true, + shelfClipStart) + assertEquals(1f, amountInShelf) + } + + @Test + fun getAmountInShelf_lastViewAlmostBelowShelf_completelyInShelf() { + val viewStart = 0f + val shelfClipStart = 0.001f + + val expandableView = mock(ExpandableView::class.java) + whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java)) + whenever(expandableView.translationY).thenReturn(viewStart) + whenever(expandableView.actualHeight).thenReturn(20) + + whenever(expandableView.minHeight).thenReturn(20) + whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY + whenever(expandableView.isInShelf).thenReturn(true) + + whenever(ambientState.isOnKeyguard).thenReturn(true) + whenever(ambientState.isExpansionChanging).thenReturn(false) + whenever(ambientState.isShadeExpanded).thenReturn(true) + + val amountInShelf = shelf.getAmountInShelf(/* i= */ 0, + /* view= */ expandableView, + /* scrollingFast= */ false, + /* expandingAnimated= */ false, + /* isLastChild= */ true, + shelfClipStart) + assertEquals(1f, amountInShelf) + } + + @Test + fun getAmountInShelf_lastViewHalfClippedByShelf_halfInShelf() { + val viewStart = 0f + val shelfClipStart = 10f + + val expandableView = mock(ExpandableView::class.java) + whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java)) + whenever(expandableView.translationY).thenReturn(viewStart) + whenever(expandableView.actualHeight).thenReturn(25) + + whenever(expandableView.minHeight).thenReturn(25) + whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY + whenever(expandableView.isInShelf).thenReturn(true) + + whenever(ambientState.isOnKeyguard).thenReturn(true) + whenever(ambientState.isExpansionChanging).thenReturn(false) + whenever(ambientState.isShadeExpanded).thenReturn(true) + + val amountInShelf = shelf.getAmountInShelf(/* i= */ 0, + /* view= */ expandableView, + /* scrollingFast= */ false, + /* expandingAnimated= */ false, + /* isLastChild= */ true, + shelfClipStart) + assertEquals(0.5f, amountInShelf) + } + + @Test + fun getAmountInShelf_lastViewAboveShelf_notInShelf() { + val viewStart = 0f + val shelfClipStart = 15f + + val expandableView = mock(ExpandableView::class.java) + whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java)) + whenever(expandableView.translationY).thenReturn(viewStart) + whenever(expandableView.actualHeight).thenReturn(10) + + whenever(expandableView.minHeight).thenReturn(10) + whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY + whenever(expandableView.isInShelf).thenReturn(false) + + whenever(ambientState.isExpansionChanging).thenReturn(false) + whenever(ambientState.isOnKeyguard).thenReturn(true) + + val amountInShelf = shelf.getAmountInShelf(/* i= */ 0, + /* view= */ expandableView, + /* scrollingFast= */ false, + /* expandingAnimated= */ false, + /* isLastChild= */ true, + shelfClipStart) + assertEquals(0f, amountInShelf) + } + private fun setFractionToShade(fraction: Float) { whenever(ambientState.fractionToShade).thenReturn(fraction) } |