• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.widget;
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.v4.content.res.TypedArrayUtils;
24 import android.support.v7.preference.PreferenceViewHolder;
25 import android.text.TextUtils;
26 import android.util.AttributeSet;
27 import android.view.KeyEvent;
28 import android.view.View;
29 import android.widget.SeekBar;
30 import android.widget.SeekBar.OnSeekBarChangeListener;
31 
32 import com.android.settings.widget.DefaultIndicatorSeekBar;
33 import com.android.settingslib.RestrictedPreference;
34 
35 /**
36  * Based on android.preference.SeekBarPreference, but uses support preference as base.
37  */
38 public class SeekBarPreference extends RestrictedPreference
39         implements OnSeekBarChangeListener, View.OnKeyListener {
40 
41     private int mProgress;
42     private int mMax;
43     private boolean mTrackingTouch;
44 
45     private boolean mContinuousUpdates;
46     private int mDefaultProgress = -1;
47 
48     private SeekBar mSeekBar;
49     private boolean mShouldBlink;
50 
SeekBarPreference( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)51     public SeekBarPreference(
52             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
53         super(context, attrs, defStyleAttr, defStyleRes);
54 
55         TypedArray a = context.obtainStyledAttributes(
56                 attrs, com.android.internal.R.styleable.ProgressBar, defStyleAttr, defStyleRes);
57         setMax(a.getInt(com.android.internal.R.styleable.ProgressBar_max, mMax));
58         a.recycle();
59 
60         a = context.obtainStyledAttributes(attrs,
61                 com.android.internal.R.styleable.SeekBarPreference, defStyleAttr, defStyleRes);
62         final int layoutResId = a.getResourceId(
63                 com.android.internal.R.styleable.SeekBarPreference_layout,
64                 com.android.internal.R.layout.preference_widget_seekbar);
65         a.recycle();
66 
67         setLayoutResource(layoutResId);
68     }
69 
SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr)70     public SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
71         this(context, attrs, defStyleAttr, 0);
72     }
73 
SeekBarPreference(Context context, AttributeSet attrs)74     public SeekBarPreference(Context context, AttributeSet attrs) {
75         this(context, attrs, TypedArrayUtils.getAttr(context,
76                         android.support.v7.preference.R.attr.seekBarPreferenceStyle,
77                         com.android.internal.R.attr.seekBarPreferenceStyle));
78     }
79 
SeekBarPreference(Context context)80     public SeekBarPreference(Context context) {
81         this(context, null);
82     }
83 
setShouldBlink(boolean shouldBlink)84     public void setShouldBlink(boolean shouldBlink) {
85         mShouldBlink = shouldBlink;
86         notifyChanged();
87     }
88 
89     @Override
onBindViewHolder(PreferenceViewHolder view)90     public void onBindViewHolder(PreferenceViewHolder view) {
91         super.onBindViewHolder(view);
92         view.itemView.setOnKeyListener(this);
93         mSeekBar = (SeekBar) view.findViewById(
94                 com.android.internal.R.id.seekbar);
95         mSeekBar.setOnSeekBarChangeListener(this);
96         mSeekBar.setMax(mMax);
97         mSeekBar.setProgress(mProgress);
98         mSeekBar.setEnabled(isEnabled());
99         final CharSequence title = getTitle();
100         if (!TextUtils.isEmpty(title)) {
101             mSeekBar.setContentDescription(title);
102         }
103         if (mSeekBar instanceof DefaultIndicatorSeekBar) {
104             ((DefaultIndicatorSeekBar) mSeekBar).setDefaultProgress(mDefaultProgress);
105         }
106         if (mShouldBlink) {
107             View v = view.itemView;
108             v.post(() -> {
109                 if (v.getBackground() != null) {
110                     final int centerX = v.getWidth() / 2;
111                     final int centerY = v.getHeight() / 2;
112                     v.getBackground().setHotspot(centerX, centerY);
113                 }
114                 v.setPressed(true);
115                 v.setPressed(false);
116                 mShouldBlink = false;
117             });
118         }
119     }
120 
121     @Override
getSummary()122     public CharSequence getSummary() {
123         return null;
124     }
125 
126     @Override
onSetInitialValue(boolean restoreValue, Object defaultValue)127     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
128         setProgress(restoreValue ? getPersistedInt(mProgress)
129                 : (Integer) defaultValue);
130     }
131 
132     @Override
onGetDefaultValue(TypedArray a, int index)133     protected Object onGetDefaultValue(TypedArray a, int index) {
134         return a.getInt(index, 0);
135     }
136 
137     @Override
onKey(View v, int keyCode, KeyEvent event)138     public boolean onKey(View v, int keyCode, KeyEvent event) {
139         if (event.getAction() != KeyEvent.ACTION_DOWN) {
140             return false;
141         }
142 
143         SeekBar seekBar = (SeekBar) v.findViewById(com.android.internal.R.id.seekbar);
144         if (seekBar == null) {
145             return false;
146         }
147         return seekBar.onKeyDown(keyCode, event);
148     }
149 
setMax(int max)150     public void setMax(int max) {
151         if (max != mMax) {
152             mMax = max;
153             notifyChanged();
154         }
155     }
156 
getMax()157     public int getMax() {
158         return mMax;
159     }
160 
setProgress(int progress)161     public void setProgress(int progress) {
162         setProgress(progress, true);
163     }
164 
165     /**
166      * Sets the progress point to draw a single tick mark representing a default value.
167      */
setDefaultProgress(int defaultProgress)168     public void setDefaultProgress(int defaultProgress) {
169         if (mDefaultProgress != defaultProgress) {
170             mDefaultProgress = defaultProgress;
171             if (mSeekBar instanceof DefaultIndicatorSeekBar) {
172                 ((DefaultIndicatorSeekBar) mSeekBar).setDefaultProgress(mDefaultProgress);
173             }
174         }
175     }
176 
177     /**
178      * When {@code continuousUpdates} is true, update the persisted setting immediately as the thumb
179      * is dragged along the SeekBar. Otherwise, only update the value of the setting when the thumb
180      * is dropped.
181      */
setContinuousUpdates(boolean continuousUpdates)182     public void setContinuousUpdates(boolean continuousUpdates) {
183         mContinuousUpdates = continuousUpdates;
184     }
185 
setProgress(int progress, boolean notifyChanged)186     private void setProgress(int progress, boolean notifyChanged) {
187         if (progress > mMax) {
188             progress = mMax;
189         }
190         if (progress < 0) {
191             progress = 0;
192         }
193         if (progress != mProgress) {
194             mProgress = progress;
195             persistInt(progress);
196             if (notifyChanged) {
197                 notifyChanged();
198             }
199         }
200     }
201 
getProgress()202     public int getProgress() {
203         return mProgress;
204     }
205 
206     /**
207      * Persist the seekBar's progress value if callChangeListener
208      * returns true, otherwise set the seekBar's progress to the stored value
209      */
syncProgress(SeekBar seekBar)210     void syncProgress(SeekBar seekBar) {
211         int progress = seekBar.getProgress();
212         if (progress != mProgress) {
213             if (callChangeListener(progress)) {
214                 setProgress(progress, false);
215             } else {
216                 seekBar.setProgress(mProgress);
217             }
218         }
219     }
220 
221     @Override
onProgressChanged( SeekBar seekBar, int progress, boolean fromUser)222     public void onProgressChanged(
223             SeekBar seekBar, int progress, boolean fromUser) {
224         if (fromUser && (mContinuousUpdates || !mTrackingTouch)) {
225             syncProgress(seekBar);
226         }
227     }
228 
229     @Override
onStartTrackingTouch(SeekBar seekBar)230     public void onStartTrackingTouch(SeekBar seekBar) {
231         mTrackingTouch = true;
232     }
233 
234     @Override
onStopTrackingTouch(SeekBar seekBar)235     public void onStopTrackingTouch(SeekBar seekBar) {
236         mTrackingTouch = false;
237         if (seekBar.getProgress() != mProgress) {
238             syncProgress(seekBar);
239         }
240     }
241 
242     @Override
onSaveInstanceState()243     protected Parcelable onSaveInstanceState() {
244         /*
245          * Suppose a client uses this preference type without persisting. We
246          * must save the instance state so it is able to, for example, survive
247          * orientation changes.
248          */
249 
250         final Parcelable superState = super.onSaveInstanceState();
251         if (isPersistent()) {
252             // No need to save instance state since it's persistent
253             return superState;
254         }
255 
256         // Save the instance state
257         final SavedState myState = new SavedState(superState);
258         myState.progress = mProgress;
259         myState.max = mMax;
260         return myState;
261     }
262 
263     @Override
onRestoreInstanceState(Parcelable state)264     protected void onRestoreInstanceState(Parcelable state) {
265         if (!state.getClass().equals(SavedState.class)) {
266             // Didn't save state for us in onSaveInstanceState
267             super.onRestoreInstanceState(state);
268             return;
269         }
270 
271         // Restore the instance state
272         SavedState myState = (SavedState) state;
273         super.onRestoreInstanceState(myState.getSuperState());
274         mProgress = myState.progress;
275         mMax = myState.max;
276         notifyChanged();
277     }
278 
279     /**
280      * SavedState, a subclass of {@link BaseSavedState}, will store the state
281      * of MyPreference, a subclass of Preference.
282      * <p>
283      * It is important to always call through to super methods.
284      */
285     private static class SavedState extends BaseSavedState {
286         int progress;
287         int max;
288 
SavedState(Parcel source)289         public SavedState(Parcel source) {
290             super(source);
291 
292             // Restore the click counter
293             progress = source.readInt();
294             max = source.readInt();
295         }
296 
297         @Override
writeToParcel(Parcel dest, int flags)298         public void writeToParcel(Parcel dest, int flags) {
299             super.writeToParcel(dest, flags);
300 
301             // Save the click counter
302             dest.writeInt(progress);
303             dest.writeInt(max);
304         }
305 
SavedState(Parcelable superState)306         public SavedState(Parcelable superState) {
307             super(superState);
308         }
309 
310         @SuppressWarnings("unused")
311         public static final Parcelable.Creator<SavedState> CREATOR =
312                 new Parcelable.Creator<SavedState>() {
313             public SavedState createFromParcel(Parcel in) {
314                 return new SavedState(in);
315             }
316 
317             public SavedState[] newArray(int size) {
318                 return new SavedState[size];
319             }
320         };
321     }
322 }
323