0
|
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 de.robv.android.xposed.library.ui;
|
|
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.preference.Preference;
|
|
24 import android.util.AttributeSet;
|
|
25 import android.view.LayoutInflater;
|
|
26 import android.view.View;
|
|
27 import android.view.ViewGroup;
|
|
28 import android.widget.SeekBar;
|
|
29 import android.widget.SeekBar.OnSeekBarChangeListener;
|
|
30 import android.widget.TextView;
|
|
31 import de.robv.android.xposed.library.R;
|
|
32
|
|
33 public class ValueSeekBarPreference extends Preference implements OnSeekBarChangeListener {
|
|
34
|
|
35 private int mProgress;
|
|
36 private int mStep;
|
|
37 private int mMin;
|
|
38 private int mMax;
|
|
39 private String valueDisplayFormat;
|
|
40 private boolean mTrackingTouch;
|
|
41 private TextView tvValue;
|
|
42
|
|
43 public ValueSeekBarPreference(
|
|
44 Context context, AttributeSet attrs, int defStyle) {
|
|
45 super(context, attrs, defStyle);
|
|
46
|
|
47 if (attrs != null) {
|
|
48 setStep(attrs.getAttributeIntValue(null, "step", 1));
|
|
49 setMin(attrs.getAttributeIntValue(null, "min", 0));
|
|
50 setMax(attrs.getAttributeIntValue(null, "max", 100));
|
|
51 valueDisplayFormat = attrs.getAttributeValue(null, "displayFormat");
|
|
52 if (valueDisplayFormat == null)
|
|
53 valueDisplayFormat = "%d";
|
|
54 }
|
|
55 }
|
|
56
|
|
57 public ValueSeekBarPreference(Context context, AttributeSet attrs) {
|
|
58 this(context, attrs, android.R.attr.preferenceStyle);
|
|
59 }
|
|
60
|
|
61 public ValueSeekBarPreference(Context context) {
|
|
62 this(context, null);
|
|
63 }
|
|
64
|
|
65 @Override
|
|
66 protected View onCreateView(ViewGroup parent) {
|
|
67 ViewGroup originalView = (ViewGroup) super.onCreateView(parent);
|
|
68
|
|
69 final LayoutInflater layoutInflater =
|
|
70 (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
71
|
|
72 ViewGroup newlayout = (ViewGroup) layoutInflater.inflate(R.layout.preference_valueseekbar_extension, null);
|
|
73 newlayout.addView(originalView, 0);
|
|
74
|
|
75 tvValue = (TextView) newlayout.findViewById(R.id.valueseekbar_preference_value);
|
|
76
|
|
77 return newlayout;
|
|
78 }
|
|
79
|
|
80 @Override
|
|
81 protected void onBindView(View view) {
|
|
82 super.onBindView(view);
|
|
83 SeekBar seekBar = (SeekBar) view.findViewById(R.id.valueseekbar_preference_seekbar);
|
|
84 seekBar.setOnSeekBarChangeListener(this);
|
|
85 seekBar.setMax((mMax - mMin) / mStep);
|
|
86 seekBar.setProgress((mProgress - mMin) / mStep);
|
|
87 tvValue.setText(String.format(valueDisplayFormat, mProgress));
|
|
88 seekBar.setEnabled(isEnabled());
|
|
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 public void setStep(int step) {
|
|
103 if (step != mStep) {
|
|
104 mStep = step;
|
|
105 notifyChanged();
|
|
106 }
|
|
107 }
|
|
108
|
|
109 public void setMin(int min) {
|
|
110 if (min != mMin) {
|
|
111 mMin = min;
|
|
112 notifyChanged();
|
|
113 }
|
|
114 }
|
|
115
|
|
116 public void setMax(int max) {
|
|
117 if (max != mMax) {
|
|
118 mMax = max;
|
|
119 notifyChanged();
|
|
120 }
|
|
121 }
|
|
122
|
|
123 public void setProgress(int progress) {
|
|
124 setProgress(progress, true);
|
|
125 }
|
|
126
|
|
127 private void setProgress(int progress, boolean notifyChanged) {
|
|
128 if (progress > mMax) {
|
|
129 progress = mMax;
|
|
130 }
|
|
131 if (progress < mMin) {
|
|
132 progress = mMin;
|
|
133 }
|
|
134 if (progress != mProgress) {
|
|
135 mProgress = progress;
|
|
136 persistInt(progress);
|
|
137 if (notifyChanged) {
|
|
138 notifyChanged();
|
|
139 }
|
|
140 }
|
|
141 }
|
|
142
|
|
143 public int getProgress() {
|
|
144 return mProgress;
|
|
145 }
|
|
146
|
|
147 /**
|
|
148 * Persist the seekBar's progress value if callChangeListener
|
|
149 * returns true, otherwise set the seekBar's progress to the stored value
|
|
150 */
|
|
151 void syncProgress(SeekBar seekBar) {
|
|
152 int progress = seekBar.getProgress() * mStep + mMin;
|
|
153 if (progress != mProgress) {
|
|
154 if (callChangeListener(progress)) {
|
|
155 setProgress(progress, false);
|
|
156 } else {
|
|
157 seekBar.setProgress((mProgress - mMin) / mStep);
|
|
158 }
|
|
159 }
|
|
160 }
|
|
161
|
|
162 @Override
|
|
163 public void onProgressChanged(
|
|
164 SeekBar seekBar, int progress, boolean fromUser) {
|
|
165 if (fromUser && !mTrackingTouch) {
|
|
166 syncProgress(seekBar);
|
|
167 }
|
|
168 tvValue.setText(String.format(valueDisplayFormat, progress * mStep + mMin));
|
|
169 }
|
|
170
|
|
171 @Override
|
|
172 public void onStartTrackingTouch(SeekBar seekBar) {
|
|
173 mTrackingTouch = true;
|
|
174 }
|
|
175
|
|
176 @Override
|
|
177 public void onStopTrackingTouch(SeekBar seekBar) {
|
|
178 mTrackingTouch = false;
|
|
179 if (seekBar.getProgress() * mStep + mMin != mProgress) {
|
|
180 syncProgress(seekBar);
|
|
181 }
|
|
182 }
|
|
183
|
|
184 @Override
|
|
185 protected Parcelable onSaveInstanceState() {
|
|
186 /*
|
|
187 * Suppose a client uses this preference type without persisting. We
|
|
188 * must save the instance state so it is able to, for example, survive
|
|
189 * orientation changes.
|
|
190 */
|
|
191
|
|
192 final Parcelable superState = super.onSaveInstanceState();
|
|
193 if (isPersistent()) {
|
|
194 // No need to save instance state since it's persistent
|
|
195 return superState;
|
|
196 }
|
|
197
|
|
198 // Save the instance state
|
|
199 final SavedState myState = new SavedState(superState);
|
|
200 myState.progress = mProgress;
|
|
201 myState.step = mStep;
|
|
202 myState.min = mMin;
|
|
203 myState.max = mMax;
|
|
204 return myState;
|
|
205 }
|
|
206
|
|
207 @Override
|
|
208 protected void onRestoreInstanceState(Parcelable state) {
|
|
209 if (!state.getClass().equals(SavedState.class)) {
|
|
210 // Didn't save state for us in onSaveInstanceState
|
|
211 super.onRestoreInstanceState(state);
|
|
212 return;
|
|
213 }
|
|
214
|
|
215 // Restore the instance state
|
|
216 SavedState myState = (SavedState) state;
|
|
217 super.onRestoreInstanceState(myState.getSuperState());
|
|
218 mProgress = myState.progress;
|
|
219 mStep = myState.step;
|
|
220 mMin = myState.min;
|
|
221 mMax = myState.max;
|
|
222 notifyChanged();
|
|
223 }
|
|
224
|
|
225 /**
|
|
226 * SavedState, a subclass of {@link BaseSavedState}, will store the state
|
|
227 * of MyPreference, a subclass of Preference.
|
|
228 * <p>
|
|
229 * It is important to always call through to super methods.
|
|
230 */
|
|
231 private static class SavedState extends BaseSavedState {
|
|
232 int progress;
|
|
233 int step;
|
|
234 int min;
|
|
235 int max;
|
|
236
|
|
237 public SavedState(Parcel source) {
|
|
238 super(source);
|
|
239
|
|
240 // Restore the click counter
|
|
241 progress = source.readInt();
|
|
242 step = source.readInt();
|
|
243 min = source.readInt();
|
|
244 max = source.readInt();
|
|
245 }
|
|
246
|
|
247 @Override
|
|
248 public void writeToParcel(Parcel dest, int flags) {
|
|
249 super.writeToParcel(dest, flags);
|
|
250
|
|
251 dest.writeInt(progress);
|
|
252 dest.writeInt(step);
|
|
253 dest.writeInt(min);
|
|
254 dest.writeInt(max);
|
|
255 }
|
|
256
|
|
257 public SavedState(Parcelable superState) {
|
|
258 super(superState);
|
|
259 }
|
|
260
|
|
261 @SuppressWarnings("unused")
|
|
262 public static final Parcelable.Creator<SavedState> CREATOR =
|
|
263 new Parcelable.Creator<SavedState>() {
|
|
264 public SavedState createFromParcel(Parcel in) {
|
|
265 return new SavedState(in);
|
|
266 }
|
|
267
|
|
268 public SavedState[] newArray(int size) {
|
|
269 return new SavedState[size];
|
|
270 }
|
|
271 };
|
|
272 }
|
|
273 }
|