Merge "Integrating MagneticNotificationRowManager with NSSL controller." into main
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 90bda09..f4181e1 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1962,13 +1962,10 @@
}
flag {
- name: "magnetic_notification_horizontal_swipe"
+ name: "magnetic_notification_swipes"
namespace: "systemui"
description: "Add support for magnetic behavior on horizontal notification swipes."
bug: "390179908"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
}
flag {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 20cd6c7..4ce1380 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -165,6 +165,8 @@
@Mock
private SensitiveNotificationProtectionController mSensitiveNotificationProtectionController;
@Mock private ExpandHelper mExpandHelper;
+ @Mock private MagneticNotificationRowManager mMagneticNotificationRowManager;
+ @Mock private NotificationSectionsManager mSectionsManager;
@Captor
private ArgumentCaptor<Runnable> mSensitiveStateListenerArgumentCaptor;
@@ -798,7 +800,9 @@
mActivityStarter,
new ResourcesSplitShadeStateController(),
mSensitiveNotificationProtectionController,
- mWallpaperInteractor);
+ mWallpaperInteractor,
+ mMagneticNotificationRowManager,
+ mSectionsManager);
}
static class LogMatcher implements ArgumentMatcher<LogMaker> {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 789701f5..766ae73 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -405,7 +405,7 @@
doNothing().when(mSwipeHelper).superSnapChild(mNotificationRow, 0, 0);
mSwipeHelper.snapChild(mNotificationRow, 0, 0);
- verify(mCallback, times(1)).onDragCancelled(mNotificationRow);
+ verify(mCallback, times(1)).onDragCancelledWithVelocity(mNotificationRow, 0);
verify(mSwipeHelper, times(1)).superSnapChild(mNotificationRow, 0, 0);
verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
}
@@ -416,7 +416,7 @@
doNothing().when(mSwipeHelper).superSnapChild(mNotificationRow, 10, 0);
mSwipeHelper.snapChild(mNotificationRow, 10, 0);
- verify(mCallback, times(1)).onDragCancelled(mNotificationRow);
+ verify(mCallback, times(1)).onDragCancelledWithVelocity(mNotificationRow, 0);
verify(mSwipeHelper, times(1)).superSnapChild(mNotificationRow, 10, 0);
verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed();
}
@@ -426,7 +426,7 @@
doNothing().when(mSwipeHelper).superSnapChild(mView, 10, 0);
mSwipeHelper.snapChild(mView, 10, 0);
- verify(mCallback).onDragCancelled(mView);
+ verify(mCallback).onDragCancelledWithVelocity(mView, 0);
verify(mSwipeHelper, never()).superSnapChild(mView, 10, 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 13cd2c5..19b2920 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -19,6 +19,7 @@
import static androidx.dynamicanimation.animation.DynamicAnimation.TRANSLATION_X;
import static androidx.dynamicanimation.animation.FloatPropertyCompat.createFloatPropertyCompat;
+import static com.android.systemui.Flags.magneticNotificationSwipes;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
@@ -76,8 +77,7 @@
protected final Handler mHandler;
- private final SpringConfig mSnapBackSpringConfig =
- new SpringConfig(SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
+ private final SpringConfig mSnapBackSpringConfig;
private final FlingAnimationUtils mFlingAnimationUtils;
private float mPagingTouchSlop;
@@ -153,6 +153,12 @@
R.bool.config_fadeDependingOnAmountSwiped);
mFalsingManager = falsingManager;
mFeatureFlags = featureFlags;
+ if (magneticNotificationSwipes()) {
+ mSnapBackSpringConfig = new SpringConfig(550f /*stiffness*/, 0.52f /*dampingRatio*/);
+ } else {
+ mSnapBackSpringConfig = new SpringConfig(
+ SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
+ }
mFlingAnimationUtils = new FlingAnimationUtils(resources.getDisplayMetrics(),
getMaxEscapeAnimDuration() / 1000f);
}
@@ -718,7 +724,7 @@
dismissChild(mTouchedView, velocity,
!swipedFastEnough() /* useAccelerateInterpolator */);
} else {
- mCallback.onDragCancelled(mTouchedView);
+ mCallback.onDragCancelledWithVelocity(mTouchedView, velocity);
snapChild(mTouchedView, 0 /* leftTarget */, velocity);
}
mTouchedView = null;
@@ -925,6 +931,15 @@
void onDragCancelled(View v);
/**
+ * A drag operation has been cancelled on a view with a final velocity.
+ * @param v View that was dragged.
+ * @param finalVelocity Final velocity of the drag.
+ */
+ default void onDragCancelledWithVelocity(View v, float finalVelocity) {
+ onDragCancelled(v);
+ }
+
+ /**
* Called when the child is long pressed and available to start drag and drop.
*
* @param v the view that was long pressed.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 0346108..3dbf069 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -27,6 +27,7 @@
import com.android.settingslib.notification.domain.interactor.NotificationsSoundPolicyInteractor;
import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.systemui.CoreStartable;
+import com.android.systemui.Flags;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dagger.qualifiers.Background;
@@ -84,6 +85,8 @@
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule;
+import com.android.systemui.statusbar.notification.stack.MagneticNotificationRowManager;
+import com.android.systemui.statusbar.notification.stack.MagneticNotificationRowManagerImpl;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
@@ -322,4 +325,19 @@
return (entry, recoveredBuilder) -> null;
}
}
+
+ /**
+ * Provide an implementation of {@link MagneticNotificationRowManager} based on its flag.
+ */
+ @Provides
+ @SysUISingleton
+ static MagneticNotificationRowManager provideMagneticNotificationRowManager(
+ Provider<MagneticNotificationRowManagerImpl> implProvider
+ ) {
+ if (Flags.magneticNotificationSwipes()) {
+ return implProvider.get();
+ } else {
+ return MagneticNotificationRowManager.getEmpty();
+ }
+ }
}
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 ba6f8f4..bd13dcd 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
@@ -20,8 +20,8 @@
import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
-import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE;
import static com.android.systemui.Flags.notificationsPinnedHunInShade;
+import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
import static com.android.systemui.statusbar.policy.RemoteInputView.FOCUS_ANIMATION_MIN_SCALE;
@@ -142,7 +142,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
@@ -366,6 +365,7 @@
this, FloatPropertyCompat.createFloatPropertyCompat(TRANSLATE_CONTENT));
private final MagneticRowListener mMagneticRowListener = new MagneticRowListener() {
+
@Override
public void setMagneticTranslation(float translation) {
if (mMagneticAnimator.isRunning()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt
index 345d59a..02336e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt
@@ -96,4 +96,35 @@
* [onMagneticInteractionEnd] will not be called from the lifecycle of the user gesture.
*/
fun reset()
+
+ companion object {
+ /** Detaching threshold in dp */
+ const val MAGNETIC_DETACH_THRESHOLD_DP = 56
+
+ /* An empty implementation of a manager */
+ @JvmStatic
+ val Empty: MagneticNotificationRowManager
+ get() =
+ object : MagneticNotificationRowManager {
+ override fun setSwipeThresholdPx(thresholdPx: Float) {}
+
+ override fun setMagneticAndRoundableTargets(
+ swipingRow: ExpandableNotificationRow,
+ stackScrollLayout: NotificationStackScrollLayout,
+ sectionsManager: NotificationSectionsManager,
+ ) {}
+
+ override fun setMagneticRowTranslation(
+ row: ExpandableNotificationRow,
+ translation: Float,
+ ): Boolean = false
+
+ override fun onMagneticInteractionEnd(
+ row: ExpandableNotificationRow,
+ velocity: Float?,
+ ) {}
+
+ override fun reset() {}
+ }
+ }
}
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 bf24c87..04862c9 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
@@ -24,6 +24,7 @@
import static com.android.app.tracing.TrackGroupUtils.trackGroup;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_CLEAR_ALL;
+import static com.android.systemui.Flags.magneticNotificationSwipes;
import static com.android.systemui.Flags.notificationOverExpansionClippingFix;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
@@ -5787,17 +5788,21 @@
getChildrenWithBackground()
);
- RoundableTargets targets = mController.getNotificationTargetsHelper().findRoundableTargets(
- (ExpandableNotificationRow) viewSwiped,
- this,
- mSectionsManager
- );
+ if (!magneticNotificationSwipes()) {
+ RoundableTargets targets = mController
+ .getNotificationTargetsHelper()
+ .findRoundableTargets(
+ (ExpandableNotificationRow) viewSwiped,
+ this,
+ mSectionsManager);
- mController.getNotificationRoundnessManager()
- .setViewsAffectedBySwipe(
- targets.getBefore(),
- targets.getSwiped(),
- targets.getAfter());
+ mController.getNotificationRoundnessManager()
+ .setViewsAffectedBySwipe(
+ targets.getBefore(),
+ targets.getSwiped(),
+ targets.getAfter());
+
+ }
updateFirstAndLastBackgroundViews();
requestDisallowInterceptTouchEvent(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 8eaef36..8048245 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -188,6 +188,8 @@
private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateLogger mStackStateLogger;
private final NotificationStackScrollLogger mLogger;
+ private final MagneticNotificationRowManager mMagneticNotificationRowManager;
+ private final NotificationSectionsManager mSectionsManager;
private final GroupExpansionManager mGroupExpansionManager;
private NotificationStackScrollLayout mView;
@@ -465,6 +467,28 @@
}
@Override
+ public void onDensityScaleChange(float density) {
+ mMagneticNotificationRowManager.setSwipeThresholdPx(
+ density * MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP
+ );
+ }
+
+ @Override
+ public boolean handleSwipeableViewTranslation(SwipeableView view, float translate) {
+ if (view instanceof ExpandableNotificationRow row) {
+ return mMagneticNotificationRowManager
+ .setMagneticRowTranslation(row, translate);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void resetMagneticStates() {
+ mMagneticNotificationRowManager.reset();
+ }
+
+ @Override
public void onSnooze(StatusBarNotification sbn,
NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
mNotificationsController.setNotificationSnoozed(sbn, snoozeOption);
@@ -479,6 +503,14 @@
public void onDragCancelled(View v) {
}
+ @Override
+ public void onDragCancelledWithVelocity(View v, float finalVelocity) {
+ if (v instanceof ExpandableNotificationRow row) {
+ mMagneticNotificationRowManager.onMagneticInteractionEnd(
+ row, finalVelocity);
+ }
+ }
+
/**
* Handles cleanup after the given {@code view} has been fully swiped out (including
* re-invoking dismiss logic in case the notification has not made its way out yet).
@@ -506,6 +538,10 @@
*/
public void handleChildViewDismissed(View view) {
+ if (view instanceof ExpandableNotificationRow row) {
+ mMagneticNotificationRowManager.onMagneticInteractionEnd(
+ row, null /* velocity */);
+ }
// The View needs to clean up the Swipe states, e.g. roundness.
mView.onSwipeEnd();
if (mView.getClearAllInProgress()) {
@@ -577,6 +613,10 @@
@Override
public void onBeginDrag(View v) {
+ if (v instanceof ExpandableNotificationRow row) {
+ mMagneticNotificationRowManager.setMagneticAndRoundableTargets(
+ row, mView, mSectionsManager);
+ }
mView.onSwipeBegin(v);
}
@@ -691,7 +731,9 @@
ActivityStarter activityStarter,
SplitShadeStateController splitShadeStateController,
SensitiveNotificationProtectionController sensitiveNotificationProtectionController,
- WallpaperInteractor wallpaperInteractor) {
+ WallpaperInteractor wallpaperInteractor,
+ MagneticNotificationRowManager magneticNotificationRowManager,
+ NotificationSectionsManager sectionsManager) {
mView = view;
mViewBinder = viewBinder;
mStackStateLogger = stackLogger;
@@ -742,6 +784,8 @@
mSensitiveNotificationProtectionController = sensitiveNotificationProtectionController;
mWallpaperInteractor = wallpaperInteractor;
mView.passSplitShadeStateController(splitShadeStateController);
+ mMagneticNotificationRowManager = magneticNotificationRowManager;
+ mSectionsManager = sectionsManager;
if (SceneContainerFlag.isEnabled()) {
mWakeUpCoordinator.setStackScroller(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 5045744..d476d48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -34,7 +34,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.SwipeHelper;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.FalsingManager;
@@ -363,7 +362,7 @@
superSnapChild(animView, targetLeft, velocity);
}
- mCallback.onDragCancelled(animView);
+ mCallback.onDragCancelledWithVelocity(animView, velocity);
if (targetLeft == 0) {
handleMenuCoveredOrDismissed();
}
@@ -404,7 +403,11 @@
@Override
public void setTranslation(View v, float translate) {
if (v instanceof SwipeableView) {
- ((SwipeableView) v).setTranslation(translate);
+ boolean setTranslationHandled =
+ mCallback.handleSwipeableViewTranslation((SwipeableView) v, translate);
+ if (!setTranslationHandled) {
+ ((SwipeableView) v).setTranslation(translate);
+ }
}
}
@@ -529,6 +532,18 @@
mPulsing = pulsing;
}
+ @Override
+ public void setDensityScale(float densityScale) {
+ super.setDensityScale(densityScale);
+ mCallback.onDensityScaleChange(densityScale);
+ }
+
+ @Override
+ public void resetTouchState() {
+ super.resetTouchState();
+ mCallback.resetMagneticStates();
+ }
+
public interface NotificationCallback extends SwipeHelper.Callback{
/**
* @return if the view should be dismissed as soon as the touch is released, otherwise its
@@ -548,6 +563,13 @@
* @param animView the view to ask about
*/
float getTotalTranslationLength(View animView);
+
+ void onDensityScaleChange(float density);
+
+ boolean handleSwipeableViewTranslation(SwipeableView view, float translate);
+
+ // Reset any ongoing magnetic interactions
+ void resetMagneticStates();
}
static class Builder {