diff --git a/src/com/android/settings/widget/SeekBarPreference.java b/src/com/android/settings/widget/SeekBarPreference.java index ac2838271c4..47bb28608d5 100644 --- a/src/com/android/settings/widget/SeekBarPreference.java +++ b/src/com/android/settings/widget/SeekBarPreference.java @@ -16,6 +16,8 @@ package com.android.settings.widget; +import static android.view.HapticFeedbackConstants.CLOCK_TICK; + import android.content.Context; import android.content.res.TypedArray; import android.os.Parcel; @@ -39,12 +41,17 @@ import com.android.settingslib.RestrictedPreference; public class SeekBarPreference extends RestrictedPreference implements OnSeekBarChangeListener, View.OnKeyListener { + public static final int HAPTIC_FEEDBACK_MODE_NONE = 0; + public static final int HAPTIC_FEEDBACK_MODE_ON_TICKS = 1; + public static final int HAPTIC_FEEDBACK_MODE_ON_ENDS = 2; + private int mProgress; private int mMax; private int mMin; private boolean mTrackingTouch; private boolean mContinuousUpdates; + private int mHapticFeedbackMode = HAPTIC_FEEDBACK_MODE_NONE; private int mDefaultProgress = -1; private SeekBar mSeekBar; @@ -235,6 +242,17 @@ public class SeekBarPreference extends RestrictedPreference mContinuousUpdates = continuousUpdates; } + /** + * Sets the haptic feedback mode. HAPTIC_FEEDBACK_MODE_ON_TICKS means to perform haptic feedback + * as the SeekBar's progress is updated; HAPTIC_FEEDBACK_MODE_ON_ENDS means to perform haptic + * feedback as the SeekBar's progress value is equal to the min/max value. + * + * @param hapticFeedbackMode the haptic feedback mode. + */ + public void setHapticFeedbackMode(int hapticFeedbackMode) { + mHapticFeedbackMode = hapticFeedbackMode; + } + private void setProgress(int progress, boolean notifyChanged) { if (progress > mMax) { progress = mMax; @@ -264,6 +282,16 @@ public class SeekBarPreference extends RestrictedPreference if (progress != mProgress) { if (callChangeListener(progress)) { setProgress(progress, false); + switch (mHapticFeedbackMode) { + case HAPTIC_FEEDBACK_MODE_ON_TICKS: + seekBar.performHapticFeedback(CLOCK_TICK); + break; + case HAPTIC_FEEDBACK_MODE_ON_ENDS: + if (progress == mMax || progress == mMin) { + seekBar.performHapticFeedback(CLOCK_TICK); + } + break; + } } else { seekBar.setProgress(mProgress); } diff --git a/tests/robotests/src/com/android/settings/widget/SeekBarPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/SeekBarPreferenceTest.java index 42ed0746417..451b84bd882 100644 --- a/tests/robotests/src/com/android/settings/widget/SeekBarPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/widget/SeekBarPreferenceTest.java @@ -16,15 +16,21 @@ package com.android.settings.widget; +import static android.view.HapticFeedbackConstants.CLOCK_TICK; +import static android.view.HapticFeedbackConstants.CONTEXT_CLICK; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; import android.content.Context; import android.os.Bundle; import android.os.Parcelable; +import android.widget.SeekBar; import androidx.preference.PreferenceFragmentCompat; @@ -46,9 +52,11 @@ public class SeekBarPreferenceTest { private static final int MAX = 75; private static final int MIN = 5; private static final int PROGRESS = 16; + private static final int NEW_PROGRESS = 17; private Context mContext; private SeekBarPreference mSeekBarPreference; + private SeekBar mSeekBar; @Before public void setUp() { @@ -60,6 +68,11 @@ public class SeekBarPreferenceTest { mSeekBarPreference.setMin(MIN); mSeekBarPreference.setProgress(PROGRESS); mSeekBarPreference.setPersistent(false); + mSeekBarPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_NONE); + + mSeekBar = new SeekBar(mContext); + mSeekBar.setMax(MAX); + mSeekBar.setMin(MIN); } @Test @@ -118,6 +131,53 @@ public class SeekBarPreferenceTest { verify(mSeekBarPreference).setSeekBarStateDescription("test"); } + @Test + public void onProgressChanged_hapticFeedbackModeNone_clockTickFeedbackNotPerformed() { + mSeekBar.setProgress(NEW_PROGRESS); + when(mSeekBarPreference.callChangeListener(anyInt())).thenReturn(true); + mSeekBar.performHapticFeedback(CONTEXT_CLICK); + + mSeekBarPreference.onProgressChanged(mSeekBar, NEW_PROGRESS, true); + + assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isNotEqualTo(CLOCK_TICK); + } + + @Test + public void onProgressChanged_hapticFeedbackModeOnTicks_clockTickFeedbackPerformed() { + mSeekBarPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_TICKS); + mSeekBar.setProgress(NEW_PROGRESS); + when(mSeekBarPreference.callChangeListener(anyInt())).thenReturn(true); + mSeekBar.performHapticFeedback(CONTEXT_CLICK); + + mSeekBarPreference.onProgressChanged(mSeekBar, NEW_PROGRESS, true); + + assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK); + } + + @Test + public void onProgressChanged_hapticFeedbackModeOnEnds_clockTickFeedbackNotPerformed() { + mSeekBarPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_ENDS); + mSeekBar.setProgress(NEW_PROGRESS); + when(mSeekBarPreference.callChangeListener(anyInt())).thenReturn(true); + mSeekBar.performHapticFeedback(CONTEXT_CLICK); + + mSeekBarPreference.onProgressChanged(mSeekBar, NEW_PROGRESS, true); + + assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isNotEqualTo(CLOCK_TICK); + } + + @Test + public void onProgressChanged_hapticFeedbackModeOnEndsAndMinValue_clockTickFeedbackPerformed() { + mSeekBarPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_ENDS); + mSeekBar.setProgress(MIN); + when(mSeekBarPreference.callChangeListener(anyInt())).thenReturn(true); + mSeekBar.performHapticFeedback(CONTEXT_CLICK); + + mSeekBarPreference.onProgressChanged(mSeekBar, MIN, true); + + assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK); + } + public static class TestFragment extends PreferenceFragmentCompat { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {