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