diff options
| author | 2025-01-28 12:10:38 -0800 | |
|---|---|---|
| committer | 2025-01-28 12:10:38 -0800 | |
| commit | 502ef2bf446118f111a8e9232e260280d76d4702 (patch) | |
| tree | 586b0691669e5ff801e6eed59b9000f0e3a0dd60 | |
| parent | 6893f8be80fda109887fa665a77874c1a5a71782 (diff) | |
| parent | 2b2081b9915e5e39cb918ee0bc785d6019a43b4d (diff) | |
Merge "Integrating MagneticNotificationRowManager with NSSL controller." into main
10 files changed, 163 insertions, 27 deletions
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 90bda09e8630..f4181e1c69ef 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1962,13 +1962,10 @@ flag { } 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 20cd6c7517e2..4ce13804c913 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 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @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 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { 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 789701f5e4b0..766ae73cb49d 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 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { 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 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { 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 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { 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 13cd2c538f3f..19b29206440d 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -19,6 +19,7 @@ package com.android.systemui; 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 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { 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 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { 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 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { dismissChild(mTouchedView, velocity, !swipedFastEnough() /* useAccelerateInterpolator */); } else { - mCallback.onDragCancelled(mTouchedView); + mCallback.onDragCancelledWithVelocity(mTouchedView, velocity); snapChild(mTouchedView, 0 /* leftTarget */, velocity); } mTouchedView = null; @@ -925,6 +931,15 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { 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 0346108856a2..3dbf0698dce9 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.data.repository.ZenModeRepositoryImp 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.NotificationEntryProcesso 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 @@ public interface NotificationsModule { 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 ba6f8f4a18f5..bd13dcd4e10b 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.Flags.notificationsRedesignTemplates; 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.ArrayList; 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView 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 345d59a412bd..02336e42c26a 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 @@ interface MagneticNotificationRowManager { * [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 bf24c873c693..04862c91e7ec 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 android.view.MotionEvent.ACTION_UP; 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 @@ public class NotificationStackScrollLayout 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 8eaef3681e5c..804824569f1e 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 @@ public class NotificationStackScrollLayoutController implements Dumpable { 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 @@ public class NotificationStackScrollLayoutController implements Dumpable { } @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 class NotificationStackScrollLayoutController implements Dumpable { 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 class NotificationStackScrollLayoutController implements Dumpable { */ 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 @@ public class NotificationStackScrollLayoutController implements Dumpable { @Override public void onBeginDrag(View v) { + if (v instanceof ExpandableNotificationRow row) { + mMagneticNotificationRowManager.setMagneticAndRoundableTargets( + row, mView, mSectionsManager); + } mView.onSwipeBegin(v); } @@ -691,7 +731,9 @@ public class NotificationStackScrollLayoutController implements Dumpable { ActivityStarter activityStarter, SplitShadeStateController splitShadeStateController, SensitiveNotificationProtectionController sensitiveNotificationProtectionController, - WallpaperInteractor wallpaperInteractor) { + WallpaperInteractor wallpaperInteractor, + MagneticNotificationRowManager magneticNotificationRowManager, + NotificationSectionsManager sectionsManager) { mView = view; mViewBinder = viewBinder; mStackStateLogger = stackLogger; @@ -742,6 +784,8 @@ public class NotificationStackScrollLayoutController implements Dumpable { 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 50457449f466..d476d482226d 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 android.view.ViewConfiguration; 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 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc superSnapChild(animView, targetLeft, velocity); } - mCallback.onDragCancelled(animView); + mCallback.onDragCancelledWithVelocity(animView, velocity); if (targetLeft == 0) { handleMenuCoveredOrDismissed(); } @@ -404,7 +403,11 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc @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 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc 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 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc * @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 { |