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