// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Based on frameworks/base/core/java/android/preference/SeekBarPreference.java, // extended to support floating-point min/max/step and a summary label. package org.chromium.chrome.browser.preferences; import android.content.Context; import android.preference.Preference; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import org.chromium.chrome.R; /** * A preference that allows the user to set a value by sliding a seek bar. * * When this preference is used, a layout must be provided that contains a SeekBar with ID "seekbar" * and a TextView with ID "seekbar_amount". */ public class SeekBarPreference extends Preference implements OnSeekBarChangeListener { private float mMin, mMax, mStep; private float mValue; private boolean mTrackingTouch; CharSequence mSummary; private TextView mSummaryView; /** * Constructor for inflating from XML. */ public SeekBarPreference(Context context, AttributeSet attrs) { super(context, attrs); mMin = 0.5f; mMax = 2.0f; mStep = 0.05f; mValue = mMin; } /** * Sets the progress value for the seekbar. The value will be adjusted, if needed, to ensure * it's within the valid range. */ public void setValue(float value) { setValue(value, true); } /** * Returns whether the user is currently dragging the seek bar. */ public boolean isTrackingTouch() { return mTrackingTouch; } @Override protected void onBindView(View view) { super.onBindView(view); SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar); seekBar.setOnSeekBarChangeListener(this); seekBar.setMax(prefValueToSeekBarProgress(mMax)); seekBar.setProgress(prefValueToSeekBarProgress(mValue)); seekBar.setEnabled(isEnabled()); mSummaryView = (TextView) view.findViewById(R.id.seekbar_amount); mSummaryView.setText(mSummary); } /** * Sets the summary for this Preference with a CharSequence. Unlike the superclass * implementation, this does not call notifyChanged() as that would cancel the * current slider drag. * * @param summary The summary for the preference. */ @Override public void setSummary(CharSequence summary) { if (TextUtils.equals(summary, mSummary)) return; mSummary = summary; if (mSummaryView != null) mSummaryView.setText(summary); } @Override public CharSequence getSummary() { return mSummary; } private float seekBarProgressToPrefValue(int seekBarProgress) { // SeekBar only supports integer steps, and always starts from 0. // So must convert floating point pref values to/from integers, // appropriately scaled for the SeekBar. return mMin + seekBarProgress * mStep; } private int prefValueToSeekBarProgress(float prefValue) { return Math.round((prefValue - mMin) / mStep); } private void setValue(float value, boolean notifyChanged) { value = Math.min(mMax, Math.max(mMin, value)); if (value != mValue) { mValue = value; if (notifyChanged) notifyChanged(); } } /** * Persist the seekBar's progress value if callChangeListener * returns true, otherwise set the seekBar's progress to the stored value */ private void syncProgress(SeekBar seekBar) { float value = seekBarProgressToPrefValue(seekBar.getProgress()); if (value != mValue) { if (callChangeListener(value)) { setValue(value, false); } else { seekBar.setProgress(prefValueToSeekBarProgress(mValue)); } } } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) syncProgress(seekBar); } @Override public void onStartTrackingTouch(SeekBar seekBar) { mTrackingTouch = true; } @Override public void onStopTrackingTouch(SeekBar seekBar) { mTrackingTouch = false; } }