package org.music.player; import org.music.player.R; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.res.Resources; import android.preference.DialogPreference; import android.util.AttributeSet; import android.view.Gravity; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; /** * A preference that provides a dialog with a slider for idle time. * * The slider produces a value in seconds from 60 (1 minute) to 21600 * (6 hours). The values range on an approximately exponential scale. */ public class IdlePreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener { private static final int DEFAULT_VALUE = 3600; private static final int MIN = 60; private static final int MAX = 21600; /** * The current idle timeout displayed on the slider. Will not be persisted * until the dialog is closed. */ private int mValue; /** * The view in which the value is displayed. */ private TextView mValueText; public IdlePreference(Context context, AttributeSet attrs) { super(context, attrs); } @Override public CharSequence getSummary() { return formatTime(getPersistedInt(DEFAULT_VALUE)); } @Override protected void onPrepareDialogBuilder(Builder builder) { Context context = getContext(); ViewGroup.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); mValue = getPersistedInt(DEFAULT_VALUE); LinearLayout layout = new LinearLayout(context); layout.setOrientation(LinearLayout.VERTICAL); layout.setLayoutParams(params); mValueText = new TextView(context); mValueText.setGravity(Gravity.RIGHT); mValueText.setPadding(20, 0, 20, 0); layout.addView(mValueText); SeekBar seekBar = new SeekBar(context); seekBar.setPadding(20, 0, 20, 20); seekBar.setLayoutParams(params); seekBar.setMax(1000); seekBar.setProgress((int)(Math.pow((float)(mValue - MIN) / (MAX - MIN), 0.25f) * 1000)); seekBar.setOnSeekBarChangeListener(this); layout.addView(seekBar); updateText(); builder.setView(layout); } /** * Format seconds into a human-readable time description. * * @param value The time, in seconds. * @return A human-readable string, such as "1 hour, 21 minutes" */ private String formatTime(int value) { Resources res = getContext().getResources(); StringBuilder text = new StringBuilder(); if (value >= 3600) { int hours = value / 3600; text.append(res.getQuantityString(R.plurals.hours, hours, hours)); text.append(", "); int minutes = value / 60 - hours * 60; text.append(res.getQuantityString(R.plurals.minutes, minutes, minutes)); } else { int minutes = value / 60; text.append(res.getQuantityString(R.plurals.minutes, minutes, minutes)); text.append(", "); int seconds = value - minutes * 60; text.append(res.getQuantityString(R.plurals.seconds, seconds, seconds)); } return text.toString(); } /** * Update the text view with the current value. */ private void updateText() { mValueText.setText(formatTime(mValue)); } @Override protected void onDialogClosed(boolean positiveResult) { if (positiveResult && shouldPersist()) { persistInt(mValue); notifyChanged(); } } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // Approximate an exponential curve with x^4. Produces a value from MIN-MAX. if (fromUser) { float value = seekBar.getProgress() / 1000.0f; value *= value; value *= value; mValue = (int)(value * (MAX - MIN)) + MIN; updateText(); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }