summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt141
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt18
7 files changed, 249 insertions, 96 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt
index 739636e01f0b..d14ff35f824a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.stack
import android.os.testableLooper
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.SysuiTestCase
@@ -46,13 +47,14 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
private val childrenNumber = 5
private val stackScrollLayout = mock<NotificationStackScrollLayout>()
private val sectionsManager = mock<NotificationSectionsManager>()
- private val swipedMultiplier = 0.5f
private val msdlPlayer = kosmos.fakeMSDLPlayer
+ private var canRowBeDismissed = true
private val underTest = kosmos.magneticNotificationRowManagerImpl
private lateinit var notificationTestHelper: NotificationTestHelper
private lateinit var children: NotificationChildrenContainer
+ private lateinit var swipedRow: ExpandableNotificationRow
@Before
fun setUp() {
@@ -60,14 +62,15 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
notificationTestHelper =
NotificationTestHelper(mContext, mDependency, kosmos.testableLooper, featureFlags)
children = notificationTestHelper.createGroup(childrenNumber).childrenContainer
+ swipedRow = children.attachedChildren[childrenNumber / 2]
+ configureMagneticRowListener(swipedRow)
}
@Test
fun setMagneticAndRoundableTargets_onIdle_targetsGetSet() =
kosmos.testScope.runTest {
// WHEN the targets are set for a row
- val row = children.attachedChildren[childrenNumber / 2]
- setTargetsForRow(row)
+ setTargets()
// THEN the magnetic and roundable targets are defined and the state is TARGETS_SET
assertThat(underTest.currentState).isEqualTo(State.TARGETS_SET)
@@ -79,11 +82,10 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
fun setMagneticRowTranslation_whenTargetsAreSet_startsPulling() =
kosmos.testScope.runTest {
// GIVEN targets are set
- val row = children.attachedChildren[childrenNumber / 2]
- setTargetsForRow(row)
+ setTargets()
// WHEN setting a translation for the swiped row
- underTest.setMagneticRowTranslation(row, translation = 100f)
+ underTest.setMagneticRowTranslation(swipedRow, translation = 100f)
// THEN the state moves to PULLING
assertThat(underTest.currentState).isEqualTo(State.PULLING)
@@ -107,8 +109,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
fun setMagneticRowTranslation_whenRowIsNotSwiped_doesNotSetMagneticTranslation() =
kosmos.testScope.runTest {
// GIVEN that targets are set
- val row = children.attachedChildren[childrenNumber / 2]
- setTargetsForRow(row)
+ setTargets()
// WHEN setting a translation for a row that is not being swiped
val differentRow = children.attachedChildren[childrenNumber / 2 - 1]
@@ -120,41 +121,61 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
}
@Test
- fun setMagneticRowTranslation_belowThreshold_whilePulling_setsMagneticTranslations() =
+ fun setMagneticRowTranslation_whenDismissible_belowThreshold_whenPulling_setsTranslations() =
kosmos.testScope.runTest {
// GIVEN a threshold of 100 px
val threshold = 100f
underTest.setSwipeThresholdPx(threshold)
// GIVEN that targets are set and the rows are being pulled
- val row = children.attachedChildren[childrenNumber / 2]
- setTargetsForRow(row)
- underTest.setMagneticRowTranslation(row, translation = 100f)
+ setTargets()
+ underTest.setMagneticRowTranslation(swipedRow, translation = 100f)
// WHEN setting a translation that will fall below the threshold
- val translation = threshold / swipedMultiplier - 50f
- underTest.setMagneticRowTranslation(row, translation)
+ val translation = threshold / underTest.swipedRowMultiplier - 50f
+ underTest.setMagneticRowTranslation(swipedRow, translation)
// THEN the targets continue to be pulled and translations are set
assertThat(underTest.currentState).isEqualTo(State.PULLING)
- assertThat(row.translation).isEqualTo(swipedMultiplier * translation)
+ assertThat(swipedRow.translation).isEqualTo(underTest.swipedRowMultiplier * translation)
}
@Test
- fun setMagneticRowTranslation_aboveThreshold_whilePulling_detachesMagneticTargets() =
+ fun setMagneticRowTranslation_whenNotDismissible_belowThreshold_whenPulling_setsTranslations() =
kosmos.testScope.runTest {
// GIVEN a threshold of 100 px
val threshold = 100f
underTest.setSwipeThresholdPx(threshold)
// GIVEN that targets are set and the rows are being pulled
- val row = children.attachedChildren[childrenNumber / 2]
- setTargetsForRow(row)
- underTest.setMagneticRowTranslation(row, translation = 100f)
+ canRowBeDismissed = false
+ setTargets()
+ underTest.setMagneticRowTranslation(swipedRow, translation = 100f)
+
+ // WHEN setting a translation that will fall below the threshold
+ val translation = threshold / underTest.swipedRowMultiplier - 50f
+ underTest.setMagneticRowTranslation(swipedRow, translation)
+
+ // THEN the targets continue to be pulled and reduced translations are set
+ val expectedTranslation = getReducedTranslation(translation)
+ assertThat(underTest.currentState).isEqualTo(State.PULLING)
+ assertThat(swipedRow.translation).isEqualTo(expectedTranslation)
+ }
+
+ @Test
+ fun setMagneticRowTranslation_whenDismissible_aboveThreshold_whilePulling_detaches() =
+ kosmos.testScope.runTest {
+ // GIVEN a threshold of 100 px
+ val threshold = 100f
+ underTest.setSwipeThresholdPx(threshold)
+
+ // GIVEN that targets are set and the rows are being pulled
+ setTargets()
+ underTest.setMagneticRowTranslation(swipedRow, translation = 100f)
// WHEN setting a translation that will fall above the threshold
- val translation = threshold / swipedMultiplier + 50f
- underTest.setMagneticRowTranslation(row, translation)
+ val translation = threshold / underTest.swipedRowMultiplier + 50f
+ underTest.setMagneticRowTranslation(swipedRow, translation)
// THEN the swiped view detaches and the correct detach haptics play
assertThat(underTest.currentState).isEqualTo(State.DETACHED)
@@ -162,15 +183,36 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
}
@Test
+ fun setMagneticRowTranslation_whenNotDismissible_aboveThreshold_whilePulling_doesNotDetach() =
+ kosmos.testScope.runTest {
+ // GIVEN a threshold of 100 px
+ val threshold = 100f
+ underTest.setSwipeThresholdPx(threshold)
+
+ // GIVEN that targets are set and the rows are being pulled
+ canRowBeDismissed = false
+ setTargets()
+ underTest.setMagneticRowTranslation(swipedRow, translation = 100f)
+
+ // WHEN setting a translation that will fall above the threshold
+ val translation = threshold / underTest.swipedRowMultiplier + 50f
+ underTest.setMagneticRowTranslation(swipedRow, translation)
+
+ // THEN the swiped view does not detach and the reduced translation is set
+ val expectedTranslation = getReducedTranslation(translation)
+ assertThat(underTest.currentState).isEqualTo(State.PULLING)
+ assertThat(swipedRow.translation).isEqualTo(expectedTranslation)
+ }
+
+ @Test
fun setMagneticRowTranslation_whileDetached_setsTranslationAndStaysDetached() =
kosmos.testScope.runTest {
// GIVEN that the swiped view has been detached
- val row = children.attachedChildren[childrenNumber / 2]
- setDetachedState(row)
+ setDetachedState()
// WHEN setting a new translation
val translation = 300f
- underTest.setMagneticRowTranslation(row, translation)
+ underTest.setMagneticRowTranslation(swipedRow, translation)
// THEN the swiped view continues to be detached
assertThat(underTest.currentState).isEqualTo(State.DETACHED)
@@ -180,14 +222,13 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
fun onMagneticInteractionEnd_whilePulling_goesToIdle() =
kosmos.testScope.runTest {
// GIVEN targets are set
- val row = children.attachedChildren[childrenNumber / 2]
- setTargetsForRow(row)
+ setTargets()
// WHEN setting a translation for the swiped row
- underTest.setMagneticRowTranslation(row, translation = 100f)
+ underTest.setMagneticRowTranslation(swipedRow, translation = 100f)
// WHEN the interaction ends on the row
- underTest.onMagneticInteractionEnd(row, velocity = null)
+ underTest.onMagneticInteractionEnd(swipedRow, velocity = null)
// THEN the state resets
assertThat(underTest.currentState).isEqualTo(State.IDLE)
@@ -197,32 +238,56 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
fun onMagneticInteractionEnd_whileDetached_goesToIdle() =
kosmos.testScope.runTest {
// GIVEN the swiped row is detached
- val row = children.attachedChildren[childrenNumber / 2]
- setDetachedState(row)
+ setDetachedState()
// WHEN the interaction ends on the row
- underTest.onMagneticInteractionEnd(row, velocity = null)
+ underTest.onMagneticInteractionEnd(swipedRow, velocity = null)
// THEN the state resets
assertThat(underTest.currentState).isEqualTo(State.IDLE)
}
- private fun setDetachedState(row: ExpandableNotificationRow) {
+ private fun setDetachedState() {
val threshold = 100f
underTest.setSwipeThresholdPx(threshold)
// Set the pulling state
- setTargetsForRow(row)
- underTest.setMagneticRowTranslation(row, translation = 100f)
+ setTargets()
+ underTest.setMagneticRowTranslation(swipedRow, translation = 100f)
// Set a translation that will fall above the threshold
- val translation = threshold / swipedMultiplier + 50f
- underTest.setMagneticRowTranslation(row, translation)
+ val translation = threshold / underTest.swipedRowMultiplier + 50f
+ underTest.setMagneticRowTranslation(swipedRow, translation)
assertThat(underTest.currentState).isEqualTo(State.DETACHED)
}
- private fun setTargetsForRow(row: ExpandableNotificationRow) {
- underTest.setMagneticAndRoundableTargets(row, stackScrollLayout, sectionsManager)
+ private fun setTargets() {
+ underTest.setMagneticAndRoundableTargets(swipedRow, stackScrollLayout, sectionsManager)
+ }
+
+ private fun getReducedTranslation(originalTranslation: Float) =
+ underTest.swipedRowMultiplier *
+ originalTranslation *
+ MagneticNotificationRowManagerImpl.MAGNETIC_REDUCTION
+
+ private fun configureMagneticRowListener(row: ExpandableNotificationRow) {
+ val listener =
+ object : MagneticRowListener {
+ override fun setMagneticTranslation(translation: Float) {
+ row.translation = translation
+ }
+
+ override fun triggerMagneticForce(
+ endTranslation: Float,
+ springForce: SpringForce,
+ startVelocity: Float,
+ ) {}
+
+ override fun cancelMagneticAnimations() {}
+
+ override fun canRowBeDismissed(): Boolean = canRowBeDismissed
+ }
+ row.magneticRowListener = listener
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index aa7665a5b630..15f316800000 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -71,7 +71,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
@@ -361,39 +360,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
};
- private final SpringAnimation mMagneticAnimator = new SpringAnimation(
- this, FloatPropertyCompat.createFloatPropertyCompat(TRANSLATE_CONTENT));
-
- private final MagneticRowListener mMagneticRowListener = new MagneticRowListener() {
-
- @Override
- public void setMagneticTranslation(float translation) {
- if (mMagneticAnimator.isRunning()) {
- mMagneticAnimator.animateToFinalPosition(translation);
- } else {
- setTranslation(translation);
- }
- }
-
- @Override
- public void triggerMagneticForce(float endTranslation, @NonNull SpringForce springForce,
- float startVelocity) {
- cancelMagneticAnimations();
- mMagneticAnimator.setSpring(springForce);
- mMagneticAnimator.setStartVelocity(startVelocity);
- mMagneticAnimator.animateToFinalPosition(endTranslation);
- }
-
- @Override
- public void cancelMagneticAnimations() {
- cancelSnapBackAnimation();
- cancelTranslateAnimation();
- mMagneticAnimator.cancel();
- }
- };
+ @Override
+ protected void cancelTranslationAnimations() {
+ cancelSnapBackAnimation();
+ cancelTranslateAnimation();
+ }
private void cancelSnapBackAnimation() {
- PhysicsAnimator<ExpandableNotificationRow> animator =
+ PhysicsAnimator<ExpandableView> animator =
PhysicsAnimator.getInstanceIfExists(this /* target */);
if (animator != null) {
animator.cancel();
@@ -2044,6 +2018,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
new NotificationInlineImageCache());
float radius = getResources().getDimension(R.dimen.notification_corner_radius_small);
mSmallRoundness = radius / getMaxRadius();
+ mMagneticAnimator = new SpringAnimation(
+ this, FloatPropertyCompat.createFloatPropertyCompat(TRANSLATE_CONTENT));
initDimens();
}
@@ -3300,6 +3276,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
/**
+ * For the case of an {@link ExpandableNotificationRow}, the dismissibility of the row considers
+ * the exposure of guts, the state of the notification entry, and if the view itself is allowed
+ * to be dismissed.
+ */
+ @Override
+ public boolean canExpandableViewBeDismissed() {
+ if (areGutsExposed() || !mEntry.hasFinishedInitialization()) {
+ return false;
+ }
+ return canViewBeDismissed();
+ }
+
+ /**
* @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
* otherwise some state might not be updated.
*/
@@ -4067,6 +4056,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mLayouts = new NotificationContentView[]{mPrivateLayout, mPublicLayout};
}
+ @VisibleForTesting
+ public void setMagneticRowListener(MagneticRowListener listener) {
+ mMagneticRowListener = listener;
+ }
+
/**
* Equivalent to View.OnLongClickListener with coordinates
*/
@@ -4317,8 +4311,4 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
mLogger.logRemoveTransientRow(row.getEntry(), getEntry());
}
-
- public MagneticRowListener getMagneticRowListener() {
- return mMagneticRowListener;
- }
}
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 f83a1d9b7833..76ba7f9ea901 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
@@ -33,6 +33,9 @@ import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
@@ -42,6 +45,7 @@ import com.android.systemui.statusbar.notification.Roundable;
import com.android.systemui.statusbar.notification.RoundableState;
import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
+import com.android.systemui.statusbar.notification.stack.MagneticRowListener;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.util.Compile;
import com.android.systemui.util.DumpUtilsKt;
@@ -85,6 +89,55 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro
protected boolean mLastInSection;
protected boolean mFirstInSection;
+ protected SpringAnimation mMagneticAnimator = new SpringAnimation(
+ this /* object */, DynamicAnimation.TRANSLATION_X);
+
+ protected MagneticRowListener mMagneticRowListener = new MagneticRowListener() {
+
+ @Override
+ public void setMagneticTranslation(float translation) {
+ if (mMagneticAnimator.isRunning()) {
+ mMagneticAnimator.animateToFinalPosition(translation);
+ } else {
+ setTranslation(translation);
+ }
+ }
+
+ @Override
+ public void triggerMagneticForce(float endTranslation, @NonNull SpringForce springForce,
+ float startVelocity) {
+ cancelMagneticAnimations();
+ mMagneticAnimator.setSpring(springForce);
+ mMagneticAnimator.setStartVelocity(startVelocity);
+ mMagneticAnimator.animateToFinalPosition(endTranslation);
+ }
+
+ @Override
+ public void cancelMagneticAnimations() {
+ cancelTranslationAnimations();
+ mMagneticAnimator.cancel();
+ }
+
+ @Override
+ public boolean canRowBeDismissed() {
+ return canExpandableViewBeDismissed();
+ }
+ };
+
+ /**
+ * @return true if the ExpandableView can be dismissed. False otherwise.
+ */
+ public boolean canExpandableViewBeDismissed() {
+ return false;
+ }
+
+ /** Cancel any trailing animations on the translation of the view */
+ protected void cancelTranslationAnimations(){}
+
+ public MagneticRowListener getMagneticRowListener() {
+ return mMagneticRowListener;
+ }
+
public ExpandableView(Context context, AttributeSet attrs) {
super(context, attrs);
mViewState = createExpandableViewState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
index 61aaf4998e87..3941700496f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
@@ -57,7 +57,7 @@ constructor(
SpringForce().setStiffness(SNAP_BACK_STIFFNESS).setDampingRatio(SNAP_BACK_DAMPING_RATIO)
// Multiplier applied to the translation of a row while swiped
- private val swipedRowMultiplier =
+ val swipedRowMultiplier =
MAGNETIC_TRANSLATION_MULTIPLIERS[MAGNETIC_TRANSLATION_MULTIPLIERS.size / 2]
override fun setSwipeThresholdPx(thresholdPx: Float) {
@@ -111,24 +111,22 @@ constructor(
): Boolean {
if (!row.isSwipedTarget()) return false
+ val canTargetBeDismissed =
+ currentMagneticListeners.swipedListener()?.canRowBeDismissed() ?: false
when (currentState) {
State.IDLE -> {
logger.logMagneticRowTranslationNotSet(currentState, row.entry)
return false
}
State.TARGETS_SET -> {
- pullTargets(translation)
+ pullTargets(translation, canTargetBeDismissed)
currentState = State.PULLING
}
State.PULLING -> {
- val targetTranslation = swipedRowMultiplier * translation
- val crossedThreshold = abs(targetTranslation) >= magneticDetachThreshold
- if (crossedThreshold) {
- snapNeighborsBack()
- currentMagneticListeners.swipedListener()?.let { detach(it, translation) }
- currentState = State.DETACHED
+ if (canTargetBeDismissed) {
+ pullDismissibleRow(translation)
} else {
- pullTargets(translation)
+ pullTargets(translation, canSwipedBeDismissed = false)
}
}
State.DETACHED -> {
@@ -139,23 +137,49 @@ constructor(
return true
}
- private fun pullTargets(translation: Float) {
+ private fun pullDismissibleRow(translation: Float) {
+ val targetTranslation = swipedRowMultiplier * translation
+ val crossedThreshold = abs(targetTranslation) >= magneticDetachThreshold
+ if (crossedThreshold) {
+ snapNeighborsBack()
+ currentMagneticListeners.swipedListener()?.let { detach(it, translation) }
+ currentState = State.DETACHED
+ } else {
+ pullTargets(translation, canSwipedBeDismissed = true)
+ }
+ }
+
+ private fun pullTargets(translation: Float, canSwipedBeDismissed: Boolean) {
var targetTranslation: Float
currentMagneticListeners.forEachIndexed { i, listener ->
- targetTranslation = MAGNETIC_TRANSLATION_MULTIPLIERS[i] * translation
- listener?.setMagneticTranslation(targetTranslation)
+ listener?.let {
+ if (!canSwipedBeDismissed || !it.canRowBeDismissed()) {
+ // Use a reduced translation if the target swiped can't be dismissed or if the
+ // target itself can't be dismissed
+ targetTranslation =
+ MAGNETIC_TRANSLATION_MULTIPLIERS[i] * translation * MAGNETIC_REDUCTION
+ } else {
+ targetTranslation = MAGNETIC_TRANSLATION_MULTIPLIERS[i] * translation
+ }
+ it.setMagneticTranslation(targetTranslation)
+ }
}
- playPullHaptics(mappedTranslation = swipedRowMultiplier * translation)
+ playPullHaptics(mappedTranslation = swipedRowMultiplier * translation, canSwipedBeDismissed)
}
- private fun playPullHaptics(mappedTranslation: Float) {
+ private fun playPullHaptics(mappedTranslation: Float, canSwipedBeDismissed: Boolean) {
val normalizedTranslation = abs(mappedTranslation) / magneticDetachThreshold
- val vibrationScale =
- (normalizedTranslation * MAX_VIBRATION_SCALE).pow(VIBRATION_PERCEPTION_EXPONENT)
+ val scaleFactor =
+ if (canSwipedBeDismissed) {
+ WEAK_VIBRATION_SCALE
+ } else {
+ STRONG_VIBRATION_SCALE
+ }
+ val vibrationScale = scaleFactor * normalizedTranslation
msdlPlayer.playToken(
MSDLToken.DRAG_INDICATOR_CONTINUOUS,
InteractionProperties.DynamicVibrationScale(
- scale = vibrationScale,
+ scale = vibrationScale.pow(VIBRATION_PERCEPTION_EXPONENT),
vibrationAttributes = VIBRATION_ATTRIBUTES_PIPELINING,
),
)
@@ -233,6 +257,8 @@ constructor(
*/
private val MAGNETIC_TRANSLATION_MULTIPLIERS = listOf(0.18f, 0.28f, 0.5f, 0.28f, 0.18f)
+ const val MAGNETIC_REDUCTION = 0.65f
+
/** Spring parameters for physics animators */
private const val DETACH_STIFFNESS = 800f
private const val DETACH_DAMPING_RATIO = 0.95f
@@ -244,7 +270,8 @@ constructor(
.setUsage(VibrationAttributes.USAGE_TOUCH)
.setFlags(VibrationAttributes.FLAG_PIPELINED_EFFECT)
.build()
- private const val MAX_VIBRATION_SCALE = 0.2f
private const val VIBRATION_PERCEPTION_EXPONENT = 1 / 0.89f
+ private const val WEAK_VIBRATION_SCALE = 0.2f
+ private const val STRONG_VIBRATION_SCALE = 0.45f
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt
index 8a1adfe95392..46036d4c1fad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt
@@ -41,4 +41,7 @@ interface MagneticRowListener {
/** Cancel any animations related to the magnetic interactions of the row */
fun cancelMagneticAnimations()
+
+ /** Can the row be dismissed. */
+ fun canRowBeDismissed(): Boolean
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ce1fc97cbffe..d6b34b068cc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -6609,10 +6609,7 @@ public class NotificationStackScrollLayout
static boolean canChildBeDismissed(View v) {
if (v instanceof ExpandableNotificationRow row) {
- if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) {
- return false;
- }
- return row.canViewBeDismissed();
+ return row.canExpandableViewBeDismissed();
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
index 74e8b8ef29c2..b69b936ea9f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
@@ -3,7 +3,9 @@ package com.android.systemui.statusbar.notification.stack
import androidx.core.view.children
import androidx.core.view.isVisible
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.notification.Roundable
+import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import javax.inject.Inject
@@ -129,6 +131,10 @@ class NotificationTargetsHelper @Inject constructor() {
magneticTargets[leftIndex] = leftElement.magneticRowListener
leftIndex--
} else {
+ if (leftElement.isValidMagneticBoundary()) {
+ // Add the boundary and then stop the iterating
+ magneticTargets[leftIndex] = leftElement?.magneticRowListener
+ }
canMoveLeft = false
}
}
@@ -138,12 +144,24 @@ class NotificationTargetsHelper @Inject constructor() {
magneticTargets[rightIndex] = rightElement.magneticRowListener
rightIndex++
} else {
+ if (rightElement.isValidMagneticBoundary()) {
+ // Add the boundary and then stop the iterating
+ magneticTargets[rightIndex] = rightElement?.magneticRowListener
+ }
canMoveRight = false
}
}
}
return magneticTargets
}
+
+ private fun ExpandableView?.isValidMagneticBoundary(): Boolean =
+ when (this) {
+ is FooterView,
+ is NotificationShelf,
+ is SectionHeaderView -> true
+ else -> false
+ }
}
/**