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 17 package android.preference; 18 19 import android.content.Context; 20 import android.content.res.TypedArray; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.util.AttributeSet; 24 import android.view.KeyEvent; 25 import android.view.View; 26 import android.widget.SeekBar; 27 import android.widget.SeekBar.OnSeekBarChangeListener; 28 29 /** 30 * @hide 31 */ 32 public class SeekBarPreference extends Preference 33 implements OnSeekBarChangeListener { 34 35 private int mProgress; 36 private int mMax; 37 private boolean mTrackingTouch; 38 39 public SeekBarPreference( 40 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 41 super(context, attrs, defStyleAttr, defStyleRes); 42 43 TypedArray a = context.obtainStyledAttributes( 44 attrs, com.android.internal.R.styleable.ProgressBar, defStyleAttr, defStyleRes); 45 setMax(a.getInt(com.android.internal.R.styleable.ProgressBar_max, mMax)); 46 a.recycle(); 47 48 a = context.obtainStyledAttributes(attrs, 49 com.android.internal.R.styleable.SeekBarPreference, defStyleAttr, defStyleRes); 50 final int layoutResId = a.getResourceId( 51 com.android.internal.R.styleable.SeekBarPreference_layout, 52 com.android.internal.R.layout.preference_widget_seekbar); 53 a.recycle(); 54 55 setLayoutResource(layoutResId); 56 } 57 58 public SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) { 59 this(context, attrs, defStyleAttr, 0); 60 } 61 62 public SeekBarPreference(Context context, AttributeSet attrs) { 63 this(context, attrs, com.android.internal.R.attr.seekBarPreferenceStyle); 64 } 65 66 public SeekBarPreference(Context context) { 67 this(context, null); 68 } 69 70 @Override 71 protected void onBindView(View view) { 72 super.onBindView(view); 73 SeekBar seekBar = (SeekBar) view.findViewById( 74 com.android.internal.R.id.seekbar); 75 seekBar.setOnSeekBarChangeListener(this); 76 seekBar.setMax(mMax); 77 seekBar.setProgress(mProgress); 78 seekBar.setEnabled(isEnabled()); 79 } 80 81 @Override 82 protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { 83 setProgress(restoreValue ? getPersistedInt(mProgress) 84 : (Integer) defaultValue); 85 } 86 87 @Override 88 protected Object onGetDefaultValue(TypedArray a, int index) { 89 return a.getInt(index, 0); 90 } 91 92 @Override 93 public boolean onKey(View v, int keyCode, KeyEvent event) { 94 if (event.getAction() != KeyEvent.ACTION_DOWN) { 95 return false; 96 } 97 98 SeekBar seekBar = (SeekBar) v.findViewById(com.android.internal.R.id.seekbar); 99 if (seekBar == null) { 100 return false; 101 } 102 return seekBar.onKeyDown(keyCode, event); 103 } 104 105 public void setMax(int max) { 106 if (max != mMax) { 107 mMax = max; 108 notifyChanged(); 109 } 110 } 111 112 public void setProgress(int progress) { 113 setProgress(progress, true); 114 } 115 116 private void setProgress(int progress, boolean notifyChanged) { 117 if (progress > mMax) { 118 progress = mMax; 119 } 120 if (progress < 0) { 121 progress = 0; 122 } 123 if (progress != mProgress) { 124 mProgress = progress; 125 persistInt(progress); 126 if (notifyChanged) { 127 notifyChanged(); 128 } 129 } 130 } 131 132 public int getProgress() { 133 return mProgress; 134 } 135 136 /** 137 * Persist the seekBar's progress value if callChangeListener 138 * returns true, otherwise set the seekBar's progress to the stored value 139 */ 140 void syncProgress(SeekBar seekBar) { 141 int progress = seekBar.getProgress(); 142 if (progress != mProgress) { 143 if (callChangeListener(progress)) { 144 setProgress(progress, false); 145 } else { 146 seekBar.setProgress(mProgress); 147 } 148 } 149 } 150 151 @Override 152 public void onProgressChanged( 153 SeekBar seekBar, int progress, boolean fromUser) { 154 if (fromUser && !mTrackingTouch) { 155 syncProgress(seekBar); 156 } 157 } 158 159 @Override 160 public void onStartTrackingTouch(SeekBar seekBar) { 161 mTrackingTouch = true; 162 } 163 164 @Override 165 public void onStopTrackingTouch(SeekBar seekBar) { 166 mTrackingTouch = false; 167 if (seekBar.getProgress() != mProgress) { 168 syncProgress(seekBar); 169 } 170 } 171 172 @Override 173 protected Parcelable onSaveInstanceState() { 174 /* 175 * Suppose a client uses this preference type without persisting. We 176 * must save the instance state so it is able to, for example, survive 177 * orientation changes. 178 */ 179 180 final Parcelable superState = super.onSaveInstanceState(); 181 if (isPersistent()) { 182 // No need to save instance state since it's persistent 183 return superState; 184 } 185 186 // Save the instance state 187 final SavedState myState = new SavedState(superState); 188 myState.progress = mProgress; 189 myState.max = mMax; 190 return myState; 191 } 192 193 @Override 194 protected void onRestoreInstanceState(Parcelable state) { 195 if (!state.getClass().equals(SavedState.class)) { 196 // Didn't save state for us in onSaveInstanceState 197 super.onRestoreInstanceState(state); 198 return; 199 } 200 201 // Restore the instance state 202 SavedState myState = (SavedState) state; 203 super.onRestoreInstanceState(myState.getSuperState()); 204 mProgress = myState.progress; 205 mMax = myState.max; 206 notifyChanged(); 207 } 208 209 /** 210 * SavedState, a subclass of {@link BaseSavedState}, will store the state 211 * of MyPreference, a subclass of Preference. 212 * <p> 213 * It is important to always call through to super methods. 214 */ 215 private static class SavedState extends BaseSavedState { 216 int progress; 217 int max; 218 219 public SavedState(Parcel source) { 220 super(source); 221 222 // Restore the click counter 223 progress = source.readInt(); 224 max = source.readInt(); 225 } 226 227 @Override 228 public void writeToParcel(Parcel dest, int flags) { 229 super.writeToParcel(dest, flags); 230 231 // Save the click counter 232 dest.writeInt(progress); 233 dest.writeInt(max); 234 } 235 236 public SavedState(Parcelable superState) { 237 super(superState); 238 } 239 240 @SuppressWarnings("unused") 241 public static final Parcelable.Creator<SavedState> CREATOR = 242 new Parcelable.Creator<SavedState>() { 243 public SavedState createFromParcel(Parcel in) { 244 return new SavedState(in); 245 } 246 247 public SavedState[] newArray(int size) { 248 return new SavedState[size]; 249 } 250 }; 251 } 252 } 253