154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project/*
254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project *
454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * you may not use this file except in compliance with the License.
654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * You may obtain a copy of the License at
754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project *
854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project *
1054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * See the License for the specific language governing permissions and
1454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * limitations under the License.
1554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */
1654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
1754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectpackage android.widget;
1854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
19911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viveretteimport android.annotation.Nullable;
2054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.content.Context;
21911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viveretteimport android.content.res.ColorStateList;
2254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.content.res.TypedArray;
2354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.graphics.Canvas;
24661e63658da39cccfe49a129e4860455716ff3c9Alan Viveretteimport android.graphics.Insets;
25911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viveretteimport android.graphics.PorterDuff;
2654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.graphics.Rect;
27661e63658da39cccfe49a129e4860455716ff3c9Alan Viveretteimport android.graphics.Region.Op;
2854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.graphics.drawable.Drawable;
29c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanvimport android.os.Bundle;
3054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.util.AttributeSet;
31b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Projectimport android.view.KeyEvent;
3254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.view.MotionEvent;
331029866a12e04e9db52485e2ec0353e764d15549Adam Powellimport android.view.ViewConfiguration;
348a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
358a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
3654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
37911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viveretteimport com.android.internal.R;
38911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
3954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectpublic abstract class AbsSeekBar extends ProgressBar {
40661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private final Rect mTempRect = new Rect();
41661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
4254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    private Drawable mThumb;
43a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    private ColorStateList mThumbTintList = null;
44b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette    private PorterDuff.Mode mThumbTintMode = null;
45911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    private boolean mHasThumbTint = false;
46b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette    private boolean mHasThumbTintMode = false;
47911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
4854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    private int mThumbOffset;
49661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private boolean mSplitTrack;
50661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
5154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
5254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * On touch, this offset plus the scaled value from the position of the
5354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * touch will form the progress value. Usually 0.
5454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
5554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    float mTouchProgressOffset;
5654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
5754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
5854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * Whether this is user seekable.
5954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
6054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    boolean mIsUserSeekable = true;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * On key presses (right or left), the amount to increment/decrement the
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * progress.
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mKeyProgressIncrement = 1;
67661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
6854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    private static final int NO_ALPHA = 0xFF;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mDisabledAlpha;
70661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
711029866a12e04e9db52485e2ec0353e764d15549Adam Powell    private int mScaledTouchSlop;
721029866a12e04e9db52485e2ec0353e764d15549Adam Powell    private float mTouchDownX;
731029866a12e04e9db52485e2ec0353e764d15549Adam Powell    private boolean mIsDragging;
741029866a12e04e9db52485e2ec0353e764d15549Adam Powell
7554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public AbsSeekBar(Context context) {
7654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super(context);
7754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
7854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
7954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public AbsSeekBar(Context context, AttributeSet attrs) {
8054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super(context, attrs);
8154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
8254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
83617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public AbsSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
84617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
85617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
86617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
87617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public AbsSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
88617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
8954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
90617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        TypedArray a = context.obtainStyledAttributes(
91617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                attrs, com.android.internal.R.styleable.SeekBar, defStyleAttr, defStyleRes);
92661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
93661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
94661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        setThumb(thumb);
95661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
96b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        if (a.hasValue(R.styleable.SeekBar_thumbTintMode)) {
97b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette            mThumbTintMode = Drawable.parseTintMode(a.getInt(
98b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette                    R.styleable.SeekBar_thumbTintMode, -1), mThumbTintMode);
99b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette            mHasThumbTintMode = true;
100b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        }
1014f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette
102911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        if (a.hasValue(R.styleable.SeekBar_thumbTint)) {
103a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette            mThumbTintList = a.getColorStateList(R.styleable.SeekBar_thumbTint);
104911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            mHasThumbTint = true;
105911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        }
106911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
107661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        // Guess thumb offset if thumb != null, but allow layout to override.
108661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int thumbOffset = a.getDimensionPixelOffset(
109992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
110992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy        setThumbOffset(thumbOffset);
111661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
112661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = a.getBoolean(com.android.internal.R.styleable.SeekBar_splitTrack, false);
11354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        a.recycle();
11454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
11554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        a = context.obtainStyledAttributes(attrs,
11654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                com.android.internal.R.styleable.Theme, 0, 0);
11754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.Theme_disabledAlpha, 0.5f);
11854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        a.recycle();
1191029866a12e04e9db52485e2ec0353e764d15549Adam Powell
120b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        applyThumbTint();
121b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette
1221029866a12e04e9db52485e2ec0353e764d15549Adam Powell        mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
12354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
12454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
12554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
1268d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler     * Sets the thumb that will be drawn at the end of the progress meter within the SeekBar.
1278d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler     * <p>
1288d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler     * If the thumb is a valid drawable (i.e. not null), half its width will be
1298d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler     * used as the new thumb offset (@see #setThumbOffset(int)).
130661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
13154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * @param thumb Drawable representing the thumb
13254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
13354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public void setThumb(Drawable thumb) {
134911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        final boolean needUpdate;
1352e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        // This way, calling setThumb again with the same bitmap will result in
1362e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        // it recalcuating mThumbOffset (if for example it the bounds of the
1372e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        // drawable changed)
1382e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        if (mThumb != null && thumb != mThumb) {
1392e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            mThumb.setCallback(null);
1402e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            needUpdate = true;
1412e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        } else {
1422e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            needUpdate = false;
1432e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        }
144911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
14554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (thumb != null) {
14654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            thumb.setCallback(this);
1470af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            if (canResolveLayoutDirection()) {
148e56ffdc7b31b0937628609cc3bbaa15879023569Fabrice Di Meglio                thumb.setLayoutDirection(getLayoutDirection());
1490af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            }
1508d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler
1518d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            // Assuming the thumb drawable is symmetric, set the thumb offset
1528d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            // such that the thumb will hang halfway off either edge of the
1538d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            // progress bar.
154992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            mThumbOffset = thumb.getIntrinsicWidth() / 2;
1552e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato
1562e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            // If we're updating get the new states
1572e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            if (needUpdate &&
1582e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                    (thumb.getIntrinsicWidth() != mThumb.getIntrinsicWidth()
1592e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                        || thumb.getIntrinsicHeight() != mThumb.getIntrinsicHeight())) {
1602e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                requestLayout();
1612e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            }
16254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
163911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
16454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        mThumb = thumb;
165911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
166911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        applyThumbTint();
16754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        invalidate();
168911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
1692e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        if (needUpdate) {
170661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            updateThumbAndTrackPos(getWidth(), getHeight());
1710283a5573c0a8b239f88147fe4ecf1b379e2f0a4Adam Powell            if (thumb != null && thumb.isStateful()) {
1722e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                // Note that if the states are different this won't work.
1732e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                // For now, let's consider that an app bug.
1742e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                int[] state = getDrawableState();
1752e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                thumb.setState(state);
1762e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            }
1772e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        }
17854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
17954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
18054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
1813004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     * Return the drawable used to represent the scroll thumb - the component that
1823004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     * the user can drag back and forth indicating the current value by its position.
1833004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     *
1843004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     * @return The current thumb drawable
1853004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     */
1863004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell    public Drawable getThumb() {
1873004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell        return mThumb;
1883004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell    }
1893004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell
1903004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell    /**
1914f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     * Applies a tint to the thumb drawable. Does not modify the current tint
192b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
193911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * <p>
194911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * Subsequent calls to {@link #setThumb(Drawable)} will automatically
195911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * mutate the drawable and apply the specified tint and tint mode using
196a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette     * {@link Drawable#setTintList(ColorStateList)}.
197911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     *
198911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * @param tint the tint to apply, may be {@code null} to clear tint
199911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     *
200911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * @attr ref android.R.styleable#SeekBar_thumbTint
201a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette     * @see #getThumbTintList()
202a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette     * @see Drawable#setTintList(ColorStateList)
203911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     */
204a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    public void setThumbTintList(@Nullable ColorStateList tint) {
205a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mThumbTintList = tint;
206911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        mHasThumbTint = true;
207911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
208911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        applyThumbTint();
209911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    }
210911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
211911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    /**
212b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     * Returns the tint applied to the thumb drawable, if specified.
213b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     *
214911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * @return the tint applied to the thumb drawable
215911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * @attr ref android.R.styleable#SeekBar_thumbTint
216a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette     * @see #setThumbTintList(ColorStateList)
217911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     */
218911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    @Nullable
219a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    public ColorStateList getThumbTintList() {
220a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        return mThumbTintList;
221911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    }
222911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
223911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    /**
224911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * Specifies the blending mode used to apply the tint specified by
225a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette     * {@link #setThumbTintList(ColorStateList)}} to the thumb drawable. The
226b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     * default mode is {@link PorterDuff.Mode#SRC_IN}.
227911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     *
228911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * @param tintMode the blending mode used to apply the tint, may be
229911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     *                 {@code null} to clear tint
2304f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     *
231911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * @attr ref android.R.styleable#SeekBar_thumbTintMode
2324f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     * @see #getThumbTintMode()
233a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette     * @see Drawable#setTintMode(PorterDuff.Mode)
234911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     */
235911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
2364f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette        mThumbTintMode = tintMode;
237b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        mHasThumbTintMode = true;
2384f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette
2394f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette        applyThumbTint();
240911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    }
241911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
242911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    /**
243b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     * Returns the blending mode used to apply the tint to the thumb drawable,
244b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     * if specified.
245b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     *
246911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * @return the blending mode used to apply the tint to the thumb drawable
247911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * @attr ref android.R.styleable#SeekBar_thumbTintMode
2484f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     * @see #setThumbTintMode(PorterDuff.Mode)
249911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     */
250911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    @Nullable
251911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    public PorterDuff.Mode getThumbTintMode() {
252911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        return mThumbTintMode;
253911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    }
254911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
255911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    private void applyThumbTint() {
256b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        if (mThumb != null && (mHasThumbTint || mHasThumbTintMode)) {
257911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            mThumb = mThumb.mutate();
258b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette
259b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette            if (mHasThumbTint) {
260b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette                mThumb.setTintList(mThumbTintList);
261b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette            }
262b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette
263b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette            if (mHasThumbTintMode) {
264b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette                mThumb.setTintMode(mThumbTintMode);
265b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette            }
266d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette
267d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette            // The drawable (or one of its children) may not have been
268d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette            // stateful before applying the tint, so let's try again.
269d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette            if (mThumb.isStateful()) {
270d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette                mThumb.setState(getDrawableState());
271d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette            }
272911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        }
273911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    }
274911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
275911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    /**
27654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * @see #setThumbOffset(int)
27754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
27854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public int getThumbOffset() {
27954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        return mThumbOffset;
28054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
28154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
28254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
28354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * Sets the thumb offset that allows the thumb to extend out of the range of
28454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * the track.
285661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
28654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * @param thumbOffset The offset amount in pixels.
28754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
28854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public void setThumbOffset(int thumbOffset) {
28954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        mThumbOffset = thumbOffset;
29054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        invalidate();
29154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
29254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
294661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Specifies whether the track should be split by the thumb. When true,
295661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * the thumb's optical bounds will be clipped out of the track drawable,
296661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * then the thumb will be drawn into the resulting gap.
297661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
298661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @param splitTrack Whether the track should be split by the thumb
299661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
300661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public void setSplitTrack(boolean splitTrack) {
301661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mSplitTrack = splitTrack;
302661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        invalidate();
303661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
304661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
305661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
306661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Returns whether the track should be split by the thumb.
307661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
308661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public boolean getSplitTrack() {
309661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        return mSplitTrack;
310661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
311661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
312661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the amount of progress changed via the arrow keys.
314661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param increment The amount to increment or decrement when the user
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            presses the arrow keys.
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setKeyProgressIncrement(int increment) {
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mKeyProgressIncrement = increment < 0 ? -increment : increment;
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the amount of progress changed via the arrow keys.
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * By default, this will be a value that is derived from the max progress.
326661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The amount to increment or decrement when the user presses the
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         arrow keys. This will be positive.
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getKeyProgressIncrement() {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mKeyProgressIncrement;
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
333661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized void setMax(int max) {
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.setMax(max);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // It will take the user too long to change this via keys, change it
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // to something more reasonable
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
34654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected boolean verifyDrawable(Drawable who) {
34754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        return who == mThumb || super.verifyDrawable(who);
34854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
34954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
35054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
351e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn    public void jumpDrawablesToCurrentState() {
352e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn        super.jumpDrawablesToCurrentState();
3538de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette
3548de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette        if (mThumb != null) {
3558de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette            mThumb.jumpToCurrentState();
3568de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette        }
357e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn    }
358e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn
359e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn    @Override
36054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected void drawableStateChanged() {
36154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super.drawableStateChanged();
362661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
363661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Drawable progressDrawable = getProgressDrawable();
36454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (progressDrawable != null) {
36554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
36654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
367661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
368661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Drawable thumb = mThumb;
369661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (thumb != null && thumb.isStateful()) {
370661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            thumb.setState(getDrawableState());
371b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project        }
37254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
373661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
374cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette    @Override
3758de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette    public void drawableHotspotChanged(float x, float y) {
3768de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette        super.drawableHotspotChanged(x, y);
377cebc6bab51d9c77db8f346c1390169eabac4f27dAlan Viverette
3788de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette        if (mThumb != null) {
3798de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette            mThumb.setHotspot(x, y);
3802356c5e69b0911e6334ebf6374217898371be5acAlan Viverette        }
3812356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    }
3822356c5e69b0911e6334ebf6374217898371be5acAlan Viverette
3832356c5e69b0911e6334ebf6374217898371be5acAlan Viverette    @Override
3846518ad760f98a0aa5db8c49ce1564bf5907a2c15Svetoslav Ganov    void onProgressRefresh(float scale, boolean fromUser) {
3856518ad760f98a0aa5db8c49ce1564bf5907a2c15Svetoslav Ganov        super.onProgressRefresh(scale, fromUser);
386661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
3875ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette        final Drawable thumb = mThumb;
3885ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette        if (thumb != null) {
3895ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette            setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
390661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
3915ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette            // Since we draw translated, the drawable's bounds that it signals
3925ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette            // for invalidation won't be the actual bounds we want invalidated,
3935ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette            // so just invalidate this whole view.
3945ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette            invalidate();
3955ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette        }
3960c11a489075e05ae84d3c8b5d7ac1ae293af00f9Jon Miranda    }
3970c11a489075e05ae84d3c8b5d7ac1ae293af00f9Jon Miranda
3980c11a489075e05ae84d3c8b5d7ac1ae293af00f9Jon Miranda    @Override
39954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
400f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        super.onSizeChanged(w, h, oldw, oldh);
401661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
402661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        updateThumbAndTrackPos(w, h);
4032e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    }
4042e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato
405661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private void updateThumbAndTrackPos(int w, int h) {
406661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Drawable track = getCurrentDrawable();
407661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Drawable thumb = mThumb;
408661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
40954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        // The max height does not incorporate padding, whereas the height
410661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        // parameter does.
411661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
412661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
413661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
414661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        // Apply offset to whichever item is taller.
415661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int trackOffset;
416661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int thumbOffset;
41754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (thumbHeight > trackHeight) {
418661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            trackOffset = (thumbHeight - trackHeight) / 2;
419661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            thumbOffset = 0;
42054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        } else {
421661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            trackOffset = 0;
422661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            thumbOffset = (trackHeight - thumbHeight) / 2;
423661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
424661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
425661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (track != null) {
426661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            track.setBounds(0, trackOffset, w - mPaddingRight - mPaddingLeft,
427661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette                    h - mPaddingBottom - trackOffset - mPaddingTop);
428661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
429661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
430661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (thumb != null) {
431661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            setThumbPos(w, thumb, getScale(), thumbOffset);
43254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
43354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
43454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
435661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private float getScale() {
436661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final int max = getMax();
437661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        return max > 0 ? getProgress() / (float) max : 0;
438661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
439661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
44054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
441661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Updates the thumb drawable bounds.
442661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
443661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @param w Width of the view, including padding
444661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @param thumb Drawable used for the thumb
445661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @param scale Current progress between 0 and 1
446661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * @param offset Vertical offset for centering. If set to
447661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *            {@link Integer#MIN_VALUE}, the current offset will be used.
44854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
449661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private void setThumbPos(int w, Drawable thumb, float scale, int offset) {
45054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int available = w - mPaddingLeft - mPaddingRight;
45161956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int thumbWidth = thumb.getIntrinsicWidth();
45261956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int thumbHeight = thumb.getIntrinsicHeight();
45354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        available -= thumbWidth;
45454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
45554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        // The extra space for the thumb to move on the track
45654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        available += mThumbOffset * 2;
45754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
45861956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int thumbPos = (int) (scale * available + 0.5f);
45954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
46061956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int top, bottom;
461661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (offset == Integer.MIN_VALUE) {
46261956606818918194a38e045a8e35e7108480e5eAlan Viverette            final Rect oldBounds = thumb.getBounds();
46361956606818918194a38e045a8e35e7108480e5eAlan Viverette            top = oldBounds.top;
46461956606818918194a38e045a8e35e7108480e5eAlan Viverette            bottom = oldBounds.bottom;
46554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        } else {
466661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            top = offset;
467661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            bottom = offset + thumbHeight;
46854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
46961956606818918194a38e045a8e35e7108480e5eAlan Viverette
4702b378cde411b551464f0040e935692073cfb119fFabrice Di Meglio        final int left = (isLayoutRtl() && mMirrorForRtl) ? available - thumbPos : thumbPos;
47161956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int right = left + thumbWidth;
47261956606818918194a38e045a8e35e7108480e5eAlan Viverette
47361956606818918194a38e045a8e35e7108480e5eAlan Viverette        final Drawable background = getBackground();
474c80ad99a33ee49d0bac994c1749ff24d243c3862Alan Viverette        if (background != null) {
4758de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette            final Rect bounds = thumb.getBounds();
47661956606818918194a38e045a8e35e7108480e5eAlan Viverette            final int offsetX = mPaddingLeft - mThumbOffset;
47761956606818918194a38e045a8e35e7108480e5eAlan Viverette            final int offsetY = mPaddingTop;
478304624100b363137913d1d910690fc83872e41c3Alan Viverette            background.setHotspotBounds(left + offsetX, top + offsetY,
479304624100b363137913d1d910690fc83872e41c3Alan Viverette                    right + offsetX, bottom + offsetY);
48061956606818918194a38e045a8e35e7108480e5eAlan Viverette        }
48161956606818918194a38e045a8e35e7108480e5eAlan Viverette
48261956606818918194a38e045a8e35e7108480e5eAlan Viverette        // Canvas will be translated, so 0,0 is where we start drawing
48361956606818918194a38e045a8e35e7108480e5eAlan Viverette        thumb.setBounds(left, top, right, bottom);
48454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
4850af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio
4864457e85a7090ad51726d50a4daf981d917cceeddFabrice Di Meglio    /**
4874457e85a7090ad51726d50a4daf981d917cceeddFabrice Di Meglio     * @hide
4884457e85a7090ad51726d50a4daf981d917cceeddFabrice Di Meglio     */
4890af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    @Override
4900af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    public void onResolveDrawables(int layoutDirection) {
4910af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        super.onResolveDrawables(layoutDirection);
4920af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio
4930af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        if (mThumb != null) {
4940af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            mThumb.setLayoutDirection(layoutDirection);
4950af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        }
4960af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    }
4970af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio
49854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
49954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected synchronized void onDraw(Canvas canvas) {
50054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super.onDraw(canvas);
501661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        drawThumb(canvas);
5028de1494557cf1d00c1c3fce439138a28de7fbd61Alan Viverette
503661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
504661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
505661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    @Override
506661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    void drawTrack(Canvas canvas) {
507661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Drawable thumbDrawable = mThumb;
508661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (thumbDrawable != null && mSplitTrack) {
509661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            final Insets insets = thumbDrawable.getOpticalInsets();
510661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            final Rect tempRect = mTempRect;
511661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            thumbDrawable.copyBounds(tempRect);
512661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            tempRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
513661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            tempRect.left += insets.left;
514661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            tempRect.right -= insets.right;
515661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
516661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            final int saveCount = canvas.save();
517661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            canvas.clipRect(tempRect, Op.DIFFERENCE);
518661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            super.drawTrack(canvas);
519661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            canvas.restoreToCount(saveCount);
520661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        } else {
521661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            super.drawTrack(canvas);
522661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
523661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
524661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
525661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
526661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Draw the thumb.
527661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
528661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    void drawThumb(Canvas canvas) {
52954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (mThumb != null) {
53054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            canvas.save();
53154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            // Translate the padding. For the x, we need to allow the thumb to
53254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            // draw in its extra space
53354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
53454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            mThumb.draw(canvas);
53554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            canvas.restore();
53654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
53754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
53854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
53954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
54054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
54154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        Drawable d = getCurrentDrawable();
54254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
54354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int thumbHeight = mThumb == null ? 0 : mThumb.getIntrinsicHeight();
54454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int dw = 0;
54554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int dh = 0;
54654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (d != null) {
54754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
54854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
54954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            dh = Math.max(thumbHeight, dh);
55054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
55154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        dw += mPaddingLeft + mPaddingRight;
55254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        dh += mPaddingTop + mPaddingBottom;
553661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
554189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn        setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
555189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn                resolveSizeAndState(dh, heightMeasureSpec, 0));
55654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
557661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
55854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
55954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public boolean onTouchEvent(MotionEvent event) {
56054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (!mIsUserSeekable || !isEnabled()) {
56154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            return false;
56254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
563661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
56454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        switch (event.getAction()) {
56554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            case MotionEvent.ACTION_DOWN:
5661029866a12e04e9db52485e2ec0353e764d15549Adam Powell                if (isInScrollingContainer()) {
5671029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    mTouchDownX = event.getX();
5681029866a12e04e9db52485e2ec0353e764d15549Adam Powell                } else {
5691029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    setPressed(true);
5702c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                    if (mThumb != null) {
5712c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                        invalidate(mThumb.getBounds()); // This may be within the padding region
5722c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                    }
5731029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStartTrackingTouch();
5741029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    trackTouchEvent(event);
5751029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    attemptClaimDrag();
5761029866a12e04e9db52485e2ec0353e764d15549Adam Powell                }
57754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                break;
578661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
57954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            case MotionEvent.ACTION_MOVE:
5801029866a12e04e9db52485e2ec0353e764d15549Adam Powell                if (mIsDragging) {
5811029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    trackTouchEvent(event);
5821029866a12e04e9db52485e2ec0353e764d15549Adam Powell                } else {
5831029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    final float x = event.getX();
5841029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    if (Math.abs(x - mTouchDownX) > mScaledTouchSlop) {
5851029866a12e04e9db52485e2ec0353e764d15549Adam Powell                        setPressed(true);
5862c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                        if (mThumb != null) {
5872c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                            invalidate(mThumb.getBounds()); // This may be within the padding region
5882c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                        }
5891029866a12e04e9db52485e2ec0353e764d15549Adam Powell                        onStartTrackingTouch();
5901029866a12e04e9db52485e2ec0353e764d15549Adam Powell                        trackTouchEvent(event);
5911029866a12e04e9db52485e2ec0353e764d15549Adam Powell                        attemptClaimDrag();
5921029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    }
5931029866a12e04e9db52485e2ec0353e764d15549Adam Powell                }
59454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                break;
595661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
59654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            case MotionEvent.ACTION_UP:
5971029866a12e04e9db52485e2ec0353e764d15549Adam Powell                if (mIsDragging) {
5981029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    trackTouchEvent(event);
5991029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStopTrackingTouch();
6001029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    setPressed(false);
6011029866a12e04e9db52485e2ec0353e764d15549Adam Powell                } else {
6021029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    // Touch up when we never crossed the touch slop threshold should
6031029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    // be interpreted as a tap-seek to that location.
6041029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStartTrackingTouch();
6051029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    trackTouchEvent(event);
6061029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStopTrackingTouch();
6071029866a12e04e9db52485e2ec0353e764d15549Adam Powell                }
608eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                // ProgressBar doesn't know to repaint the thumb drawable
609eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                // in its inactive state when the touch stops (because the
610eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                // value has not apparently changed)
611eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                invalidate();
61254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                break;
613661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
61454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            case MotionEvent.ACTION_CANCEL:
6151029866a12e04e9db52485e2ec0353e764d15549Adam Powell                if (mIsDragging) {
6161029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStopTrackingTouch();
6171029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    setPressed(false);
6181029866a12e04e9db52485e2ec0353e764d15549Adam Powell                }
619eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                invalidate(); // see above explanation
62054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                break;
62154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
62254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        return true;
62354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
62454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
625c80ad99a33ee49d0bac994c1749ff24d243c3862Alan Viverette    private void setHotspot(float x, float y) {
62661956606818918194a38e045a8e35e7108480e5eAlan Viverette        final Drawable bg = getBackground();
627c80ad99a33ee49d0bac994c1749ff24d243c3862Alan Viverette        if (bg != null) {
628c80ad99a33ee49d0bac994c1749ff24d243c3862Alan Viverette            bg.setHotspot(x, y);
62961956606818918194a38e045a8e35e7108480e5eAlan Viverette        }
63061956606818918194a38e045a8e35e7108480e5eAlan Viverette    }
63161956606818918194a38e045a8e35e7108480e5eAlan Viverette
63254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    private void trackTouchEvent(MotionEvent event) {
63354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        final int width = getWidth();
63454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        final int available = width - mPaddingLeft - mPaddingRight;
63561956606818918194a38e045a8e35e7108480e5eAlan Viverette        final int x = (int) event.getX();
63654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        float scale;
63754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        float progress = 0;
6382b378cde411b551464f0040e935692073cfb119fFabrice Di Meglio        if (isLayoutRtl() && mMirrorForRtl) {
6390af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            if (x > width - mPaddingRight) {
6400af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = 0.0f;
6410af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            } else if (x < mPaddingLeft) {
6420af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = 1.0f;
6430af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            } else {
6440af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = (float)(available - x + mPaddingLeft) / (float)available;
6450af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                progress = mTouchProgressOffset;
6460af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            }
64754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        } else {
6480af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            if (x < mPaddingLeft) {
6490af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = 0.0f;
6500af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            } else if (x > width - mPaddingRight) {
6510af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = 1.0f;
6520af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            } else {
6530af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = (float)(x - mPaddingLeft) / (float)available;
6540af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                progress = mTouchProgressOffset;
6550af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            }
65654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
65769577ae794751e6ecaca6a580b1b33545bd21082Jean-Baptiste Queru        final int max = getMax();
65854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        progress += scale * max;
65961956606818918194a38e045a8e35e7108480e5eAlan Viverette
660c80ad99a33ee49d0bac994c1749ff24d243c3862Alan Viverette        setHotspot(x, (int) event.getY());
66154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        setProgress((int) progress, true);
66254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
663f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project
664f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project    /**
665f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project     * Tries to claim the user's drag motion, and requests disallowing any
666f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project     * ancestors from stealing events in the drag.
667f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project     */
668f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project    private void attemptClaimDrag() {
669f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project        if (mParent != null) {
670f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project            mParent.requestDisallowInterceptTouchEvent(true);
671f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project        }
672f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project    }
673661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
67454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
67554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * This is called when the user has started touching this widget.
67654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
67754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    void onStartTrackingTouch() {
6781029866a12e04e9db52485e2ec0353e764d15549Adam Powell        mIsDragging = true;
67954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
68054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
68154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
68254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * This is called when the user either releases his touch or the touch is
68354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * canceled.
68454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
68554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    void onStopTrackingTouch() {
6861029866a12e04e9db52485e2ec0353e764d15549Adam Powell        mIsDragging = false;
68754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
68854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
689105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /**
690105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * Called when the user changes the seekbar's progress by using a key event.
691105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     */
692105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    void onKeyChange() {
693105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
694105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
695b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project    @Override
696b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
697992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy        if (isEnabled()) {
698992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            int progress = getProgress();
699992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            switch (keyCode) {
700992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                case KeyEvent.KEYCODE_DPAD_LEFT:
701992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    if (progress <= 0) break;
7025ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette                    setProgress(progress - mKeyProgressIncrement, true);
703992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    onKeyChange();
704992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    return true;
705661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
706992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                case KeyEvent.KEYCODE_DPAD_RIGHT:
707992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    if (progress >= getMax()) break;
7085ce0ec0efd541362359bfead8e62ade80a0425caAlan Viverette                    setProgress(progress + mKeyProgressIncrement, true);
709992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    onKeyChange();
710992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    return true;
711992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            }
712b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project        }
713b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project
714b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project        return super.onKeyDown(keyCode, event);
715b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project    }
716b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project
7178a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
7188a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
7198a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
7208a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(AbsSeekBar.class.getName());
7218a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
7228a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
7238a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
7248a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
7258a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
7268a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(AbsSeekBar.class.getName());
727c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv
728c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        if (isEnabled()) {
729c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            final int progress = getProgress();
730c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            if (progress > 0) {
731c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
732c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            }
733c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            if (progress < getMax()) {
734c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
735c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            }
736c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        }
737c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv    }
738c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv
739c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv    @Override
740c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv    public boolean performAccessibilityAction(int action, Bundle arguments) {
741c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        if (super.performAccessibilityAction(action, arguments)) {
742c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            return true;
743c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        }
744c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        if (!isEnabled()) {
745c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            return false;
746c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        }
747c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        final int progress = getProgress();
748c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        final int increment = Math.max(1, Math.round((float) getMax() / 5));
749c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        switch (action) {
750c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
751c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                if (progress <= 0) {
752c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                    return false;
753c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                }
754c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                setProgress(progress - increment, true);
755c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                onKeyChange();
756c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                return true;
757c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            }
758c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
759c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                if (progress >= getMax()) {
760c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                    return false;
761c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                }
762c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                setProgress(progress + increment, true);
763c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                onKeyChange();
764c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                return true;
765c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            }
766c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        }
767c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        return false;
7688a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
769f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio
770f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio    @Override
771f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio    public void onRtlPropertiesChanged(int layoutDirection) {
772f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        super.onRtlPropertiesChanged(layoutDirection);
773f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio
774661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final Drawable thumb = mThumb;
775f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        if (thumb != null) {
776661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            setThumbPos(getWidth(), thumb, getScale(), Integer.MIN_VALUE);
777661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
778661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            // Since we draw translated, the drawable's bounds that it signals
779661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            // for invalidation won't be the actual bounds we want invalidated,
780661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            // so just invalidate this whole view.
781f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio            invalidate();
782f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        }
783f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio    }
78454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project}
785