Skip to content

Commit c4d19f6

Browse files
leticiarossipekingme
authored andcommitted
[Slider] Fix ACTION_CANCEL motion touch event handling so that the slider resets its state if a cancel happens. Also don't let slider update incorrectly when a touch event may be overlapping with back gesture inset areas, as the back event takes precedence.
PiperOrigin-RevId: 828106972
1 parent 90a8043 commit c4d19f6

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

lib/java/com/google/android/material/slider/BaseSlider.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
import com.google.android.material.shape.MaterialShapeDrawable;
109109
import com.google.android.material.shape.ShapeAppearanceModel;
110110
import com.google.android.material.tooltip.TooltipDrawable;
111+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
111112
import java.lang.annotation.Retention;
112113
import java.lang.annotation.RetentionPolicy;
113114
import 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

Comments
 (0)