Skip to content

Commit 194a0aa

Browse files
cketchamdsn5ft
authored andcommitted
[Slider] Fix the validation of the slider step size and values.
Resolves #1587 PiperOrigin-RevId: 327419448 (cherry picked from commit 5004d5a)
1 parent 475e63b commit 194a0aa

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282
import com.google.android.material.tooltip.TooltipDrawable;
8383
import java.lang.annotation.Retention;
8484
import java.lang.annotation.RetentionPolicy;
85+
import java.math.BigDecimal;
86+
import java.math.MathContext;
8587
import java.util.ArrayList;
8688
import java.util.Collections;
8789
import java.util.Iterator;
@@ -456,8 +458,21 @@ private void validateValueTo() {
456458
}
457459
}
458460

461+
private boolean valueLandsOnTick(float value) {
462+
// Check that the value is a multiple of stepSize given the offset of valueFrom
463+
// We're using BigDecimal here to avoid floating point rounding errors.
464+
double potentialTickValue =
465+
new BigDecimal(Float.toString(value))
466+
.subtract(new BigDecimal(Float.toString(valueFrom)))
467+
.divide(new BigDecimal(Float.toString(stepSize)), MathContext.DECIMAL64)
468+
.doubleValue();
469+
470+
// If the potentialTickValue is a whole number, it means the value lands on a tick.
471+
return Math.abs(Math.round(potentialTickValue) - potentialTickValue) < THRESHOLD;
472+
}
473+
459474
private void validateStepSize() {
460-
if (stepSize > 0.0f && ((valueTo - valueFrom) / stepSize) % 1 > THRESHOLD) {
475+
if (stepSize > 0.0f && !valueLandsOnTick(valueTo)) {
461476
throw new IllegalStateException(
462477
String.format(
463478
EXCEPTION_ILLEGAL_STEP_SIZE,
@@ -477,7 +492,7 @@ private void validateValues() {
477492
Float.toString(valueFrom),
478493
Float.toString(valueTo)));
479494
}
480-
if (stepSize > 0.0f && ((valueFrom - value) / stepSize) % 1 > THRESHOLD) {
495+
if (stepSize > 0.0f && !valueLandsOnTick(value)) {
481496
throw new IllegalStateException(
482497
String.format(
483498
EXCEPTION_ILLEGAL_DISCRETE_VALUE,

lib/javatests/com/google/android/material/slider/SliderConfigTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,48 @@ public static Iterable<Object[]> data() {
119119
/* stepValue = */ 10f,
120120
/* value = */ 21f,
121121
IllegalStateException.class,
122+
},
123+
new Object[] {
124+
/* valueFrom = */ 0.1f,
125+
/* valueTo = */ 10f,
126+
/* stepValue = */ 0.1f,
127+
/* value = */ 0.1f,
128+
null,
129+
},
130+
new Object[] {
131+
/* valueFrom = */ 0.1f,
132+
/* valueTo = */ 10f,
133+
/* stepValue = */ 0.1f,
134+
/* value = */ 0.1999999f, // We don't support this level of precision.
135+
null,
136+
},
137+
new Object[] {
138+
/* valueFrom = */ 0f,
139+
/* valueTo = */ 10f,
140+
/* stepValue = */ 0.001f,
141+
/* value = */ 7f,
142+
null,
143+
},
144+
new Object[] {
145+
/* valueFrom = */ 0.1f,
146+
/* valueTo = */ 10f,
147+
/* stepValue = */ 0.1f,
148+
/* value = */ 0.15f,
149+
IllegalStateException.class,
150+
},
151+
new Object[] {
152+
/* valueFrom = */ 0f,
153+
/* valueTo = */ 100000f,
154+
/* stepValue = */ 0.01f,
155+
/* value = */ 65536.02f,
156+
null,
157+
},
158+
new Object[] {
159+
/* valueFrom = */ 0f,
160+
/* valueTo = */ 1f,
161+
/* stepValue = */ 1 / 3f,
162+
/* value = */ 0f,
163+
null,
122164
});
123165
}
124166

0 commit comments

Comments
 (0)