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 android.preference; 18 19import android.content.Context; 20import android.content.res.TypedArray; 21import android.os.Parcel; 22import android.os.Parcelable; 23import android.util.AttributeSet; 24import android.view.KeyEvent; 25import android.view.View; 26import android.widget.SeekBar; 27import android.widget.SeekBar.OnSeekBarChangeListener; 28 29/** 30 * @hide 31 */ 32public 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 public CharSequence getSummary() { 83 return null; 84 } 85 86 @Override 87 protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { 88 setProgress(restoreValue ? getPersistedInt(mProgress) 89 : (Integer) defaultValue); 90 } 91 92 @Override 93 protected Object onGetDefaultValue(TypedArray a, int index) { 94 return a.getInt(index, 0); 95 } 96 97 @Override 98 public boolean onKey(View v, int keyCode, KeyEvent event) { 99 if (event.getAction() != KeyEvent.ACTION_UP) { 100 if (keyCode == KeyEvent.KEYCODE_PLUS 101 || keyCode == KeyEvent.KEYCODE_EQUALS) { 102 setProgress(getProgress() + 1); 103 return true; 104 } 105 if (keyCode == KeyEvent.KEYCODE_MINUS) { 106 setProgress(getProgress() - 1); 107 return true; 108 } 109 } 110 return false; 111 } 112 113 public void setMax(int max) { 114 if (max != mMax) { 115 mMax = max; 116 notifyChanged(); 117 } 118 } 119 120 public void setProgress(int progress) { 121 setProgress(progress, true); 122 } 123 124 private void setProgress(int progress, boolean notifyChanged) { 125 if (progress > mMax) { 126 progress = mMax; 127 } 128 if (progress < 0) { 129 progress = 0; 130 } 131 if (progress != mProgress) { 132 mProgress = progress; 133 persistInt(progress); 134 if (notifyChanged) { 135 notifyChanged(); 136 } 137 } 138 } 139 140 public int getProgress() { 141 return mProgress; 142 } 143 144 /** 145 * Persist the seekBar's progress value if callChangeListener 146 * returns true, otherwise set the seekBar's progress to the stored value 147 */ 148 void syncProgress(SeekBar seekBar) { 149 int progress = seekBar.getProgress(); 150 if (progress != mProgress) { 151 if (callChangeListener(progress)) { 152 setProgress(progress, false); 153 } else { 154 seekBar.setProgress(mProgress); 155 } 156 } 157 } 158 159 @Override 160 public void onProgressChanged( 161 SeekBar seekBar, int progress, boolean fromUser) { 162 if (fromUser && !mTrackingTouch) { 163 syncProgress(seekBar); 164 } 165 } 166 167 @Override 168 public void onStartTrackingTouch(SeekBar seekBar) { 169 mTrackingTouch = true; 170 } 171 172 @Override 173 public void onStopTrackingTouch(SeekBar seekBar) { 174 mTrackingTouch = false; 175 if (seekBar.getProgress() != mProgress) { 176 syncProgress(seekBar); 177 } 178 } 179 180 @Override 181 protected Parcelable onSaveInstanceState() { 182 /* 183 * Suppose a client uses this preference type without persisting. We 184 * must save the instance state so it is able to, for example, survive 185 * orientation changes. 186 */ 187 188 final Parcelable superState = super.onSaveInstanceState(); 189 if (isPersistent()) { 190 // No need to save instance state since it's persistent 191 return superState; 192 } 193 194 // Save the instance state 195 final SavedState myState = new SavedState(superState); 196 myState.progress = mProgress; 197 myState.max = mMax; 198 return myState; 199 } 200 201 @Override 202 protected void onRestoreInstanceState(Parcelable state) { 203 if (!state.getClass().equals(SavedState.class)) { 204 // Didn't save state for us in onSaveInstanceState 205 super.onRestoreInstanceState(state); 206 return; 207 } 208 209 // Restore the instance state 210 SavedState myState = (SavedState) state; 211 super.onRestoreInstanceState(myState.getSuperState()); 212 mProgress = myState.progress; 213 mMax = myState.max; 214 notifyChanged(); 215 } 216 217 /** 218 * SavedState, a subclass of {@link BaseSavedState}, will store the state 219 * of MyPreference, a subclass of Preference. 220 * <p> 221 * It is important to always call through to super methods. 222 */ 223 private static class SavedState extends BaseSavedState { 224 int progress; 225 int max; 226 227 public SavedState(Parcel source) { 228 super(source); 229 230 // Restore the click counter 231 progress = source.readInt(); 232 max = source.readInt(); 233 } 234 235 @Override 236 public void writeToParcel(Parcel dest, int flags) { 237 super.writeToParcel(dest, flags); 238 239 // Save the click counter 240 dest.writeInt(progress); 241 dest.writeInt(max); 242 } 243 244 public SavedState(Parcelable superState) { 245 super(superState); 246 } 247 248 @SuppressWarnings("unused") 249 public static final Parcelable.Creator<SavedState> CREATOR = 250 new Parcelable.Creator<SavedState>() { 251 public SavedState createFromParcel(Parcel in) { 252 return new SavedState(in); 253 } 254 255 public SavedState[] newArray(int size) { 256 return new SavedState[size]; 257 } 258 }; 259 } 260} 261