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 
SeekBarPreference( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)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 
SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr)62     public SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
63         this(context, attrs, defStyleAttr, 0);
64     }
65 
SeekBarPreference(Context context, AttributeSet attrs)66     public SeekBarPreference(Context context, AttributeSet attrs) {
67         this(context, attrs, com.android.internal.R.attr.seekBarPreferenceStyle);
68     }
69 
SeekBarPreference(Context context)70     public SeekBarPreference(Context context) {
71         this(context, null);
72     }
73 
74     @Override
onBindViewHolder(PreferenceViewHolder view)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
getSummary()87     public CharSequence getSummary() {
88         return null;
89     }
90 
91     @Override
onSetInitialValue(boolean restoreValue, Object defaultValue)92     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
93         setProgress(restoreValue ? getPersistedInt(mProgress)
94                 : (Integer) defaultValue);
95     }
96 
97     @Override
onGetDefaultValue(TypedArray a, int index)98     protected Object onGetDefaultValue(TypedArray a, int index) {
99         return a.getInt(index, 0);
100     }
101 
102     @Override
onKey(View v, int keyCode, KeyEvent event)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 
setMax(int max)115     public void setMax(int max) {
116         if (max != mMax) {
117             mMax = max;
118             notifyChanged();
119         }
120     }
121 
setProgress(int progress)122     public void setProgress(int progress) {
123         setProgress(progress, true);
124     }
125 
setProgress(int progress, boolean notifyChanged)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 
getProgress()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      */
syncProgress(SeekBar seekBar)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
onProgressChanged( SeekBar seekBar, int progress, boolean fromUser)162     public void onProgressChanged(
163             SeekBar seekBar, int progress, boolean fromUser) {
164         if (fromUser && !mTrackingTouch) {
165             syncProgress(seekBar);
166         }
167     }
168 
169     @Override
onStartTrackingTouch(SeekBar seekBar)170     public void onStartTrackingTouch(SeekBar seekBar) {
171         mTrackingTouch = true;
172     }
173 
174     @Override
onStopTrackingTouch(SeekBar seekBar)175     public void onStopTrackingTouch(SeekBar seekBar) {
176         mTrackingTouch = false;
177         if (seekBar.getProgress() != mProgress) {
178             syncProgress(seekBar);
179         }
180     }
181 
182     @Override
onSaveInstanceState()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
onRestoreInstanceState(Parcelable state)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 
SavedState(Parcel source)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
writeToParcel(Parcel dest, int flags)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 
SavedState(Parcelable superState)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