// 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;
}
}