SeekBarPreference.java revision cbfe1eb881028d06aee9720634bbdbc4ef17e71a
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings.widget; 18 19import android.content.Context; 20import android.content.res.TypedArray; 21import android.os.Parcel; 22import android.os.Parcelable; 23import android.support.v4.content.res.TypedArrayUtils; 24import android.support.v7.preference.PreferenceViewHolder; 25import android.text.TextUtils; 26import android.util.AttributeSet; 27import android.view.KeyEvent; 28import android.view.View; 29import android.widget.SeekBar; 30import android.widget.SeekBar.OnSeekBarChangeListener; 31 32import com.android.settings.widget.DefaultIndicatorSeekBar; 33import com.android.settingslib.RestrictedPreference; 34 35/** 36 * Based on android.preference.SeekBarPreference, but uses support preference as base. 37 */ 38public class SeekBarPreference extends RestrictedPreference 39 implements OnSeekBarChangeListener, View.OnKeyListener { 40 41 private int mProgress; 42 private int mMax; 43 private boolean mTrackingTouch; 44 45 private boolean mContinuousUpdates; 46 private int mDefaultProgress = -1; 47 48 private SeekBar mSeekBar; 49 50 public SeekBarPreference( 51 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 52 super(context, attrs, defStyleAttr, defStyleRes); 53 54 TypedArray a = context.obtainStyledAttributes( 55 attrs, com.android.internal.R.styleable.ProgressBar, defStyleAttr, defStyleRes); 56 setMax(a.getInt(com.android.internal.R.styleable.ProgressBar_max, mMax)); 57 a.recycle(); 58 59 a = context.obtainStyledAttributes(attrs, 60 com.android.internal.R.styleable.SeekBarPreference, defStyleAttr, defStyleRes); 61 final int layoutResId = a.getResourceId( 62 com.android.internal.R.styleable.SeekBarPreference_layout, 63 com.android.internal.R.layout.preference_widget_seekbar); 64 a.recycle(); 65 66 setLayoutResource(layoutResId); 67 } 68 69 public SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) { 70 this(context, attrs, defStyleAttr, 0); 71 } 72 73 public SeekBarPreference(Context context, AttributeSet attrs) { 74 this(context, attrs, TypedArrayUtils.getAttr(context, 75 android.support.v7.preference.R.attr.seekBarPreferenceStyle, 76 com.android.internal.R.attr.seekBarPreferenceStyle)); 77 } 78 79 public SeekBarPreference(Context context) { 80 this(context, null); 81 } 82 83 @Override 84 public void onBindViewHolder(PreferenceViewHolder view) { 85 super.onBindViewHolder(view); 86 view.itemView.setOnKeyListener(this); 87 mSeekBar = (SeekBar) view.findViewById( 88 com.android.internal.R.id.seekbar); 89 mSeekBar.setOnSeekBarChangeListener(this); 90 mSeekBar.setMax(mMax); 91 mSeekBar.setProgress(mProgress); 92 mSeekBar.setEnabled(isEnabled()); 93 final CharSequence title = getTitle(); 94 if (!TextUtils.isEmpty(title)) { 95 mSeekBar.setContentDescription(title); 96 } 97 if (mSeekBar instanceof DefaultIndicatorSeekBar) { 98 ((DefaultIndicatorSeekBar) mSeekBar).setDefaultProgress(mDefaultProgress); 99 } 100 } 101 102 @Override 103 public CharSequence getSummary() { 104 return null; 105 } 106 107 @Override 108 protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { 109 setProgress(restoreValue ? getPersistedInt(mProgress) 110 : (Integer) defaultValue); 111 } 112 113 @Override 114 protected Object onGetDefaultValue(TypedArray a, int index) { 115 return a.getInt(index, 0); 116 } 117 118 @Override 119 public boolean onKey(View v, int keyCode, KeyEvent event) { 120 if (event.getAction() != KeyEvent.ACTION_DOWN) { 121 return false; 122 } 123 124 SeekBar seekBar = (SeekBar) v.findViewById(com.android.internal.R.id.seekbar); 125 if (seekBar == null) { 126 return false; 127 } 128 return seekBar.onKeyDown(keyCode, event); 129 } 130 131 public void setMax(int max) { 132 if (max != mMax) { 133 mMax = max; 134 notifyChanged(); 135 } 136 } 137 138 public void setProgress(int progress) { 139 setProgress(progress, true); 140 } 141 142 /** 143 * Sets the progress point to draw a single tick mark representing a default value. 144 */ 145 public void setDefaultProgress(int defaultProgress) { 146 if (mDefaultProgress != defaultProgress) { 147 mDefaultProgress = defaultProgress; 148 if (mSeekBar instanceof DefaultIndicatorSeekBar) { 149 ((DefaultIndicatorSeekBar) mSeekBar).setDefaultProgress(mDefaultProgress); 150 } 151 } 152 } 153 154 /** 155 * When {@code continuousUpdates} is true, update the persisted setting immediately as the thumb 156 * is dragged along the SeekBar. Otherwise, only update the value of the setting when the thumb 157 * is dropped. 158 */ 159 public void setContinuousUpdates(boolean continuousUpdates) { 160 mContinuousUpdates = continuousUpdates; 161 } 162 163 private void setProgress(int progress, boolean notifyChanged) { 164 if (progress > mMax) { 165 progress = mMax; 166 } 167 if (progress < 0) { 168 progress = 0; 169 } 170 if (progress != mProgress) { 171 mProgress = progress; 172 persistInt(progress); 173 if (notifyChanged) { 174 notifyChanged(); 175 } 176 } 177 } 178 179 public int getProgress() { 180 return mProgress; 181 } 182 183 /** 184 * Persist the seekBar's progress value if callChangeListener 185 * returns true, otherwise set the seekBar's progress to the stored value 186 */ 187 void syncProgress(SeekBar seekBar) { 188 int progress = seekBar.getProgress(); 189 if (progress != mProgress) { 190 if (callChangeListener(progress)) { 191 setProgress(progress, false); 192 } else { 193 seekBar.setProgress(mProgress); 194 } 195 } 196 } 197 198 @Override 199 public void onProgressChanged( 200 SeekBar seekBar, int progress, boolean fromUser) { 201 if (fromUser && (mContinuousUpdates || !mTrackingTouch)) { 202 syncProgress(seekBar); 203 } 204 } 205 206 @Override 207 public void onStartTrackingTouch(SeekBar seekBar) { 208 mTrackingTouch = true; 209 } 210 211 @Override 212 public void onStopTrackingTouch(SeekBar seekBar) { 213 mTrackingTouch = false; 214 if (seekBar.getProgress() != mProgress) { 215 syncProgress(seekBar); 216 } 217 } 218 219 @Override 220 protected Parcelable onSaveInstanceState() { 221 /* 222 * Suppose a client uses this preference type without persisting. We 223 * must save the instance state so it is able to, for example, survive 224 * orientation changes. 225 */ 226 227 final Parcelable superState = super.onSaveInstanceState(); 228 if (isPersistent()) { 229 // No need to save instance state since it's persistent 230 return superState; 231 } 232 233 // Save the instance state 234 final SavedState myState = new SavedState(superState); 235 myState.progress = mProgress; 236 myState.max = mMax; 237 return myState; 238 } 239 240 @Override 241 protected void onRestoreInstanceState(Parcelable state) { 242 if (!state.getClass().equals(SavedState.class)) { 243 // Didn't save state for us in onSaveInstanceState 244 super.onRestoreInstanceState(state); 245 return; 246 } 247 248 // Restore the instance state 249 SavedState myState = (SavedState) state; 250 super.onRestoreInstanceState(myState.getSuperState()); 251 mProgress = myState.progress; 252 mMax = myState.max; 253 notifyChanged(); 254 } 255 256 /** 257 * SavedState, a subclass of {@link BaseSavedState}, will store the state 258 * of MyPreference, a subclass of Preference. 259 * <p> 260 * It is important to always call through to super methods. 261 */ 262 private static class SavedState extends BaseSavedState { 263 int progress; 264 int max; 265 266 public SavedState(Parcel source) { 267 super(source); 268 269 // Restore the click counter 270 progress = source.readInt(); 271 max = source.readInt(); 272 } 273 274 @Override 275 public void writeToParcel(Parcel dest, int flags) { 276 super.writeToParcel(dest, flags); 277 278 // Save the click counter 279 dest.writeInt(progress); 280 dest.writeInt(max); 281 } 282 283 public SavedState(Parcelable superState) { 284 super(superState); 285 } 286 287 @SuppressWarnings("unused") 288 public static final Parcelable.Creator<SavedState> CREATOR = 289 new Parcelable.Creator<SavedState>() { 290 public SavedState createFromParcel(Parcel in) { 291 return new SavedState(in); 292 } 293 294 public SavedState[] newArray(int size) { 295 return new SavedState[size]; 296 } 297 }; 298 } 299} 300