Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt +58 −5 Original line number Diff line number Diff line Loading @@ -16,12 +16,18 @@ package com.android.systemui.statusbar.notification.stack import android.os.VibrationEffect import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper.RunWithLooper import androidx.dynamicanimation.animation.SpringForce import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.haptics.fakeVibratorHelper import com.android.systemui.haptics.msdl.fakeMSDLPlayer import com.android.systemui.haptics.vibratorHelper import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.createRowGroup Loading @@ -46,6 +52,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { private val stackScrollLayout = mock<NotificationStackScrollLayout>() private val sectionsManager = mock<NotificationSectionsManager>() private val msdlPlayer = kosmos.fakeMSDLPlayer private val vibratorHelper = kosmos.fakeVibratorHelper private var canRowBeDismissed = true private var magneticAnimationsCancelled = MutableList(childrenNumber) { false } Loading Loading @@ -235,7 +242,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { underTest.setMagneticRowTranslation(swipedRow, translation = 100f) // WHEN the interaction ends on the row underTest.onMagneticInteractionEnd(swipedRow, velocity = null) underTest.onMagneticInteractionEnd(swipedRow, dismissing = false, velocity = null) // THEN the state resets assertThat(underTest.currentState).isEqualTo(State.IDLE) Loading @@ -248,7 +255,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { setTargets() // WHEN the interaction ends on the row underTest.onMagneticInteractionEnd(swipedRow, velocity = null) underTest.onMagneticInteractionEnd(swipedRow, dismissing = false, velocity = null) // THEN the state resets assertThat(underTest.currentState).isEqualTo(State.IDLE) Loading @@ -261,7 +268,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { setDetachedState() // WHEN the interaction ends on the row underTest.onMagneticInteractionEnd(swipedRow, velocity = null) underTest.onMagneticInteractionEnd(swipedRow, dismissing = false, velocity = null) // THEN the state resets assertThat(underTest.currentState).isEqualTo(State.IDLE) Loading @@ -274,7 +281,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { setDetachedState() // WHEN the interaction ends on the row underTest.onMagneticInteractionEnd(swipedRow, velocity = null) underTest.onMagneticInteractionEnd(swipedRow, dismissing = false, velocity = null) // THEN magnetic animations are cancelled assertThat(magneticAnimationsCancelled[childrenNumber / 2]).isTrue() Loading @@ -290,12 +297,58 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { setTargets() // WHEN the interactionEnd is called on a target different from the swiped row underTest.onMagneticInteractionEnd(neighborRow, null) underTest.onMagneticInteractionEnd(neighborRow, dismissing = false, velocity = null) // THEN magnetic animations are cancelled assertThat(magneticAnimationsCancelled[neighborIndex]).isTrue() } @Test @EnableFlags(Flags.FLAG_MSDL_FEEDBACK) fun onMagneticInteractionEnd_whenPulling_fromDismiss_playsMSDLThresholdHaptics() = kosmos.testScope.runTest { // GIVEN a threshold of 100 px val threshold = 100f underTest.onDensityChange( threshold / MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP ) // GIVEN that targets are set and the swiped row is being pulled setTargets() underTest.setMagneticRowTranslation(swipedRow, translation = 100f) // WHEN the interaction ends on the row because it was dismissed underTest.onMagneticInteractionEnd(swipedRow, dismissing = true, velocity = null) // THEN threshold haptics play to indicate the dismissal assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.SWIPE_THRESHOLD_INDICATOR) } @Test @DisableFlags(Flags.FLAG_MSDL_FEEDBACK) fun onMagneticInteractionEnd_whenPulling_fromDismiss_playsThresholdVibration() = kosmos.testScope.runTest { // GIVEN a threshold of 100 px val threshold = 100f underTest.onDensityChange( threshold / MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP ) // GIVEN that targets are set and the swiped row is being pulled setTargets() underTest.setMagneticRowTranslation(swipedRow, translation = 100f) // WHEN the interaction ends on the row because it was dismissed underTest.onMagneticInteractionEnd(swipedRow, dismissing = true, velocity = null) // THEN threshold haptics play to indicate the dismissal val composition = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.7f) .compose() assertThat(vibratorHelper.hasVibratedWithEffects(composition)).isTrue() } @Test fun onResetRoundness_swipedRoundableGetsCleared() = kosmos.testScope.runTest { Loading packages/SystemUI/src/com/android/systemui/SwipeHelper.java +5 −3 Original line number Diff line number Diff line Loading @@ -464,7 +464,7 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { }; Animator anim = getViewTranslationAnimator(animView, newPos, updateListener); mCallback.onMagneticInteractionEnd(animView, velocity); mCallback.onMagneticInteractionEnd(animView, /* dismissing = */ true, velocity); if (anim == null) { onDismissChildWithAnimationFinished(); return; Loading Loading @@ -754,7 +754,8 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { dismissChild(mTouchedView, velocity, !swipedFastEnough() /* useAccelerateInterpolator */); } else { mCallback.onMagneticInteractionEnd(mTouchedView, velocity); mCallback.onMagneticInteractionEnd(mTouchedView, /* dismissing = */ false, velocity); mCallback.onDragCancelled(mTouchedView); snapChild(mTouchedView, 0 /* leftTarget */, velocity); } Loading Loading @@ -985,9 +986,10 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { * This method should be called when a view will snap back or be dismissed. * * @param view The {@link View} whose magnetic interaction ended. * @param dismissing If the interaction ended with the view being dismissed. * @param velocity The velocity when the interaction ended. */ void onMagneticInteractionEnd(View view, float velocity); void onMagneticInteractionEnd(View view, boolean dismissing, float velocity); /** * Determine if a view managed by magnetic interactions is dismissible when being swiped by Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt +8 −1 Original line number Diff line number Diff line Loading @@ -85,10 +85,16 @@ interface MagneticNotificationRowManager { * after calls to [setMagneticRowTranslation]. * * @param[row] [ExpandableNotificationRow] that stopped whose interaction stopped. * @param[dismissing] If the interaction ended because the row is dismissing. If false, it is * assumed that the row is snapping back instead. * @param[velocity] Optional velocity at the end of the interaction. Use this to trigger * animations with a start velocity. */ fun onMagneticInteractionEnd(row: ExpandableNotificationRow, velocity: Float? = null) fun onMagneticInteractionEnd( row: ExpandableNotificationRow, dismissing: Boolean, velocity: Float? = null, ) /** * Determine if a magnetic row swiped is dismissible according to the end velocity of the swipe. Loading Loading @@ -144,6 +150,7 @@ interface MagneticNotificationRowManager { override fun onMagneticInteractionEnd( row: ExpandableNotificationRow, dismissing: Boolean, velocity: Float?, ) {} Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt +8 −1 Original line number Diff line number Diff line Loading @@ -336,12 +336,19 @@ constructor( detachDirectionEstimator.reset() } override fun onMagneticInteractionEnd(row: ExpandableNotificationRow, velocity: Float?) { override fun onMagneticInteractionEnd( row: ExpandableNotificationRow, dismissing: Boolean, velocity: Float?, ) { detachDirectionEstimator.reset() if (row.isSwipedTarget()) { when (currentState) { State.TARGETS_SET -> currentState = State.IDLE State.PULLING -> { if (dismissing) { playThresholdHaptics() } snapNeighborsBack(velocity) currentState = State.IDLE } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +4 −2 Original line number Diff line number Diff line Loading @@ -503,9 +503,11 @@ public class NotificationStackScrollLayoutController implements Dumpable { } @Override public void onMagneticInteractionEnd(View view, float velocity) { public void onMagneticInteractionEnd(View view, boolean dismissing, float velocity) { if (view instanceof ExpandableNotificationRow row) { mMagneticNotificationRowManager.onMagneticInteractionEnd(row, velocity); mMagneticNotificationRowManager.onMagneticInteractionEnd(row, dismissing, velocity); } } Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt +58 −5 Original line number Diff line number Diff line Loading @@ -16,12 +16,18 @@ package com.android.systemui.statusbar.notification.stack import android.os.VibrationEffect import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper.RunWithLooper import androidx.dynamicanimation.animation.SpringForce import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.haptics.fakeVibratorHelper import com.android.systemui.haptics.msdl.fakeMSDLPlayer import com.android.systemui.haptics.vibratorHelper import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.createRowGroup Loading @@ -46,6 +52,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { private val stackScrollLayout = mock<NotificationStackScrollLayout>() private val sectionsManager = mock<NotificationSectionsManager>() private val msdlPlayer = kosmos.fakeMSDLPlayer private val vibratorHelper = kosmos.fakeVibratorHelper private var canRowBeDismissed = true private var magneticAnimationsCancelled = MutableList(childrenNumber) { false } Loading Loading @@ -235,7 +242,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { underTest.setMagneticRowTranslation(swipedRow, translation = 100f) // WHEN the interaction ends on the row underTest.onMagneticInteractionEnd(swipedRow, velocity = null) underTest.onMagneticInteractionEnd(swipedRow, dismissing = false, velocity = null) // THEN the state resets assertThat(underTest.currentState).isEqualTo(State.IDLE) Loading @@ -248,7 +255,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { setTargets() // WHEN the interaction ends on the row underTest.onMagneticInteractionEnd(swipedRow, velocity = null) underTest.onMagneticInteractionEnd(swipedRow, dismissing = false, velocity = null) // THEN the state resets assertThat(underTest.currentState).isEqualTo(State.IDLE) Loading @@ -261,7 +268,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { setDetachedState() // WHEN the interaction ends on the row underTest.onMagneticInteractionEnd(swipedRow, velocity = null) underTest.onMagneticInteractionEnd(swipedRow, dismissing = false, velocity = null) // THEN the state resets assertThat(underTest.currentState).isEqualTo(State.IDLE) Loading @@ -274,7 +281,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { setDetachedState() // WHEN the interaction ends on the row underTest.onMagneticInteractionEnd(swipedRow, velocity = null) underTest.onMagneticInteractionEnd(swipedRow, dismissing = false, velocity = null) // THEN magnetic animations are cancelled assertThat(magneticAnimationsCancelled[childrenNumber / 2]).isTrue() Loading @@ -290,12 +297,58 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { setTargets() // WHEN the interactionEnd is called on a target different from the swiped row underTest.onMagneticInteractionEnd(neighborRow, null) underTest.onMagneticInteractionEnd(neighborRow, dismissing = false, velocity = null) // THEN magnetic animations are cancelled assertThat(magneticAnimationsCancelled[neighborIndex]).isTrue() } @Test @EnableFlags(Flags.FLAG_MSDL_FEEDBACK) fun onMagneticInteractionEnd_whenPulling_fromDismiss_playsMSDLThresholdHaptics() = kosmos.testScope.runTest { // GIVEN a threshold of 100 px val threshold = 100f underTest.onDensityChange( threshold / MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP ) // GIVEN that targets are set and the swiped row is being pulled setTargets() underTest.setMagneticRowTranslation(swipedRow, translation = 100f) // WHEN the interaction ends on the row because it was dismissed underTest.onMagneticInteractionEnd(swipedRow, dismissing = true, velocity = null) // THEN threshold haptics play to indicate the dismissal assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.SWIPE_THRESHOLD_INDICATOR) } @Test @DisableFlags(Flags.FLAG_MSDL_FEEDBACK) fun onMagneticInteractionEnd_whenPulling_fromDismiss_playsThresholdVibration() = kosmos.testScope.runTest { // GIVEN a threshold of 100 px val threshold = 100f underTest.onDensityChange( threshold / MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP ) // GIVEN that targets are set and the swiped row is being pulled setTargets() underTest.setMagneticRowTranslation(swipedRow, translation = 100f) // WHEN the interaction ends on the row because it was dismissed underTest.onMagneticInteractionEnd(swipedRow, dismissing = true, velocity = null) // THEN threshold haptics play to indicate the dismissal val composition = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.7f) .compose() assertThat(vibratorHelper.hasVibratedWithEffects(composition)).isTrue() } @Test fun onResetRoundness_swipedRoundableGetsCleared() = kosmos.testScope.runTest { Loading
packages/SystemUI/src/com/android/systemui/SwipeHelper.java +5 −3 Original line number Diff line number Diff line Loading @@ -464,7 +464,7 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { }; Animator anim = getViewTranslationAnimator(animView, newPos, updateListener); mCallback.onMagneticInteractionEnd(animView, velocity); mCallback.onMagneticInteractionEnd(animView, /* dismissing = */ true, velocity); if (anim == null) { onDismissChildWithAnimationFinished(); return; Loading Loading @@ -754,7 +754,8 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { dismissChild(mTouchedView, velocity, !swipedFastEnough() /* useAccelerateInterpolator */); } else { mCallback.onMagneticInteractionEnd(mTouchedView, velocity); mCallback.onMagneticInteractionEnd(mTouchedView, /* dismissing = */ false, velocity); mCallback.onDragCancelled(mTouchedView); snapChild(mTouchedView, 0 /* leftTarget */, velocity); } Loading Loading @@ -985,9 +986,10 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { * This method should be called when a view will snap back or be dismissed. * * @param view The {@link View} whose magnetic interaction ended. * @param dismissing If the interaction ended with the view being dismissed. * @param velocity The velocity when the interaction ended. */ void onMagneticInteractionEnd(View view, float velocity); void onMagneticInteractionEnd(View view, boolean dismissing, float velocity); /** * Determine if a view managed by magnetic interactions is dismissible when being swiped by Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt +8 −1 Original line number Diff line number Diff line Loading @@ -85,10 +85,16 @@ interface MagneticNotificationRowManager { * after calls to [setMagneticRowTranslation]. * * @param[row] [ExpandableNotificationRow] that stopped whose interaction stopped. * @param[dismissing] If the interaction ended because the row is dismissing. If false, it is * assumed that the row is snapping back instead. * @param[velocity] Optional velocity at the end of the interaction. Use this to trigger * animations with a start velocity. */ fun onMagneticInteractionEnd(row: ExpandableNotificationRow, velocity: Float? = null) fun onMagneticInteractionEnd( row: ExpandableNotificationRow, dismissing: Boolean, velocity: Float? = null, ) /** * Determine if a magnetic row swiped is dismissible according to the end velocity of the swipe. Loading Loading @@ -144,6 +150,7 @@ interface MagneticNotificationRowManager { override fun onMagneticInteractionEnd( row: ExpandableNotificationRow, dismissing: Boolean, velocity: Float?, ) {} Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt +8 −1 Original line number Diff line number Diff line Loading @@ -336,12 +336,19 @@ constructor( detachDirectionEstimator.reset() } override fun onMagneticInteractionEnd(row: ExpandableNotificationRow, velocity: Float?) { override fun onMagneticInteractionEnd( row: ExpandableNotificationRow, dismissing: Boolean, velocity: Float?, ) { detachDirectionEstimator.reset() if (row.isSwipedTarget()) { when (currentState) { State.TARGETS_SET -> currentState = State.IDLE State.PULLING -> { if (dismissing) { playThresholdHaptics() } snapNeighborsBack(velocity) currentState = State.IDLE } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +4 −2 Original line number Diff line number Diff line Loading @@ -503,9 +503,11 @@ public class NotificationStackScrollLayoutController implements Dumpable { } @Override public void onMagneticInteractionEnd(View view, float velocity) { public void onMagneticInteractionEnd(View view, boolean dismissing, float velocity) { if (view instanceof ExpandableNotificationRow row) { mMagneticNotificationRowManager.onMagneticInteractionEnd(row, velocity); mMagneticNotificationRowManager.onMagneticInteractionEnd(row, dismissing, velocity); } } Loading