blob: 9a6859387bdfad13199a96cc6236fb8dd78a27f9 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2007 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
17package android.widget;
18
Alan Viverette9c17c852015-12-08 13:23:58 -050019import com.android.internal.R;
20
Alan Viverette91174362014-06-17 14:51:45 -070021import android.annotation.Nullable;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070022import android.content.Context;
Alan Viverette91174362014-06-17 14:51:45 -070023import android.content.res.ColorStateList;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070024import android.content.res.TypedArray;
25import android.graphics.Canvas;
Alan Viverette661e6362014-05-12 10:55:37 -070026import android.graphics.Insets;
Alan Viverette91174362014-06-17 14:51:45 -070027import android.graphics.PorterDuff;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070028import android.graphics.Rect;
Alan Viverette661e6362014-05-12 10:55:37 -070029import android.graphics.Region.Op;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070030import android.graphics.drawable.Drawable;
alanvc826b7d2012-05-16 14:19:21 -070031import android.os.Bundle;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070032import android.util.AttributeSet;
The Android Open Source Projectb7986892009-01-09 17:51:23 -080033import android.view.KeyEvent;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070034import android.view.MotionEvent;
Adam Powell10298662011-08-14 18:26:30 -070035import android.view.ViewConfiguration;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -080036import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070037
38public abstract class AbsSeekBar extends ProgressBar {
Alan Viverette661e6362014-05-12 10:55:37 -070039 private final Rect mTempRect = new Rect();
40
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070041 private Drawable mThumb;
Alan Viverettea4264452014-07-28 16:02:55 -070042 private ColorStateList mThumbTintList = null;
Alan Viveretteb56f5d22014-09-14 15:48:50 -070043 private PorterDuff.Mode mThumbTintMode = null;
Alan Viverette91174362014-06-17 14:51:45 -070044 private boolean mHasThumbTint = false;
Alan Viveretteb56f5d22014-09-14 15:48:50 -070045 private boolean mHasThumbTintMode = false;
Alan Viverette91174362014-06-17 14:51:45 -070046
Alan Viverette41a90672016-01-07 16:35:40 -050047 private Drawable mTickMark;
48 private ColorStateList mTickMarkTintList = null;
49 private PorterDuff.Mode mTickMarkTintMode = null;
50 private boolean mHasTickMarkTint = false;
51 private boolean mHasTickMarkTintMode = false;
52
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070053 private int mThumbOffset;
Alan Viverette661e6362014-05-12 10:55:37 -070054 private boolean mSplitTrack;
55
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070056 /**
57 * On touch, this offset plus the scaled value from the position of the
58 * touch will form the progress value. Usually 0.
59 */
60 float mTouchProgressOffset;
61
62 /**
63 * Whether this is user seekable.
64 */
65 boolean mIsUserSeekable = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066
67 /**
68 * On key presses (right or left), the amount to increment/decrement the
69 * progress.
70 */
71 private int mKeyProgressIncrement = 1;
Alan Viverette661e6362014-05-12 10:55:37 -070072
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070073 private static final int NO_ALPHA = 0xFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 private float mDisabledAlpha;
Alan Viverette661e6362014-05-12 10:55:37 -070075
Adam Powell10298662011-08-14 18:26:30 -070076 private int mScaledTouchSlop;
77 private float mTouchDownX;
78 private boolean mIsDragging;
79
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070080 public AbsSeekBar(Context context) {
81 super(context);
82 }
83
84 public AbsSeekBar(Context context, AttributeSet attrs) {
85 super(context, attrs);
86 }
87
Alan Viverette617feb92013-09-09 18:09:13 -070088 public AbsSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
89 this(context, attrs, defStyleAttr, 0);
90 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070091
Alan Viverette617feb92013-09-09 18:09:13 -070092 public AbsSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
93 super(context, attrs, defStyleAttr, defStyleRes);
94
Alan Viverette87e19382015-05-29 15:12:14 -070095 final TypedArray a = context.obtainStyledAttributes(
96 attrs, R.styleable.SeekBar, defStyleAttr, defStyleRes);
Alan Viverette661e6362014-05-12 10:55:37 -070097
Alan Viverette87e19382015-05-29 15:12:14 -070098 final Drawable thumb = a.getDrawable(R.styleable.SeekBar_thumb);
Alan Viverette661e6362014-05-12 10:55:37 -070099 setThumb(thumb);
100
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700101 if (a.hasValue(R.styleable.SeekBar_thumbTintMode)) {
102 mThumbTintMode = Drawable.parseTintMode(a.getInt(
103 R.styleable.SeekBar_thumbTintMode, -1), mThumbTintMode);
104 mHasThumbTintMode = true;
105 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700106
Alan Viverette91174362014-06-17 14:51:45 -0700107 if (a.hasValue(R.styleable.SeekBar_thumbTint)) {
Alan Viverettea4264452014-07-28 16:02:55 -0700108 mThumbTintList = a.getColorStateList(R.styleable.SeekBar_thumbTint);
Alan Viverette91174362014-06-17 14:51:45 -0700109 mHasThumbTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700110 }
111
Alan Viverette41a90672016-01-07 16:35:40 -0500112 final Drawable tickMark = a.getDrawable(R.styleable.SeekBar_tickMark);
113 setTickMark(tickMark);
114
115 if (a.hasValue(R.styleable.SeekBar_tickMarkTintMode)) {
116 mTickMarkTintMode = Drawable.parseTintMode(a.getInt(
117 R.styleable.SeekBar_tickMarkTintMode, -1), mTickMarkTintMode);
118 mHasTickMarkTintMode = true;
119 }
120
121 if (a.hasValue(R.styleable.SeekBar_tickMarkTint)) {
122 mTickMarkTintList = a.getColorStateList(R.styleable.SeekBar_tickMarkTint);
123 mHasTickMarkTint = true;
124 }
125
Alan Viverette87e19382015-05-29 15:12:14 -0700126 mSplitTrack = a.getBoolean(R.styleable.SeekBar_splitTrack, false);
127
Alan Viverette661e6362014-05-12 10:55:37 -0700128 // Guess thumb offset if thumb != null, but allow layout to override.
Alan Viverette41a90672016-01-07 16:35:40 -0500129 final int thumbOffset = a.getDimensionPixelOffset(
130 R.styleable.SeekBar_thumbOffset, getThumbOffset());
Romain Guy992cc422010-01-04 15:39:40 -0800131 setThumbOffset(thumbOffset);
Alan Viverette661e6362014-05-12 10:55:37 -0700132
Alan Viverette87e19382015-05-29 15:12:14 -0700133 final boolean useDisabledAlpha = a.getBoolean(R.styleable.SeekBar_useDisabledAlpha, true);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700134 a.recycle();
135
Alan Viverette87e19382015-05-29 15:12:14 -0700136 if (useDisabledAlpha) {
137 final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.Theme, 0, 0);
138 mDisabledAlpha = ta.getFloat(R.styleable.Theme_disabledAlpha, 0.5f);
139 ta.recycle();
140 } else {
141 mDisabledAlpha = 1.0f;
142 }
Adam Powell10298662011-08-14 18:26:30 -0700143
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700144 applyThumbTint();
Alan Viveretted154a5b2016-01-13 10:10:22 -0500145 applyTickMarkTint();
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700146
Adam Powell10298662011-08-14 18:26:30 -0700147 mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700148 }
149
150 /**
Daniel Sandler8d28c3b2009-08-20 13:34:02 -0400151 * Sets the thumb that will be drawn at the end of the progress meter within the SeekBar.
152 * <p>
153 * If the thumb is a valid drawable (i.e. not null), half its width will be
154 * used as the new thumb offset (@see #setThumbOffset(int)).
Alan Viverette661e6362014-05-12 10:55:37 -0700155 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700156 * @param thumb Drawable representing the thumb
157 */
158 public void setThumb(Drawable thumb) {
Alan Viverette91174362014-06-17 14:51:45 -0700159 final boolean needUpdate;
Joe Onorato2e585f72010-12-02 14:10:57 -0800160 // This way, calling setThumb again with the same bitmap will result in
161 // it recalcuating mThumbOffset (if for example it the bounds of the
162 // drawable changed)
163 if (mThumb != null && thumb != mThumb) {
164 mThumb.setCallback(null);
165 needUpdate = true;
166 } else {
167 needUpdate = false;
168 }
Alan Viverette91174362014-06-17 14:51:45 -0700169
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700170 if (thumb != null) {
171 thumb.setCallback(this);
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700172 if (canResolveLayoutDirection()) {
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700173 thumb.setLayoutDirection(getLayoutDirection());
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700174 }
Daniel Sandler8d28c3b2009-08-20 13:34:02 -0400175
176 // Assuming the thumb drawable is symmetric, set the thumb offset
177 // such that the thumb will hang halfway off either edge of the
178 // progress bar.
Romain Guy992cc422010-01-04 15:39:40 -0800179 mThumbOffset = thumb.getIntrinsicWidth() / 2;
Joe Onorato2e585f72010-12-02 14:10:57 -0800180
181 // If we're updating get the new states
182 if (needUpdate &&
183 (thumb.getIntrinsicWidth() != mThumb.getIntrinsicWidth()
184 || thumb.getIntrinsicHeight() != mThumb.getIntrinsicHeight())) {
185 requestLayout();
186 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700187 }
Alan Viverette91174362014-06-17 14:51:45 -0700188
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700189 mThumb = thumb;
Alan Viverette91174362014-06-17 14:51:45 -0700190
191 applyThumbTint();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700192 invalidate();
Alan Viverette91174362014-06-17 14:51:45 -0700193
Joe Onorato2e585f72010-12-02 14:10:57 -0800194 if (needUpdate) {
Alan Viverette661e6362014-05-12 10:55:37 -0700195 updateThumbAndTrackPos(getWidth(), getHeight());
Adam Powell0283a552012-04-19 09:58:22 -0700196 if (thumb != null && thumb.isStateful()) {
Joe Onorato2e585f72010-12-02 14:10:57 -0800197 // Note that if the states are different this won't work.
198 // For now, let's consider that an app bug.
199 int[] state = getDrawableState();
200 thumb.setState(state);
201 }
202 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700203 }
204
205 /**
Adam Powell3004cc52012-03-21 17:50:51 -0700206 * Return the drawable used to represent the scroll thumb - the component that
207 * the user can drag back and forth indicating the current value by its position.
208 *
209 * @return The current thumb drawable
210 */
211 public Drawable getThumb() {
212 return mThumb;
213 }
214
215 /**
Alan Viverette91174362014-06-17 14:51:45 -0700216 * Applies a tint to the thumb drawable. Does not modify the current tint
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700217 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Alan Viverette91174362014-06-17 14:51:45 -0700218 * <p>
219 * Subsequent calls to {@link #setThumb(Drawable)} will automatically
220 * mutate the drawable and apply the specified tint and tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700221 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -0700222 *
223 * @param tint the tint to apply, may be {@code null} to clear tint
224 *
225 * @attr ref android.R.styleable#SeekBar_thumbTint
Alan Viverettea4264452014-07-28 16:02:55 -0700226 * @see #getThumbTintList()
227 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700228 */
Alan Viverettea4264452014-07-28 16:02:55 -0700229 public void setThumbTintList(@Nullable ColorStateList tint) {
230 mThumbTintList = tint;
Alan Viverette4f64c042014-07-21 17:49:13 -0700231 mHasThumbTint = true;
232
233 applyThumbTint();
Alan Viverette91174362014-06-17 14:51:45 -0700234 }
235
236 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700237 * Returns the tint applied to the thumb drawable, if specified.
238 *
Alan Viverette91174362014-06-17 14:51:45 -0700239 * @return the tint applied to the thumb drawable
240 * @attr ref android.R.styleable#SeekBar_thumbTint
Alan Viverettea4264452014-07-28 16:02:55 -0700241 * @see #setThumbTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700242 */
243 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -0700244 public ColorStateList getThumbTintList() {
245 return mThumbTintList;
Alan Viverette91174362014-06-17 14:51:45 -0700246 }
247
248 /**
249 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -0700250 * {@link #setThumbTintList(ColorStateList)}} to the thumb drawable. The
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700251 * default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -0700252 *
253 * @param tintMode the blending mode used to apply the tint, may be
254 * {@code null} to clear tint
Alan Viverette4f64c042014-07-21 17:49:13 -0700255 *
Alan Viverette91174362014-06-17 14:51:45 -0700256 * @attr ref android.R.styleable#SeekBar_thumbTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -0700257 * @see #getThumbTintMode()
Alan Viverettea4264452014-07-28 16:02:55 -0700258 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700259 */
260 public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
Alan Viverette4f64c042014-07-21 17:49:13 -0700261 mThumbTintMode = tintMode;
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700262 mHasThumbTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700263
264 applyThumbTint();
Alan Viverette91174362014-06-17 14:51:45 -0700265 }
266
267 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700268 * Returns the blending mode used to apply the tint to the thumb drawable,
269 * if specified.
270 *
Alan Viverette91174362014-06-17 14:51:45 -0700271 * @return the blending mode used to apply the tint to the thumb drawable
272 * @attr ref android.R.styleable#SeekBar_thumbTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -0700273 * @see #setThumbTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700274 */
275 @Nullable
276 public PorterDuff.Mode getThumbTintMode() {
277 return mThumbTintMode;
278 }
279
280 private void applyThumbTint() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700281 if (mThumb != null && (mHasThumbTint || mHasThumbTintMode)) {
Alan Viverette91174362014-06-17 14:51:45 -0700282 mThumb = mThumb.mutate();
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700283
284 if (mHasThumbTint) {
285 mThumb.setTintList(mThumbTintList);
286 }
287
288 if (mHasThumbTintMode) {
289 mThumb.setTintMode(mThumbTintMode);
290 }
Alan Viveretted5133792014-10-28 14:41:36 -0700291
292 // The drawable (or one of its children) may not have been
293 // stateful before applying the tint, so let's try again.
294 if (mThumb.isStateful()) {
295 mThumb.setState(getDrawableState());
296 }
Alan Viverette91174362014-06-17 14:51:45 -0700297 }
298 }
299
300 /**
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700301 * @see #setThumbOffset(int)
302 */
303 public int getThumbOffset() {
304 return mThumbOffset;
305 }
306
307 /**
308 * Sets the thumb offset that allows the thumb to extend out of the range of
309 * the track.
Alan Viverette661e6362014-05-12 10:55:37 -0700310 *
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700311 * @param thumbOffset The offset amount in pixels.
312 */
313 public void setThumbOffset(int thumbOffset) {
314 mThumbOffset = thumbOffset;
315 invalidate();
316 }
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 /**
Alan Viverette661e6362014-05-12 10:55:37 -0700319 * Specifies whether the track should be split by the thumb. When true,
320 * the thumb's optical bounds will be clipped out of the track drawable,
321 * then the thumb will be drawn into the resulting gap.
322 *
323 * @param splitTrack Whether the track should be split by the thumb
324 */
325 public void setSplitTrack(boolean splitTrack) {
326 mSplitTrack = splitTrack;
327 invalidate();
328 }
329
330 /**
331 * Returns whether the track should be split by the thumb.
332 */
333 public boolean getSplitTrack() {
334 return mSplitTrack;
335 }
336
337 /**
Alan Viverette41a90672016-01-07 16:35:40 -0500338 * Sets the drawable displayed at each progress position, e.g. at each
339 * possible thumb position.
340 *
341 * @param tickMark the drawable to display at each progress position
342 */
343 public void setTickMark(Drawable tickMark) {
344 if (mTickMark != null) {
345 mTickMark.setCallback(null);
346 }
347
348 mTickMark = tickMark;
349
350 if (tickMark != null) {
351 tickMark.setCallback(this);
352 tickMark.setLayoutDirection(getLayoutDirection());
353 if (tickMark.isStateful()) {
354 tickMark.setState(getDrawableState());
355 }
356 applyTickMarkTint();
357 }
358
359 invalidate();
360 }
361
362 /**
363 * @return the drawable displayed at each progress position
364 */
365 public Drawable getTickMark() {
366 return mTickMark;
367 }
368
369 /**
370 * Applies a tint to the tick mark drawable. Does not modify the current tint
371 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
372 * <p>
373 * Subsequent calls to {@link #setTickMark(Drawable)} will automatically
374 * mutate the drawable and apply the specified tint and tint mode using
375 * {@link Drawable#setTintList(ColorStateList)}.
376 *
377 * @param tint the tint to apply, may be {@code null} to clear tint
378 *
379 * @attr ref android.R.styleable#SeekBar_tickMarkTint
380 * @see #getTickMarkTintList()
381 * @see Drawable#setTintList(ColorStateList)
382 */
383 public void setTickMarkTintList(@Nullable ColorStateList tint) {
384 mTickMarkTintList = tint;
385 mHasTickMarkTint = true;
386
387 applyTickMarkTint();
388 }
389
390 /**
391 * Returns the tint applied to the tick mark drawable, if specified.
392 *
393 * @return the tint applied to the tick mark drawable
394 * @attr ref android.R.styleable#SeekBar_tickMarkTint
395 * @see #setTickMarkTintList(ColorStateList)
396 */
397 @Nullable
398 public ColorStateList getTickMarkTintList() {
399 return mTickMarkTintList;
400 }
401
402 /**
403 * Specifies the blending mode used to apply the tint specified by
404 * {@link #setTickMarkTintList(ColorStateList)}} to the tick mark drawable. The
405 * default mode is {@link PorterDuff.Mode#SRC_IN}.
406 *
407 * @param tintMode the blending mode used to apply the tint, may be
408 * {@code null} to clear tint
409 *
410 * @attr ref android.R.styleable#SeekBar_tickMarkTintMode
411 * @see #getTickMarkTintMode()
412 * @see Drawable#setTintMode(PorterDuff.Mode)
413 */
414 public void setTickMarkTintMode(@Nullable PorterDuff.Mode tintMode) {
415 mTickMarkTintMode = tintMode;
416 mHasTickMarkTintMode = true;
417
418 applyTickMarkTint();
419 }
420
421 /**
422 * Returns the blending mode used to apply the tint to the tick mark drawable,
423 * if specified.
424 *
425 * @return the blending mode used to apply the tint to the tick mark drawable
426 * @attr ref android.R.styleable#SeekBar_tickMarkTintMode
427 * @see #setTickMarkTintMode(PorterDuff.Mode)
428 */
429 @Nullable
430 public PorterDuff.Mode getTickMarkTintMode() {
431 return mTickMarkTintMode;
432 }
433
434 private void applyTickMarkTint() {
435 if (mTickMark != null && (mHasTickMarkTint || mHasTickMarkTintMode)) {
436 mTickMark = mTickMark.mutate();
437
438 if (mHasTickMarkTint) {
439 mTickMark.setTintList(mTickMarkTintList);
440 }
441
442 if (mHasTickMarkTintMode) {
443 mTickMark.setTintMode(mTickMarkTintMode);
444 }
445
446 // The drawable (or one of its children) may not have been
447 // stateful before applying the tint, so let's try again.
448 if (mTickMark.isStateful()) {
449 mTickMark.setState(getDrawableState());
450 }
451 }
452 }
453
454 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 * Sets the amount of progress changed via the arrow keys.
Alan Viverette661e6362014-05-12 10:55:37 -0700456 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 * @param increment The amount to increment or decrement when the user
458 * presses the arrow keys.
459 */
460 public void setKeyProgressIncrement(int increment) {
461 mKeyProgressIncrement = increment < 0 ? -increment : increment;
462 }
463
464 /**
465 * Returns the amount of progress changed via the arrow keys.
466 * <p>
467 * By default, this will be a value that is derived from the max progress.
Alan Viverette661e6362014-05-12 10:55:37 -0700468 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 * @return The amount to increment or decrement when the user presses the
470 * arrow keys. This will be positive.
471 */
472 public int getKeyProgressIncrement() {
473 return mKeyProgressIncrement;
474 }
Alan Viverette661e6362014-05-12 10:55:37 -0700475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 @Override
477 public synchronized void setMax(int max) {
478 super.setMax(max);
479
480 if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
481 // It will take the user too long to change this via keys, change it
482 // to something more reasonable
483 setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
484 }
485 }
486
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700487 @Override
488 protected boolean verifyDrawable(Drawable who) {
Alan Viverette41a90672016-01-07 16:35:40 -0500489 return who == mThumb || who == mTickMark || super.verifyDrawable(who);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700490 }
491
492 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -0700493 public void jumpDrawablesToCurrentState() {
494 super.jumpDrawablesToCurrentState();
Alan Viverette8de14942014-06-18 18:05:15 -0700495
496 if (mThumb != null) {
497 mThumb.jumpToCurrentState();
498 }
Alan Viverette41a90672016-01-07 16:35:40 -0500499
500 if (mTickMark != null) {
501 mTickMark.jumpToCurrentState();
502 }
Dianne Hackborne2136772010-11-04 15:08:59 -0700503 }
504
505 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700506 protected void drawableStateChanged() {
507 super.drawableStateChanged();
Alan Viverette661e6362014-05-12 10:55:37 -0700508
509 final Drawable progressDrawable = getProgressDrawable();
Alan Viverette87e19382015-05-29 15:12:14 -0700510 if (progressDrawable != null && mDisabledAlpha < 1.0f) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700511 progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
512 }
Alan Viverette661e6362014-05-12 10:55:37 -0700513
514 final Drawable thumb = mThumb;
Alan Viverettead0020f2015-09-04 10:10:42 -0400515 if (thumb != null && thumb.isStateful()
516 && thumb.setState(getDrawableState())) {
517 invalidateDrawable(thumb);
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800518 }
Alan Viverette41a90672016-01-07 16:35:40 -0500519
520 final Drawable tickMark = mTickMark;
521 if (tickMark != null && tickMark.isStateful()
522 && tickMark.setState(getDrawableState())) {
523 invalidateDrawable(tickMark);
524 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700525 }
Alan Viverette661e6362014-05-12 10:55:37 -0700526
Alan Viverettecebc6ba2014-06-13 15:52:13 -0700527 @Override
Alan Viverette8de14942014-06-18 18:05:15 -0700528 public void drawableHotspotChanged(float x, float y) {
529 super.drawableHotspotChanged(x, y);
Alan Viverettecebc6ba2014-06-13 15:52:13 -0700530
Alan Viverette8de14942014-06-18 18:05:15 -0700531 if (mThumb != null) {
532 mThumb.setHotspot(x, y);
Alan Viverette2356c5e2014-05-22 22:43:59 -0700533 }
534 }
535
536 @Override
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400537 void onVisualProgressChanged(int id, float scale) {
538 super.onVisualProgressChanged(id, scale);
Alan Viverette661e6362014-05-12 10:55:37 -0700539
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400540 if (id == R.id.progress) {
541 final Drawable thumb = mThumb;
542 if (thumb != null) {
543 setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
Alan Viverette661e6362014-05-12 10:55:37 -0700544
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400545 // Since we draw translated, the drawable's bounds that it signals
546 // for invalidation won't be the actual bounds we want invalidated,
547 // so just invalidate this whole view.
548 invalidate();
549 }
Alan Viverette5ce0ec02014-11-25 09:40:54 -0800550 }
Jon Miranda0c11a482014-07-21 14:55:29 -0700551 }
552
553 @Override
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700554 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Fabrice Di Megliof37df1b2012-10-15 19:10:08 -0700555 super.onSizeChanged(w, h, oldw, oldh);
Alan Viverette661e6362014-05-12 10:55:37 -0700556
557 updateThumbAndTrackPos(w, h);
Joe Onorato2e585f72010-12-02 14:10:57 -0800558 }
559
Alan Viverette661e6362014-05-12 10:55:37 -0700560 private void updateThumbAndTrackPos(int w, int h) {
Alan Viverette3afd8b02015-02-26 13:36:28 -0800561 final int paddedHeight = h - mPaddingTop - mPaddingBottom;
Alan Viverette661e6362014-05-12 10:55:37 -0700562 final Drawable track = getCurrentDrawable();
563 final Drawable thumb = mThumb;
564
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700565 // The max height does not incorporate padding, whereas the height
Alan Viverette661e6362014-05-12 10:55:37 -0700566 // parameter does.
Alan Viverette3afd8b02015-02-26 13:36:28 -0800567 final int trackHeight = Math.min(mMaxHeight, paddedHeight);
Alan Viverette661e6362014-05-12 10:55:37 -0700568 final int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
569
570 // Apply offset to whichever item is taller.
571 final int trackOffset;
572 final int thumbOffset;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700573 if (thumbHeight > trackHeight) {
Alan Viverette3afd8b02015-02-26 13:36:28 -0800574 final int offsetHeight = (paddedHeight - thumbHeight) / 2;
575 trackOffset = offsetHeight + (thumbHeight - trackHeight) / 2;
Alan Viverette9c17c852015-12-08 13:23:58 -0500576 thumbOffset = offsetHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700577 } else {
Alan Viverette3afd8b02015-02-26 13:36:28 -0800578 final int offsetHeight = (paddedHeight - trackHeight) / 2;
Alan Viverette9c17c852015-12-08 13:23:58 -0500579 trackOffset = offsetHeight;
Alan Viverette3afd8b02015-02-26 13:36:28 -0800580 thumbOffset = offsetHeight + (trackHeight - thumbHeight) / 2;
Alan Viverette661e6362014-05-12 10:55:37 -0700581 }
582
583 if (track != null) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800584 final int trackWidth = w - mPaddingRight - mPaddingLeft;
585 track.setBounds(0, trackOffset, trackWidth, trackOffset + trackHeight);
Alan Viverette661e6362014-05-12 10:55:37 -0700586 }
587
588 if (thumb != null) {
589 setThumbPos(w, thumb, getScale(), thumbOffset);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700590 }
591 }
592
Alan Viverette661e6362014-05-12 10:55:37 -0700593 private float getScale() {
594 final int max = getMax();
595 return max > 0 ? getProgress() / (float) max : 0;
596 }
597
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700598 /**
Alan Viverette661e6362014-05-12 10:55:37 -0700599 * Updates the thumb drawable bounds.
600 *
601 * @param w Width of the view, including padding
602 * @param thumb Drawable used for the thumb
603 * @param scale Current progress between 0 and 1
604 * @param offset Vertical offset for centering. If set to
605 * {@link Integer#MIN_VALUE}, the current offset will be used.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700606 */
Alan Viverette661e6362014-05-12 10:55:37 -0700607 private void setThumbPos(int w, Drawable thumb, float scale, int offset) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700608 int available = w - mPaddingLeft - mPaddingRight;
Alan Viverette61956602014-04-22 19:07:06 -0700609 final int thumbWidth = thumb.getIntrinsicWidth();
610 final int thumbHeight = thumb.getIntrinsicHeight();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700611 available -= thumbWidth;
612
613 // The extra space for the thumb to move on the track
614 available += mThumbOffset * 2;
615
Alan Viverette61956602014-04-22 19:07:06 -0700616 final int thumbPos = (int) (scale * available + 0.5f);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700617
Alan Viverette61956602014-04-22 19:07:06 -0700618 final int top, bottom;
Alan Viverette661e6362014-05-12 10:55:37 -0700619 if (offset == Integer.MIN_VALUE) {
Alan Viverette61956602014-04-22 19:07:06 -0700620 final Rect oldBounds = thumb.getBounds();
621 top = oldBounds.top;
622 bottom = oldBounds.bottom;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700623 } else {
Alan Viverette661e6362014-05-12 10:55:37 -0700624 top = offset;
625 bottom = offset + thumbHeight;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700626 }
Alan Viverette61956602014-04-22 19:07:06 -0700627
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800628 final int left = (isLayoutRtl() && mMirrorForRtl) ? available - thumbPos : thumbPos;
Alan Viverette61956602014-04-22 19:07:06 -0700629 final int right = left + thumbWidth;
630
631 final Drawable background = getBackground();
Alan Viverettec80ad992014-05-19 15:46:17 -0700632 if (background != null) {
Alan Viverette61956602014-04-22 19:07:06 -0700633 final int offsetX = mPaddingLeft - mThumbOffset;
634 final int offsetY = mPaddingTop;
Alan Viverette30462412014-06-18 17:54:58 -0700635 background.setHotspotBounds(left + offsetX, top + offsetY,
636 right + offsetX, bottom + offsetY);
Alan Viverette61956602014-04-22 19:07:06 -0700637 }
638
639 // Canvas will be translated, so 0,0 is where we start drawing
640 thumb.setBounds(left, top, right, bottom);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700641 }
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700642
Fabrice Di Meglio4457e852012-09-18 19:23:12 -0700643 /**
644 * @hide
645 */
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700646 @Override
647 public void onResolveDrawables(int layoutDirection) {
648 super.onResolveDrawables(layoutDirection);
649
650 if (mThumb != null) {
651 mThumb.setLayoutDirection(layoutDirection);
652 }
653 }
654
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700655 @Override
656 protected synchronized void onDraw(Canvas canvas) {
657 super.onDraw(canvas);
Alan Viverette661e6362014-05-12 10:55:37 -0700658 drawThumb(canvas);
Alan Viverette8de14942014-06-18 18:05:15 -0700659
Alan Viverette661e6362014-05-12 10:55:37 -0700660 }
661
662 @Override
663 void drawTrack(Canvas canvas) {
664 final Drawable thumbDrawable = mThumb;
665 if (thumbDrawable != null && mSplitTrack) {
666 final Insets insets = thumbDrawable.getOpticalInsets();
667 final Rect tempRect = mTempRect;
668 thumbDrawable.copyBounds(tempRect);
669 tempRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
670 tempRect.left += insets.left;
671 tempRect.right -= insets.right;
672
673 final int saveCount = canvas.save();
674 canvas.clipRect(tempRect, Op.DIFFERENCE);
675 super.drawTrack(canvas);
Alan Viverette41a90672016-01-07 16:35:40 -0500676 drawTickMarks(canvas);
Alan Viverette661e6362014-05-12 10:55:37 -0700677 canvas.restoreToCount(saveCount);
678 } else {
679 super.drawTrack(canvas);
Alan Viverette41a90672016-01-07 16:35:40 -0500680 drawTickMarks(canvas);
681 }
682 }
683
684 /**
685 * Draw the tick marks.
686 */
687 void drawTickMarks(Canvas canvas) {
688 if (mTickMark != null) {
689 final int count = getMax();
690 if (count > 1) {
691 final int w = mTickMark.getIntrinsicWidth();
692 final int h = mTickMark.getIntrinsicHeight();
693 final int halfW = w >= 0 ? w / 2 : 1;
694 final int halfH = h >= 0 ? h / 2 : 1;
695 mTickMark.setBounds(-halfW, -halfH, halfW, halfH);
696
697 final int spacing = (getWidth() - mPaddingLeft - mPaddingRight) / count;
698 final int saveCount = canvas.save();
699 canvas.translate(mPaddingLeft, getHeight() / 2);
700 for (int i = 0; i <= count; i++) {
701 mTickMark.draw(canvas);
702 canvas.translate(spacing, 0);
703 }
704 canvas.restoreToCount(saveCount);
705 }
Alan Viverette661e6362014-05-12 10:55:37 -0700706 }
707 }
708
709 /**
710 * Draw the thumb.
711 */
712 void drawThumb(Canvas canvas) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700713 if (mThumb != null) {
Alan Viverette41a90672016-01-07 16:35:40 -0500714 final int saveCount = canvas.save();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700715 // Translate the padding. For the x, we need to allow the thumb to
716 // draw in its extra space
717 canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
718 mThumb.draw(canvas);
Alan Viverette41a90672016-01-07 16:35:40 -0500719 canvas.restoreToCount(saveCount);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700720 }
721 }
722
723 @Override
724 protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
725 Drawable d = getCurrentDrawable();
726
727 int thumbHeight = mThumb == null ? 0 : mThumb.getIntrinsicHeight();
728 int dw = 0;
729 int dh = 0;
730 if (d != null) {
731 dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
732 dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
733 dh = Math.max(thumbHeight, dh);
734 }
735 dw += mPaddingLeft + mPaddingRight;
736 dh += mPaddingTop + mPaddingBottom;
Alan Viverette661e6362014-05-12 10:55:37 -0700737
Dianne Hackborn189ee182010-12-02 21:48:53 -0800738 setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
739 resolveSizeAndState(dh, heightMeasureSpec, 0));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700740 }
Alan Viverette661e6362014-05-12 10:55:37 -0700741
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700742 @Override
743 public boolean onTouchEvent(MotionEvent event) {
744 if (!mIsUserSeekable || !isEnabled()) {
745 return false;
746 }
Alan Viverette661e6362014-05-12 10:55:37 -0700747
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700748 switch (event.getAction()) {
749 case MotionEvent.ACTION_DOWN:
Adam Powell10298662011-08-14 18:26:30 -0700750 if (isInScrollingContainer()) {
751 mTouchDownX = event.getX();
752 } else {
Alan Viverette9c17c852015-12-08 13:23:58 -0500753 startDrag(event);
Adam Powell10298662011-08-14 18:26:30 -0700754 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700755 break;
Alan Viverette661e6362014-05-12 10:55:37 -0700756
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700757 case MotionEvent.ACTION_MOVE:
Adam Powell10298662011-08-14 18:26:30 -0700758 if (mIsDragging) {
759 trackTouchEvent(event);
760 } else {
761 final float x = event.getX();
762 if (Math.abs(x - mTouchDownX) > mScaledTouchSlop) {
Alan Viverette9c17c852015-12-08 13:23:58 -0500763 startDrag(event);
Adam Powell10298662011-08-14 18:26:30 -0700764 }
765 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700766 break;
Alan Viverette661e6362014-05-12 10:55:37 -0700767
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700768 case MotionEvent.ACTION_UP:
Adam Powell10298662011-08-14 18:26:30 -0700769 if (mIsDragging) {
770 trackTouchEvent(event);
771 onStopTrackingTouch();
772 setPressed(false);
773 } else {
774 // Touch up when we never crossed the touch slop threshold should
775 // be interpreted as a tap-seek to that location.
776 onStartTrackingTouch();
777 trackTouchEvent(event);
778 onStopTrackingTouch();
779 }
Daniel Sandlereb9fdc22009-09-14 13:05:43 -0400780 // ProgressBar doesn't know to repaint the thumb drawable
781 // in its inactive state when the touch stops (because the
782 // value has not apparently changed)
783 invalidate();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700784 break;
Alan Viverette661e6362014-05-12 10:55:37 -0700785
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700786 case MotionEvent.ACTION_CANCEL:
Adam Powell10298662011-08-14 18:26:30 -0700787 if (mIsDragging) {
788 onStopTrackingTouch();
789 setPressed(false);
790 }
Daniel Sandlereb9fdc22009-09-14 13:05:43 -0400791 invalidate(); // see above explanation
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700792 break;
793 }
794 return true;
795 }
796
Alan Viverette9c17c852015-12-08 13:23:58 -0500797 private void startDrag(MotionEvent event) {
798 setPressed(true);
799
800 if (mThumb != null) {
801 // This may be within the padding region.
802 invalidate(mThumb.getBounds());
803 }
804
805 onStartTrackingTouch();
806 trackTouchEvent(event);
807 attemptClaimDrag();
808 }
809
Alan Viverettec80ad992014-05-19 15:46:17 -0700810 private void setHotspot(float x, float y) {
Alan Viverette61956602014-04-22 19:07:06 -0700811 final Drawable bg = getBackground();
Alan Viverettec80ad992014-05-19 15:46:17 -0700812 if (bg != null) {
813 bg.setHotspot(x, y);
Alan Viverette61956602014-04-22 19:07:06 -0700814 }
815 }
816
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700817 private void trackTouchEvent(MotionEvent event) {
Alan Viverette9c17c852015-12-08 13:23:58 -0500818 final int x = Math.round(event.getX());
819 final int y = Math.round(event.getY());
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700820 final int width = getWidth();
Alan Viverette9c17c852015-12-08 13:23:58 -0500821 final int availableWidth = width - mPaddingLeft - mPaddingRight;
822
823 final float scale;
824 float progress = 0.0f;
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800825 if (isLayoutRtl() && mMirrorForRtl) {
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700826 if (x > width - mPaddingRight) {
827 scale = 0.0f;
828 } else if (x < mPaddingLeft) {
829 scale = 1.0f;
830 } else {
Alan Viverette9c17c852015-12-08 13:23:58 -0500831 scale = (availableWidth - x + mPaddingLeft) / (float) availableWidth;
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700832 progress = mTouchProgressOffset;
833 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700834 } else {
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700835 if (x < mPaddingLeft) {
836 scale = 0.0f;
837 } else if (x > width - mPaddingRight) {
838 scale = 1.0f;
839 } else {
Alan Viverette9c17c852015-12-08 13:23:58 -0500840 scale = (x - mPaddingLeft) / (float) availableWidth;
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700841 progress = mTouchProgressOffset;
842 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700843 }
Alan Viverette9c17c852015-12-08 13:23:58 -0500844
Jean-Baptiste Queru69577ae2009-03-09 17:56:44 -0700845 final int max = getMax();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700846 progress += scale * max;
Alan Viverette61956602014-04-22 19:07:06 -0700847
Alan Viverette9c17c852015-12-08 13:23:58 -0500848 setHotspot(x, y);
849 setProgressInternal(Math.round(progress), true, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700850 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800851
852 /**
853 * Tries to claim the user's drag motion, and requests disallowing any
854 * ancestors from stealing events in the drag.
855 */
856 private void attemptClaimDrag() {
857 if (mParent != null) {
858 mParent.requestDisallowInterceptTouchEvent(true);
859 }
860 }
Alan Viverette661e6362014-05-12 10:55:37 -0700861
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700862 /**
863 * This is called when the user has started touching this widget.
864 */
865 void onStartTrackingTouch() {
Adam Powell10298662011-08-14 18:26:30 -0700866 mIsDragging = true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700867 }
868
869 /**
870 * This is called when the user either releases his touch or the touch is
871 * canceled.
872 */
873 void onStopTrackingTouch() {
Adam Powell10298662011-08-14 18:26:30 -0700874 mIsDragging = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700875 }
876
The Android Open Source Project10592532009-03-18 17:39:46 -0700877 /**
878 * Called when the user changes the seekbar's progress by using a key event.
879 */
880 void onKeyChange() {
881 }
882
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800883 @Override
884 public boolean onKeyDown(int keyCode, KeyEvent event) {
Romain Guy992cc422010-01-04 15:39:40 -0800885 if (isEnabled()) {
Johan Redestig575bb382013-01-18 18:21:48 +0100886 int increment = mKeyProgressIncrement;
Romain Guy992cc422010-01-04 15:39:40 -0800887 switch (keyCode) {
888 case KeyEvent.KEYCODE_DPAD_LEFT:
Toni Barzice9889bf2015-09-29 14:50:33 -0700889 case KeyEvent.KEYCODE_MINUS:
Johan Redestig575bb382013-01-18 18:21:48 +0100890 increment = -increment;
891 // fallthrough
Romain Guy992cc422010-01-04 15:39:40 -0800892 case KeyEvent.KEYCODE_DPAD_RIGHT:
Toni Barzice9889bf2015-09-29 14:50:33 -0700893 case KeyEvent.KEYCODE_PLUS:
894 case KeyEvent.KEYCODE_EQUALS:
Johan Redestig575bb382013-01-18 18:21:48 +0100895 increment = isLayoutRtl() ? -increment : increment;
Alan Viverette12a44912015-04-16 13:06:00 -0700896
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400897 if (setProgressInternal(getProgress() + increment, true, true)) {
Johan Redestig575bb382013-01-18 18:21:48 +0100898 onKeyChange();
899 return true;
900 }
Alan Viverette73d28902014-12-02 13:58:27 -0800901 break;
Romain Guy992cc422010-01-04 15:39:40 -0800902 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800903 }
904
905 return super.onKeyDown(keyCode, event);
906 }
907
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800908 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -0800909 public CharSequence getAccessibilityClassName() {
910 return AbsSeekBar.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800911 }
912
Alan Viverettea54956a2015-01-07 16:05:02 -0800913 /** @hide */
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800914 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800915 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
916 super.onInitializeAccessibilityNodeInfoInternal(info);
alanvc826b7d2012-05-16 14:19:21 -0700917
918 if (isEnabled()) {
919 final int progress = getProgress();
920 if (progress > 0) {
Alan Viverette12a44912015-04-16 13:06:00 -0700921 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
alanvc826b7d2012-05-16 14:19:21 -0700922 }
923 if (progress < getMax()) {
Alan Viverette12a44912015-04-16 13:06:00 -0700924 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
alanvc826b7d2012-05-16 14:19:21 -0700925 }
926 }
927 }
928
Alan Viverettea54956a2015-01-07 16:05:02 -0800929 /** @hide */
alanvc826b7d2012-05-16 14:19:21 -0700930 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800931 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
932 if (super.performAccessibilityActionInternal(action, arguments)) {
alanvc826b7d2012-05-16 14:19:21 -0700933 return true;
934 }
Alan Viverette12a44912015-04-16 13:06:00 -0700935
alanvc826b7d2012-05-16 14:19:21 -0700936 if (!isEnabled()) {
937 return false;
938 }
Alan Viverette12a44912015-04-16 13:06:00 -0700939
Maxim Bogatov32e59d52015-04-30 16:57:33 -0700940 switch (action) {
941 case R.id.accessibilityActionSetProgress: {
942 if (!canUserSetProgress()) {
943 return false;
944 }
945 if (arguments == null || !arguments.containsKey(
946 AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)) {
947 return false;
948 }
949 float value = arguments.getFloat(
950 AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE);
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400951 return setProgressInternal((int) value, true, true);
Alan Viverette12a44912015-04-16 13:06:00 -0700952 }
Maxim Bogatov32e59d52015-04-30 16:57:33 -0700953 case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
954 case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
955 if (!canUserSetProgress()) {
956 return false;
957 }
shwetachahar4e9a6492016-02-04 19:42:14 +0000958 int increment = Math.max(1, Math.round((float) getMax() / 20));
Maxim Bogatov32e59d52015-04-30 16:57:33 -0700959 if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
960 increment = -increment;
961 }
Alan Viverette12a44912015-04-16 13:06:00 -0700962
Maxim Bogatov32e59d52015-04-30 16:57:33 -0700963 // Let progress bar handle clamping values.
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400964 if (setProgressInternal(getProgress() + increment, true, true)) {
Maxim Bogatov32e59d52015-04-30 16:57:33 -0700965 onKeyChange();
966 return true;
967 }
968 return false;
alanvc826b7d2012-05-16 14:19:21 -0700969 }
alanvc826b7d2012-05-16 14:19:21 -0700970 }
971 return false;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800972 }
Fabrice Di Megliof37df1b2012-10-15 19:10:08 -0700973
Maxim Bogatov32e59d52015-04-30 16:57:33 -0700974 /**
975 * @return whether user can change progress on the view
976 */
977 boolean canUserSetProgress() {
978 return !isIndeterminate() && isEnabled();
979 }
980
Fabrice Di Megliof37df1b2012-10-15 19:10:08 -0700981 @Override
982 public void onRtlPropertiesChanged(int layoutDirection) {
983 super.onRtlPropertiesChanged(layoutDirection);
984
Alan Viverette661e6362014-05-12 10:55:37 -0700985 final Drawable thumb = mThumb;
Fabrice Di Megliof37df1b2012-10-15 19:10:08 -0700986 if (thumb != null) {
Alan Viverette661e6362014-05-12 10:55:37 -0700987 setThumbPos(getWidth(), thumb, getScale(), Integer.MIN_VALUE);
988
989 // Since we draw translated, the drawable's bounds that it signals
990 // for invalidation won't be the actual bounds we want invalidated,
991 // so just invalidate this whole view.
Fabrice Di Megliof37df1b2012-10-15 19:10:08 -0700992 invalidate();
993 }
994 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700995}