108108import com .google .android .material .shape .MaterialShapeDrawable ;
109109import com .google .android .material .shape .ShapeAppearanceModel ;
110110import com .google .android .material .tooltip .TooltipDrawable ;
111+ import com .google .errorprone .annotations .CanIgnoreReturnValue ;
111112import java .lang .annotation .Retention ;
112113import java .lang .annotation .RetentionPolicy ;
113114import java .math .BigDecimal ;
@@ -361,6 +362,9 @@ abstract class BaseSlider<
361362 private float touchDownAxis1 ;
362363 private float touchDownAxis2 ;
363364 private MotionEvent lastEvent ;
365+ @ NonNull private final Rect viewRect = new Rect ();
366+ @ NonNull List <Rect > exclusionRects = new ArrayList <>();
367+ @ NonNull private List <Float > previousDownTouchEventValues = new ArrayList <>();
364368 private LabelFormatter formatter ;
365369 private boolean thumbIsPressed = false ;
366370 private float valueFrom ;
@@ -3209,6 +3213,23 @@ private boolean shouldDrawCompatHalo() {
32093213 return forceDrawCompatHalo || !(getBackground () instanceof RippleDrawable );
32103214 }
32113215
3216+ @ Override
3217+ public void onLayout (boolean changed , int left , int top , int right , int bottom ) {
3218+ super .onLayout (changed , left , top , right , bottom );
3219+
3220+ viewRect .left = 0 ;
3221+ viewRect .top = 0 ;
3222+ viewRect .right = right - left ;
3223+ viewRect .bottom = bottom - top ;
3224+
3225+ if (!exclusionRects .contains (viewRect )) {
3226+ exclusionRects .add (viewRect );
3227+ }
3228+
3229+ // Make sure that the slider takes precedence over back navigation gestures.
3230+ ViewCompat .setSystemGestureExclusionRects (this , exclusionRects );
3231+ }
3232+
32123233 @ Override
32133234 public boolean onTouchEvent (@ NonNull MotionEvent event ) {
32143235 if (!isEnabled ()) {
@@ -3225,6 +3246,8 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
32253246 case MotionEvent .ACTION_DOWN :
32263247 touchDownAxis1 = eventCoordinateAxis1 ;
32273248 touchDownAxis2 = eventCoordinateAxis2 ;
3249+ previousDownTouchEventValues .clear ();
3250+ previousDownTouchEventValues = getValues ();
32283251
32293252 // If we're inside a vertical scrolling container,
32303253 // we should start dragging in ACTION_MOVE
@@ -3284,7 +3307,6 @@ && abs(eventCoordinateAxis2 - touchDownAxis2) < scaledTouchSlop * TOUCH_SLOP_RAT
32843307 invalidate ();
32853308 break ;
32863309 case MotionEvent .ACTION_UP :
3287- case MotionEvent .ACTION_CANCEL :
32883310 thumbIsPressed = false ;
32893311 // We need to handle a tap if the last event was down at the same point.
32903312 if (lastEvent != null
@@ -3305,6 +3327,16 @@ && abs(lastEvent.getY() - event.getY()) <= scaledTouchSlop) {
33053327 }
33063328 invalidate ();
33073329 break ;
3330+ case MotionEvent .ACTION_CANCEL :
3331+ thumbIsPressed = false ;
3332+ // Make sure that we reset the state of the slider if a cancel event happens.
3333+ snapThumbToPreviousDownTouchEventValue ();
3334+ updateHaloHotspot ();
3335+ resetThumbWidth ();
3336+ activeThumbIdx = -1 ;
3337+ onStopTrackingTouch ();
3338+ invalidate ();
3339+ break ;
33083340 default :
33093341 // Nothing to do in this case.
33103342 }
@@ -3419,6 +3451,7 @@ private boolean snapActiveThumbToValue(float value) {
34193451 return snapThumbToValue (activeThumbIdx , value );
34203452 }
34213453
3454+ @ CanIgnoreReturnValue
34223455 private boolean snapThumbToValue (int idx , float value ) {
34233456 focusedThumbIdx = idx ;
34243457
@@ -3435,6 +3468,17 @@ private boolean snapThumbToValue(int idx, float value) {
34353468 return true ;
34363469 }
34373470
3471+ private void snapThumbToPreviousDownTouchEventValue () {
3472+ if (activeThumbIdx != -1 && !previousDownTouchEventValues .isEmpty ()) {
3473+ for (int i = 0 ; i < values .size (); i ++) {
3474+ if (i == activeThumbIdx ) {
3475+ snapThumbToValue (i , previousDownTouchEventValues .get (i ));
3476+ break ;
3477+ }
3478+ }
3479+ }
3480+ }
3481+
34383482 /** Thumbs cannot cross each other, clamp the value to a bound or the value next to it. */
34393483 private float getClampedValue (int idx , float value ) {
34403484 float minSeparation = getMinSeparation ();
0 commit comments