The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package android.widget; |
| 18 | |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 19 | import com.android.internal.R; |
| 20 | |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 21 | import android.annotation.Nullable; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 22 | import android.content.Context; |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 23 | import android.content.res.ColorStateList; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 24 | import android.content.res.TypedArray; |
| 25 | import android.graphics.Canvas; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 26 | import android.graphics.Insets; |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 27 | import android.graphics.PorterDuff; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 28 | import android.graphics.Rect; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 29 | import android.graphics.Region.Op; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 30 | import android.graphics.drawable.Drawable; |
alanv | c826b7d | 2012-05-16 14:19:21 -0700 | [diff] [blame] | 31 | import android.os.Bundle; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 32 | import android.util.AttributeSet; |
The Android Open Source Project | b798689 | 2009-01-09 17:51:23 -0800 | [diff] [blame] | 33 | import android.view.KeyEvent; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 34 | import android.view.MotionEvent; |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 35 | import android.view.ViewConfiguration; |
Svetoslav Ganov | 8a78fd4 | 2012-01-17 14:36:46 -0800 | [diff] [blame] | 36 | import android.view.accessibility.AccessibilityNodeInfo; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 37 | |
| 38 | public abstract class AbsSeekBar extends ProgressBar { |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 39 | private final Rect mTempRect = new Rect(); |
| 40 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 41 | private Drawable mThumb; |
Alan Viverette | a426445 | 2014-07-28 16:02:55 -0700 | [diff] [blame] | 42 | private ColorStateList mThumbTintList = null; |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 43 | private PorterDuff.Mode mThumbTintMode = null; |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 44 | private boolean mHasThumbTint = false; |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 45 | private boolean mHasThumbTintMode = false; |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 46 | |
Alan Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 47 | 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 Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 53 | private int mThumbOffset; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 54 | private boolean mSplitTrack; |
| 55 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 56 | /** |
| 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 Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 66 | |
| 67 | /** |
| 68 | * On key presses (right or left), the amount to increment/decrement the |
| 69 | * progress. |
| 70 | */ |
| 71 | private int mKeyProgressIncrement = 1; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 72 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 73 | private static final int NO_ALPHA = 0xFF; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 74 | private float mDisabledAlpha; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 75 | |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 76 | private int mScaledTouchSlop; |
| 77 | private float mTouchDownX; |
| 78 | private boolean mIsDragging; |
| 79 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 80 | public AbsSeekBar(Context context) { |
| 81 | super(context); |
| 82 | } |
| 83 | |
| 84 | public AbsSeekBar(Context context, AttributeSet attrs) { |
| 85 | super(context, attrs); |
| 86 | } |
| 87 | |
Alan Viverette | 617feb9 | 2013-09-09 18:09:13 -0700 | [diff] [blame] | 88 | public AbsSeekBar(Context context, AttributeSet attrs, int defStyleAttr) { |
| 89 | this(context, attrs, defStyleAttr, 0); |
| 90 | } |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 91 | |
Alan Viverette | 617feb9 | 2013-09-09 18:09:13 -0700 | [diff] [blame] | 92 | public AbsSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { |
| 93 | super(context, attrs, defStyleAttr, defStyleRes); |
| 94 | |
Alan Viverette | 87e1938 | 2015-05-29 15:12:14 -0700 | [diff] [blame] | 95 | final TypedArray a = context.obtainStyledAttributes( |
| 96 | attrs, R.styleable.SeekBar, defStyleAttr, defStyleRes); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 97 | |
Alan Viverette | 87e1938 | 2015-05-29 15:12:14 -0700 | [diff] [blame] | 98 | final Drawable thumb = a.getDrawable(R.styleable.SeekBar_thumb); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 99 | setThumb(thumb); |
| 100 | |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 101 | 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 Viverette | 4f64c04 | 2014-07-21 17:49:13 -0700 | [diff] [blame] | 106 | |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 107 | if (a.hasValue(R.styleable.SeekBar_thumbTint)) { |
Alan Viverette | a426445 | 2014-07-28 16:02:55 -0700 | [diff] [blame] | 108 | mThumbTintList = a.getColorStateList(R.styleable.SeekBar_thumbTint); |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 109 | mHasThumbTint = true; |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 110 | } |
| 111 | |
Alan Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 112 | 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 Viverette | 87e1938 | 2015-05-29 15:12:14 -0700 | [diff] [blame] | 126 | mSplitTrack = a.getBoolean(R.styleable.SeekBar_splitTrack, false); |
| 127 | |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 128 | // Guess thumb offset if thumb != null, but allow layout to override. |
Alan Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 129 | final int thumbOffset = a.getDimensionPixelOffset( |
| 130 | R.styleable.SeekBar_thumbOffset, getThumbOffset()); |
Romain Guy | 992cc42 | 2010-01-04 15:39:40 -0800 | [diff] [blame] | 131 | setThumbOffset(thumbOffset); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 132 | |
Alan Viverette | 87e1938 | 2015-05-29 15:12:14 -0700 | [diff] [blame] | 133 | final boolean useDisabledAlpha = a.getBoolean(R.styleable.SeekBar_useDisabledAlpha, true); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 134 | a.recycle(); |
| 135 | |
Alan Viverette | 87e1938 | 2015-05-29 15:12:14 -0700 | [diff] [blame] | 136 | 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 Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 143 | |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 144 | applyThumbTint(); |
Alan Viverette | d154a5b | 2016-01-13 10:10:22 -0500 | [diff] [blame] | 145 | applyTickMarkTint(); |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 146 | |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 147 | mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 148 | } |
| 149 | |
| 150 | /** |
Daniel Sandler | 8d28c3b | 2009-08-20 13:34:02 -0400 | [diff] [blame] | 151 | * 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 Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 155 | * |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 156 | * @param thumb Drawable representing the thumb |
| 157 | */ |
| 158 | public void setThumb(Drawable thumb) { |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 159 | final boolean needUpdate; |
Joe Onorato | 2e585f7 | 2010-12-02 14:10:57 -0800 | [diff] [blame] | 160 | // 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 Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 169 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 170 | if (thumb != null) { |
| 171 | thumb.setCallback(this); |
Fabrice Di Meglio | 0af4b8b | 2012-06-11 18:30:05 -0700 | [diff] [blame] | 172 | if (canResolveLayoutDirection()) { |
Fabrice Di Meglio | e56ffdc | 2012-09-23 14:51:16 -0700 | [diff] [blame] | 173 | thumb.setLayoutDirection(getLayoutDirection()); |
Fabrice Di Meglio | 0af4b8b | 2012-06-11 18:30:05 -0700 | [diff] [blame] | 174 | } |
Daniel Sandler | 8d28c3b | 2009-08-20 13:34:02 -0400 | [diff] [blame] | 175 | |
| 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 Guy | 992cc42 | 2010-01-04 15:39:40 -0800 | [diff] [blame] | 179 | mThumbOffset = thumb.getIntrinsicWidth() / 2; |
Joe Onorato | 2e585f7 | 2010-12-02 14:10:57 -0800 | [diff] [blame] | 180 | |
| 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 Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 187 | } |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 188 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 189 | mThumb = thumb; |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 190 | |
| 191 | applyThumbTint(); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 192 | invalidate(); |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 193 | |
Joe Onorato | 2e585f7 | 2010-12-02 14:10:57 -0800 | [diff] [blame] | 194 | if (needUpdate) { |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 195 | updateThumbAndTrackPos(getWidth(), getHeight()); |
Adam Powell | 0283a55 | 2012-04-19 09:58:22 -0700 | [diff] [blame] | 196 | if (thumb != null && thumb.isStateful()) { |
Joe Onorato | 2e585f7 | 2010-12-02 14:10:57 -0800 | [diff] [blame] | 197 | // 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 Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 203 | } |
| 204 | |
| 205 | /** |
Adam Powell | 3004cc5 | 2012-03-21 17:50:51 -0700 | [diff] [blame] | 206 | * 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 Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 216 | * Applies a tint to the thumb drawable. Does not modify the current tint |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 217 | * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 218 | * <p> |
| 219 | * Subsequent calls to {@link #setThumb(Drawable)} will automatically |
| 220 | * mutate the drawable and apply the specified tint and tint mode using |
Alan Viverette | a426445 | 2014-07-28 16:02:55 -0700 | [diff] [blame] | 221 | * {@link Drawable#setTintList(ColorStateList)}. |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 222 | * |
| 223 | * @param tint the tint to apply, may be {@code null} to clear tint |
| 224 | * |
| 225 | * @attr ref android.R.styleable#SeekBar_thumbTint |
Alan Viverette | a426445 | 2014-07-28 16:02:55 -0700 | [diff] [blame] | 226 | * @see #getThumbTintList() |
| 227 | * @see Drawable#setTintList(ColorStateList) |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 228 | */ |
Alan Viverette | a426445 | 2014-07-28 16:02:55 -0700 | [diff] [blame] | 229 | public void setThumbTintList(@Nullable ColorStateList tint) { |
| 230 | mThumbTintList = tint; |
Alan Viverette | 4f64c04 | 2014-07-21 17:49:13 -0700 | [diff] [blame] | 231 | mHasThumbTint = true; |
| 232 | |
| 233 | applyThumbTint(); |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 234 | } |
| 235 | |
| 236 | /** |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 237 | * Returns the tint applied to the thumb drawable, if specified. |
| 238 | * |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 239 | * @return the tint applied to the thumb drawable |
| 240 | * @attr ref android.R.styleable#SeekBar_thumbTint |
Alan Viverette | a426445 | 2014-07-28 16:02:55 -0700 | [diff] [blame] | 241 | * @see #setThumbTintList(ColorStateList) |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 242 | */ |
| 243 | @Nullable |
Alan Viverette | a426445 | 2014-07-28 16:02:55 -0700 | [diff] [blame] | 244 | public ColorStateList getThumbTintList() { |
| 245 | return mThumbTintList; |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | /** |
| 249 | * Specifies the blending mode used to apply the tint specified by |
Alan Viverette | a426445 | 2014-07-28 16:02:55 -0700 | [diff] [blame] | 250 | * {@link #setThumbTintList(ColorStateList)}} to the thumb drawable. The |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 251 | * default mode is {@link PorterDuff.Mode#SRC_IN}. |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 252 | * |
| 253 | * @param tintMode the blending mode used to apply the tint, may be |
| 254 | * {@code null} to clear tint |
Alan Viverette | 4f64c04 | 2014-07-21 17:49:13 -0700 | [diff] [blame] | 255 | * |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 256 | * @attr ref android.R.styleable#SeekBar_thumbTintMode |
Alan Viverette | 4f64c04 | 2014-07-21 17:49:13 -0700 | [diff] [blame] | 257 | * @see #getThumbTintMode() |
Alan Viverette | a426445 | 2014-07-28 16:02:55 -0700 | [diff] [blame] | 258 | * @see Drawable#setTintMode(PorterDuff.Mode) |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 259 | */ |
| 260 | public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) { |
Alan Viverette | 4f64c04 | 2014-07-21 17:49:13 -0700 | [diff] [blame] | 261 | mThumbTintMode = tintMode; |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 262 | mHasThumbTintMode = true; |
Alan Viverette | 4f64c04 | 2014-07-21 17:49:13 -0700 | [diff] [blame] | 263 | |
| 264 | applyThumbTint(); |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 265 | } |
| 266 | |
| 267 | /** |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 268 | * Returns the blending mode used to apply the tint to the thumb drawable, |
| 269 | * if specified. |
| 270 | * |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 271 | * @return the blending mode used to apply the tint to the thumb drawable |
| 272 | * @attr ref android.R.styleable#SeekBar_thumbTintMode |
Alan Viverette | 4f64c04 | 2014-07-21 17:49:13 -0700 | [diff] [blame] | 273 | * @see #setThumbTintMode(PorterDuff.Mode) |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 274 | */ |
| 275 | @Nullable |
| 276 | public PorterDuff.Mode getThumbTintMode() { |
| 277 | return mThumbTintMode; |
| 278 | } |
| 279 | |
| 280 | private void applyThumbTint() { |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 281 | if (mThumb != null && (mHasThumbTint || mHasThumbTintMode)) { |
Alan Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 282 | mThumb = mThumb.mutate(); |
Alan Viverette | b56f5d2 | 2014-09-14 15:48:50 -0700 | [diff] [blame] | 283 | |
| 284 | if (mHasThumbTint) { |
| 285 | mThumb.setTintList(mThumbTintList); |
| 286 | } |
| 287 | |
| 288 | if (mHasThumbTintMode) { |
| 289 | mThumb.setTintMode(mThumbTintMode); |
| 290 | } |
Alan Viverette | d513379 | 2014-10-28 14:41:36 -0700 | [diff] [blame] | 291 | |
| 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 Viverette | 9117436 | 2014-06-17 14:51:45 -0700 | [diff] [blame] | 297 | } |
| 298 | } |
| 299 | |
| 300 | /** |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 301 | * @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 Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 310 | * |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 311 | * @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 Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 318 | /** |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 319 | * 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 Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 338 | * 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 Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 455 | * Sets the amount of progress changed via the arrow keys. |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 456 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 457 | * @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 Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 468 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 469 | * @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 Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 475 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 476 | @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 Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 487 | @Override |
| 488 | protected boolean verifyDrawable(Drawable who) { |
Alan Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 489 | return who == mThumb || who == mTickMark || super.verifyDrawable(who); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 490 | } |
| 491 | |
| 492 | @Override |
Dianne Hackborn | e213677 | 2010-11-04 15:08:59 -0700 | [diff] [blame] | 493 | public void jumpDrawablesToCurrentState() { |
| 494 | super.jumpDrawablesToCurrentState(); |
Alan Viverette | 8de1494 | 2014-06-18 18:05:15 -0700 | [diff] [blame] | 495 | |
| 496 | if (mThumb != null) { |
| 497 | mThumb.jumpToCurrentState(); |
| 498 | } |
Alan Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 499 | |
| 500 | if (mTickMark != null) { |
| 501 | mTickMark.jumpToCurrentState(); |
| 502 | } |
Dianne Hackborn | e213677 | 2010-11-04 15:08:59 -0700 | [diff] [blame] | 503 | } |
| 504 | |
| 505 | @Override |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 506 | protected void drawableStateChanged() { |
| 507 | super.drawableStateChanged(); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 508 | |
| 509 | final Drawable progressDrawable = getProgressDrawable(); |
Alan Viverette | 87e1938 | 2015-05-29 15:12:14 -0700 | [diff] [blame] | 510 | if (progressDrawable != null && mDisabledAlpha < 1.0f) { |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 511 | progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha)); |
| 512 | } |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 513 | |
| 514 | final Drawable thumb = mThumb; |
Alan Viverette | ad0020f | 2015-09-04 10:10:42 -0400 | [diff] [blame] | 515 | if (thumb != null && thumb.isStateful() |
| 516 | && thumb.setState(getDrawableState())) { |
| 517 | invalidateDrawable(thumb); |
The Android Open Source Project | b798689 | 2009-01-09 17:51:23 -0800 | [diff] [blame] | 518 | } |
Alan Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 519 | |
| 520 | final Drawable tickMark = mTickMark; |
| 521 | if (tickMark != null && tickMark.isStateful() |
| 522 | && tickMark.setState(getDrawableState())) { |
| 523 | invalidateDrawable(tickMark); |
| 524 | } |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 525 | } |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 526 | |
Alan Viverette | cebc6ba | 2014-06-13 15:52:13 -0700 | [diff] [blame] | 527 | @Override |
Alan Viverette | 8de1494 | 2014-06-18 18:05:15 -0700 | [diff] [blame] | 528 | public void drawableHotspotChanged(float x, float y) { |
| 529 | super.drawableHotspotChanged(x, y); |
Alan Viverette | cebc6ba | 2014-06-13 15:52:13 -0700 | [diff] [blame] | 530 | |
Alan Viverette | 8de1494 | 2014-06-18 18:05:15 -0700 | [diff] [blame] | 531 | if (mThumb != null) { |
| 532 | mThumb.setHotspot(x, y); |
Alan Viverette | 2356c5e | 2014-05-22 22:43:59 -0700 | [diff] [blame] | 533 | } |
| 534 | } |
| 535 | |
| 536 | @Override |
Alan Viverette | a64ed3b | 2015-09-23 10:01:45 -0400 | [diff] [blame] | 537 | void onVisualProgressChanged(int id, float scale) { |
| 538 | super.onVisualProgressChanged(id, scale); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 539 | |
Alan Viverette | a64ed3b | 2015-09-23 10:01:45 -0400 | [diff] [blame] | 540 | if (id == R.id.progress) { |
| 541 | final Drawable thumb = mThumb; |
| 542 | if (thumb != null) { |
| 543 | setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 544 | |
Alan Viverette | a64ed3b | 2015-09-23 10:01:45 -0400 | [diff] [blame] | 545 | // 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 Viverette | 5ce0ec0 | 2014-11-25 09:40:54 -0800 | [diff] [blame] | 550 | } |
Jon Miranda | 0c11a48 | 2014-07-21 14:55:29 -0700 | [diff] [blame] | 551 | } |
| 552 | |
| 553 | @Override |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 554 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
Fabrice Di Meglio | f37df1b | 2012-10-15 19:10:08 -0700 | [diff] [blame] | 555 | super.onSizeChanged(w, h, oldw, oldh); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 556 | |
| 557 | updateThumbAndTrackPos(w, h); |
Joe Onorato | 2e585f7 | 2010-12-02 14:10:57 -0800 | [diff] [blame] | 558 | } |
| 559 | |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 560 | private void updateThumbAndTrackPos(int w, int h) { |
Alan Viverette | 3afd8b0 | 2015-02-26 13:36:28 -0800 | [diff] [blame] | 561 | final int paddedHeight = h - mPaddingTop - mPaddingBottom; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 562 | final Drawable track = getCurrentDrawable(); |
| 563 | final Drawable thumb = mThumb; |
| 564 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 565 | // The max height does not incorporate padding, whereas the height |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 566 | // parameter does. |
Alan Viverette | 3afd8b0 | 2015-02-26 13:36:28 -0800 | [diff] [blame] | 567 | final int trackHeight = Math.min(mMaxHeight, paddedHeight); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 568 | 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 Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 573 | if (thumbHeight > trackHeight) { |
Alan Viverette | 3afd8b0 | 2015-02-26 13:36:28 -0800 | [diff] [blame] | 574 | final int offsetHeight = (paddedHeight - thumbHeight) / 2; |
| 575 | trackOffset = offsetHeight + (thumbHeight - trackHeight) / 2; |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 576 | thumbOffset = offsetHeight; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 577 | } else { |
Alan Viverette | 3afd8b0 | 2015-02-26 13:36:28 -0800 | [diff] [blame] | 578 | final int offsetHeight = (paddedHeight - trackHeight) / 2; |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 579 | trackOffset = offsetHeight; |
Alan Viverette | 3afd8b0 | 2015-02-26 13:36:28 -0800 | [diff] [blame] | 580 | thumbOffset = offsetHeight + (trackHeight - thumbHeight) / 2; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 581 | } |
| 582 | |
| 583 | if (track != null) { |
Alan Viverette | 6a8253f | 2015-02-23 12:49:47 -0800 | [diff] [blame] | 584 | final int trackWidth = w - mPaddingRight - mPaddingLeft; |
| 585 | track.setBounds(0, trackOffset, trackWidth, trackOffset + trackHeight); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 586 | } |
| 587 | |
| 588 | if (thumb != null) { |
| 589 | setThumbPos(w, thumb, getScale(), thumbOffset); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 590 | } |
| 591 | } |
| 592 | |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 593 | private float getScale() { |
| 594 | final int max = getMax(); |
| 595 | return max > 0 ? getProgress() / (float) max : 0; |
| 596 | } |
| 597 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 598 | /** |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 599 | * 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 Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 606 | */ |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 607 | private void setThumbPos(int w, Drawable thumb, float scale, int offset) { |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 608 | int available = w - mPaddingLeft - mPaddingRight; |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 609 | final int thumbWidth = thumb.getIntrinsicWidth(); |
| 610 | final int thumbHeight = thumb.getIntrinsicHeight(); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 611 | available -= thumbWidth; |
| 612 | |
| 613 | // The extra space for the thumb to move on the track |
| 614 | available += mThumbOffset * 2; |
| 615 | |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 616 | final int thumbPos = (int) (scale * available + 0.5f); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 617 | |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 618 | final int top, bottom; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 619 | if (offset == Integer.MIN_VALUE) { |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 620 | final Rect oldBounds = thumb.getBounds(); |
| 621 | top = oldBounds.top; |
| 622 | bottom = oldBounds.bottom; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 623 | } else { |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 624 | top = offset; |
| 625 | bottom = offset + thumbHeight; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 626 | } |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 627 | |
Fabrice Di Meglio | 2b378cd | 2013-01-30 16:39:33 -0800 | [diff] [blame] | 628 | final int left = (isLayoutRtl() && mMirrorForRtl) ? available - thumbPos : thumbPos; |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 629 | final int right = left + thumbWidth; |
| 630 | |
| 631 | final Drawable background = getBackground(); |
Alan Viverette | c80ad99 | 2014-05-19 15:46:17 -0700 | [diff] [blame] | 632 | if (background != null) { |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 633 | final int offsetX = mPaddingLeft - mThumbOffset; |
| 634 | final int offsetY = mPaddingTop; |
Alan Viverette | 3046241 | 2014-06-18 17:54:58 -0700 | [diff] [blame] | 635 | background.setHotspotBounds(left + offsetX, top + offsetY, |
| 636 | right + offsetX, bottom + offsetY); |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 637 | } |
| 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 Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 641 | } |
Fabrice Di Meglio | 0af4b8b | 2012-06-11 18:30:05 -0700 | [diff] [blame] | 642 | |
Fabrice Di Meglio | 4457e85 | 2012-09-18 19:23:12 -0700 | [diff] [blame] | 643 | /** |
| 644 | * @hide |
| 645 | */ |
Fabrice Di Meglio | 0af4b8b | 2012-06-11 18:30:05 -0700 | [diff] [blame] | 646 | @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 Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 655 | @Override |
| 656 | protected synchronized void onDraw(Canvas canvas) { |
| 657 | super.onDraw(canvas); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 658 | drawThumb(canvas); |
Alan Viverette | 8de1494 | 2014-06-18 18:05:15 -0700 | [diff] [blame] | 659 | |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 660 | } |
| 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 Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 676 | drawTickMarks(canvas); |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 677 | canvas.restoreToCount(saveCount); |
| 678 | } else { |
| 679 | super.drawTrack(canvas); |
Alan Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 680 | 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 Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 706 | } |
| 707 | } |
| 708 | |
| 709 | /** |
| 710 | * Draw the thumb. |
| 711 | */ |
| 712 | void drawThumb(Canvas canvas) { |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 713 | if (mThumb != null) { |
Alan Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 714 | final int saveCount = canvas.save(); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 715 | // 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 Viverette | 41a9067 | 2016-01-07 16:35:40 -0500 | [diff] [blame] | 719 | canvas.restoreToCount(saveCount); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 720 | } |
| 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 Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 737 | |
Dianne Hackborn | 189ee18 | 2010-12-02 21:48:53 -0800 | [diff] [blame] | 738 | setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0), |
| 739 | resolveSizeAndState(dh, heightMeasureSpec, 0)); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 740 | } |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 741 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 742 | @Override |
| 743 | public boolean onTouchEvent(MotionEvent event) { |
| 744 | if (!mIsUserSeekable || !isEnabled()) { |
| 745 | return false; |
| 746 | } |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 747 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 748 | switch (event.getAction()) { |
| 749 | case MotionEvent.ACTION_DOWN: |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 750 | if (isInScrollingContainer()) { |
| 751 | mTouchDownX = event.getX(); |
| 752 | } else { |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 753 | startDrag(event); |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 754 | } |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 755 | break; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 756 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 757 | case MotionEvent.ACTION_MOVE: |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 758 | if (mIsDragging) { |
| 759 | trackTouchEvent(event); |
| 760 | } else { |
| 761 | final float x = event.getX(); |
| 762 | if (Math.abs(x - mTouchDownX) > mScaledTouchSlop) { |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 763 | startDrag(event); |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 764 | } |
| 765 | } |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 766 | break; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 767 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 768 | case MotionEvent.ACTION_UP: |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 769 | 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 Sandler | eb9fdc2 | 2009-09-14 13:05:43 -0400 | [diff] [blame] | 780 | // 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 Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 784 | break; |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 785 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 786 | case MotionEvent.ACTION_CANCEL: |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 787 | if (mIsDragging) { |
| 788 | onStopTrackingTouch(); |
| 789 | setPressed(false); |
| 790 | } |
Daniel Sandler | eb9fdc2 | 2009-09-14 13:05:43 -0400 | [diff] [blame] | 791 | invalidate(); // see above explanation |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 792 | break; |
| 793 | } |
| 794 | return true; |
| 795 | } |
| 796 | |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 797 | 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 Viverette | c80ad99 | 2014-05-19 15:46:17 -0700 | [diff] [blame] | 810 | private void setHotspot(float x, float y) { |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 811 | final Drawable bg = getBackground(); |
Alan Viverette | c80ad99 | 2014-05-19 15:46:17 -0700 | [diff] [blame] | 812 | if (bg != null) { |
| 813 | bg.setHotspot(x, y); |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 814 | } |
| 815 | } |
| 816 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 817 | private void trackTouchEvent(MotionEvent event) { |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 818 | final int x = Math.round(event.getX()); |
| 819 | final int y = Math.round(event.getY()); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 820 | final int width = getWidth(); |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 821 | final int availableWidth = width - mPaddingLeft - mPaddingRight; |
| 822 | |
| 823 | final float scale; |
| 824 | float progress = 0.0f; |
Fabrice Di Meglio | 2b378cd | 2013-01-30 16:39:33 -0800 | [diff] [blame] | 825 | if (isLayoutRtl() && mMirrorForRtl) { |
Fabrice Di Meglio | 0af4b8b | 2012-06-11 18:30:05 -0700 | [diff] [blame] | 826 | if (x > width - mPaddingRight) { |
| 827 | scale = 0.0f; |
| 828 | } else if (x < mPaddingLeft) { |
| 829 | scale = 1.0f; |
| 830 | } else { |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 831 | scale = (availableWidth - x + mPaddingLeft) / (float) availableWidth; |
Fabrice Di Meglio | 0af4b8b | 2012-06-11 18:30:05 -0700 | [diff] [blame] | 832 | progress = mTouchProgressOffset; |
| 833 | } |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 834 | } else { |
Fabrice Di Meglio | 0af4b8b | 2012-06-11 18:30:05 -0700 | [diff] [blame] | 835 | if (x < mPaddingLeft) { |
| 836 | scale = 0.0f; |
| 837 | } else if (x > width - mPaddingRight) { |
| 838 | scale = 1.0f; |
| 839 | } else { |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 840 | scale = (x - mPaddingLeft) / (float) availableWidth; |
Fabrice Di Meglio | 0af4b8b | 2012-06-11 18:30:05 -0700 | [diff] [blame] | 841 | progress = mTouchProgressOffset; |
| 842 | } |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 843 | } |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 844 | |
Jean-Baptiste Queru | 69577ae | 2009-03-09 17:56:44 -0700 | [diff] [blame] | 845 | final int max = getMax(); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 846 | progress += scale * max; |
Alan Viverette | 6195660 | 2014-04-22 19:07:06 -0700 | [diff] [blame] | 847 | |
Alan Viverette | 9c17c85 | 2015-12-08 13:23:58 -0500 | [diff] [blame] | 848 | setHotspot(x, y); |
| 849 | setProgressInternal(Math.round(progress), true, false); |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 850 | } |
The Android Open Source Project | f013e1a | 2008-12-17 18:05:43 -0800 | [diff] [blame] | 851 | |
| 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 Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 861 | |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 862 | /** |
| 863 | * This is called when the user has started touching this widget. |
| 864 | */ |
| 865 | void onStartTrackingTouch() { |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 866 | mIsDragging = true; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 867 | } |
| 868 | |
| 869 | /** |
| 870 | * This is called when the user either releases his touch or the touch is |
| 871 | * canceled. |
| 872 | */ |
| 873 | void onStopTrackingTouch() { |
Adam Powell | 1029866 | 2011-08-14 18:26:30 -0700 | [diff] [blame] | 874 | mIsDragging = false; |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 875 | } |
| 876 | |
The Android Open Source Project | 1059253 | 2009-03-18 17:39:46 -0700 | [diff] [blame] | 877 | /** |
| 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 Project | b798689 | 2009-01-09 17:51:23 -0800 | [diff] [blame] | 883 | @Override |
| 884 | public boolean onKeyDown(int keyCode, KeyEvent event) { |
Romain Guy | 992cc42 | 2010-01-04 15:39:40 -0800 | [diff] [blame] | 885 | if (isEnabled()) { |
Johan Redestig | 575bb38 | 2013-01-18 18:21:48 +0100 | [diff] [blame] | 886 | int increment = mKeyProgressIncrement; |
Romain Guy | 992cc42 | 2010-01-04 15:39:40 -0800 | [diff] [blame] | 887 | switch (keyCode) { |
| 888 | case KeyEvent.KEYCODE_DPAD_LEFT: |
Toni Barzic | e9889bf | 2015-09-29 14:50:33 -0700 | [diff] [blame] | 889 | case KeyEvent.KEYCODE_MINUS: |
Johan Redestig | 575bb38 | 2013-01-18 18:21:48 +0100 | [diff] [blame] | 890 | increment = -increment; |
| 891 | // fallthrough |
Romain Guy | 992cc42 | 2010-01-04 15:39:40 -0800 | [diff] [blame] | 892 | case KeyEvent.KEYCODE_DPAD_RIGHT: |
Toni Barzic | e9889bf | 2015-09-29 14:50:33 -0700 | [diff] [blame] | 893 | case KeyEvent.KEYCODE_PLUS: |
| 894 | case KeyEvent.KEYCODE_EQUALS: |
Johan Redestig | 575bb38 | 2013-01-18 18:21:48 +0100 | [diff] [blame] | 895 | increment = isLayoutRtl() ? -increment : increment; |
Alan Viverette | 12a4491 | 2015-04-16 13:06:00 -0700 | [diff] [blame] | 896 | |
Alan Viverette | a64ed3b | 2015-09-23 10:01:45 -0400 | [diff] [blame] | 897 | if (setProgressInternal(getProgress() + increment, true, true)) { |
Johan Redestig | 575bb38 | 2013-01-18 18:21:48 +0100 | [diff] [blame] | 898 | onKeyChange(); |
| 899 | return true; |
| 900 | } |
Alan Viverette | 73d2890 | 2014-12-02 13:58:27 -0800 | [diff] [blame] | 901 | break; |
Romain Guy | 992cc42 | 2010-01-04 15:39:40 -0800 | [diff] [blame] | 902 | } |
The Android Open Source Project | b798689 | 2009-01-09 17:51:23 -0800 | [diff] [blame] | 903 | } |
| 904 | |
| 905 | return super.onKeyDown(keyCode, event); |
| 906 | } |
| 907 | |
Svetoslav Ganov | 8a78fd4 | 2012-01-17 14:36:46 -0800 | [diff] [blame] | 908 | @Override |
Dianne Hackborn | a7bb6fb | 2015-02-03 18:13:40 -0800 | [diff] [blame] | 909 | public CharSequence getAccessibilityClassName() { |
| 910 | return AbsSeekBar.class.getName(); |
Svetoslav Ganov | 8a78fd4 | 2012-01-17 14:36:46 -0800 | [diff] [blame] | 911 | } |
| 912 | |
Alan Viverette | a54956a | 2015-01-07 16:05:02 -0800 | [diff] [blame] | 913 | /** @hide */ |
Svetoslav Ganov | 8a78fd4 | 2012-01-17 14:36:46 -0800 | [diff] [blame] | 914 | @Override |
Alan Viverette | a54956a | 2015-01-07 16:05:02 -0800 | [diff] [blame] | 915 | public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { |
| 916 | super.onInitializeAccessibilityNodeInfoInternal(info); |
alanv | c826b7d | 2012-05-16 14:19:21 -0700 | [diff] [blame] | 917 | |
| 918 | if (isEnabled()) { |
| 919 | final int progress = getProgress(); |
| 920 | if (progress > 0) { |
Alan Viverette | 12a4491 | 2015-04-16 13:06:00 -0700 | [diff] [blame] | 921 | info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); |
alanv | c826b7d | 2012-05-16 14:19:21 -0700 | [diff] [blame] | 922 | } |
| 923 | if (progress < getMax()) { |
Alan Viverette | 12a4491 | 2015-04-16 13:06:00 -0700 | [diff] [blame] | 924 | info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); |
alanv | c826b7d | 2012-05-16 14:19:21 -0700 | [diff] [blame] | 925 | } |
| 926 | } |
| 927 | } |
| 928 | |
Alan Viverette | a54956a | 2015-01-07 16:05:02 -0800 | [diff] [blame] | 929 | /** @hide */ |
alanv | c826b7d | 2012-05-16 14:19:21 -0700 | [diff] [blame] | 930 | @Override |
Alan Viverette | a54956a | 2015-01-07 16:05:02 -0800 | [diff] [blame] | 931 | public boolean performAccessibilityActionInternal(int action, Bundle arguments) { |
| 932 | if (super.performAccessibilityActionInternal(action, arguments)) { |
alanv | c826b7d | 2012-05-16 14:19:21 -0700 | [diff] [blame] | 933 | return true; |
| 934 | } |
Alan Viverette | 12a4491 | 2015-04-16 13:06:00 -0700 | [diff] [blame] | 935 | |
alanv | c826b7d | 2012-05-16 14:19:21 -0700 | [diff] [blame] | 936 | if (!isEnabled()) { |
| 937 | return false; |
| 938 | } |
Alan Viverette | 12a4491 | 2015-04-16 13:06:00 -0700 | [diff] [blame] | 939 | |
Maxim Bogatov | 32e59d5 | 2015-04-30 16:57:33 -0700 | [diff] [blame] | 940 | 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 Viverette | a64ed3b | 2015-09-23 10:01:45 -0400 | [diff] [blame] | 951 | return setProgressInternal((int) value, true, true); |
Alan Viverette | 12a4491 | 2015-04-16 13:06:00 -0700 | [diff] [blame] | 952 | } |
Maxim Bogatov | 32e59d5 | 2015-04-30 16:57:33 -0700 | [diff] [blame] | 953 | case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: |
| 954 | case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { |
| 955 | if (!canUserSetProgress()) { |
| 956 | return false; |
| 957 | } |
shwetachahar | 4e9a649 | 2016-02-04 19:42:14 +0000 | [diff] [blame] | 958 | int increment = Math.max(1, Math.round((float) getMax() / 20)); |
Maxim Bogatov | 32e59d5 | 2015-04-30 16:57:33 -0700 | [diff] [blame] | 959 | if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) { |
| 960 | increment = -increment; |
| 961 | } |
Alan Viverette | 12a4491 | 2015-04-16 13:06:00 -0700 | [diff] [blame] | 962 | |
Maxim Bogatov | 32e59d5 | 2015-04-30 16:57:33 -0700 | [diff] [blame] | 963 | // Let progress bar handle clamping values. |
Alan Viverette | a64ed3b | 2015-09-23 10:01:45 -0400 | [diff] [blame] | 964 | if (setProgressInternal(getProgress() + increment, true, true)) { |
Maxim Bogatov | 32e59d5 | 2015-04-30 16:57:33 -0700 | [diff] [blame] | 965 | onKeyChange(); |
| 966 | return true; |
| 967 | } |
| 968 | return false; |
alanv | c826b7d | 2012-05-16 14:19:21 -0700 | [diff] [blame] | 969 | } |
alanv | c826b7d | 2012-05-16 14:19:21 -0700 | [diff] [blame] | 970 | } |
| 971 | return false; |
Svetoslav Ganov | 8a78fd4 | 2012-01-17 14:36:46 -0800 | [diff] [blame] | 972 | } |
Fabrice Di Meglio | f37df1b | 2012-10-15 19:10:08 -0700 | [diff] [blame] | 973 | |
Maxim Bogatov | 32e59d5 | 2015-04-30 16:57:33 -0700 | [diff] [blame] | 974 | /** |
| 975 | * @return whether user can change progress on the view |
| 976 | */ |
| 977 | boolean canUserSetProgress() { |
| 978 | return !isIndeterminate() && isEnabled(); |
| 979 | } |
| 980 | |
Fabrice Di Meglio | f37df1b | 2012-10-15 19:10:08 -0700 | [diff] [blame] | 981 | @Override |
| 982 | public void onRtlPropertiesChanged(int layoutDirection) { |
| 983 | super.onRtlPropertiesChanged(layoutDirection); |
| 984 | |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 985 | final Drawable thumb = mThumb; |
Fabrice Di Meglio | f37df1b | 2012-10-15 19:10:08 -0700 | [diff] [blame] | 986 | if (thumb != null) { |
Alan Viverette | 661e636 | 2014-05-12 10:55:37 -0700 | [diff] [blame] | 987 | 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 Meglio | f37df1b | 2012-10-15 19:10:08 -0700 | [diff] [blame] | 992 | invalidate(); |
| 993 | } |
| 994 | } |
The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 995 | } |