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
1954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.content.Context;
2054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.content.res.TypedArray;
2154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.graphics.Canvas;
2254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.graphics.Rect;
2354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.graphics.drawable.Drawable;
24c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanvimport android.os.Bundle;
2554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.util.AttributeSet;
26b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Projectimport android.view.KeyEvent;
2754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.view.MotionEvent;
281029866a12e04e9db52485e2ec0353e764d15549Adam Powellimport android.view.ViewConfiguration;
298a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
308a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
3154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
3254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectpublic abstract class AbsSeekBar extends ProgressBar {
3354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    private Drawable mThumb;
3454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    private int mThumbOffset;
3554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
3654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
3754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * On touch, this offset plus the scaled value from the position of the
3854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * touch will form the progress value. Usually 0.
3954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
4054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    float mTouchProgressOffset;
4154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
4254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
4354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * Whether this is user seekable.
4454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
4554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    boolean mIsUserSeekable = true;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * On key presses (right or left), the amount to increment/decrement the
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * progress.
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mKeyProgressIncrement = 1;
5254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
5354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    private static final int NO_ALPHA = 0xFF;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mDisabledAlpha;
5554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
561029866a12e04e9db52485e2ec0353e764d15549Adam Powell    private int mScaledTouchSlop;
571029866a12e04e9db52485e2ec0353e764d15549Adam Powell    private float mTouchDownX;
581029866a12e04e9db52485e2ec0353e764d15549Adam Powell    private boolean mIsDragging;
591029866a12e04e9db52485e2ec0353e764d15549Adam Powell
6054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public AbsSeekBar(Context context) {
6154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super(context);
6254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
6354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
6454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public AbsSeekBar(Context context, AttributeSet attrs) {
6554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super(context, attrs);
6654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
6754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
6854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public AbsSeekBar(Context context, AttributeSet attrs, int defStyle) {
6954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super(context, attrs, defStyle);
7054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
7154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs,
7254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                com.android.internal.R.styleable.SeekBar, defStyle, 0);
7354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
748d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler        setThumb(thumb); // will guess mThumbOffset if thumb != null...
758d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler        // ...but allow layout to override this
76992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy        int thumbOffset = a.getDimensionPixelOffset(
77992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
78992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy        setThumbOffset(thumbOffset);
7954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        a.recycle();
8054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
8154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        a = context.obtainStyledAttributes(attrs,
8254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                com.android.internal.R.styleable.Theme, 0, 0);
8354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.Theme_disabledAlpha, 0.5f);
8454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        a.recycle();
851029866a12e04e9db52485e2ec0353e764d15549Adam Powell
861029866a12e04e9db52485e2ec0353e764d15549Adam Powell        mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
8754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
8854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
8954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
908d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler     * Sets the thumb that will be drawn at the end of the progress meter within the SeekBar.
918d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler     * <p>
928d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler     * If the thumb is a valid drawable (i.e. not null), half its width will be
938d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler     * used as the new thumb offset (@see #setThumbOffset(int)).
9454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     *
9554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * @param thumb Drawable representing the thumb
9654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
9754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public void setThumb(Drawable thumb) {
982e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        boolean needUpdate;
992e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        // This way, calling setThumb again with the same bitmap will result in
1002e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        // it recalcuating mThumbOffset (if for example it the bounds of the
1012e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        // drawable changed)
1022e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        if (mThumb != null && thumb != mThumb) {
1032e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            mThumb.setCallback(null);
1042e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            needUpdate = true;
1052e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        } else {
1062e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            needUpdate = false;
1072e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        }
10854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (thumb != null) {
10954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            thumb.setCallback(this);
1100af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            if (canResolveLayoutDirection()) {
111e56ffdc7b31b0937628609cc3bbaa15879023569Fabrice Di Meglio                thumb.setLayoutDirection(getLayoutDirection());
1120af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            }
1138d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler
1148d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            // Assuming the thumb drawable is symmetric, set the thumb offset
1158d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            // such that the thumb will hang halfway off either edge of the
1168d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            // progress bar.
117992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            mThumbOffset = thumb.getIntrinsicWidth() / 2;
1182e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato
1192e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            // If we're updating get the new states
1202e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            if (needUpdate &&
1212e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                    (thumb.getIntrinsicWidth() != mThumb.getIntrinsicWidth()
1222e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                        || thumb.getIntrinsicHeight() != mThumb.getIntrinsicHeight())) {
1232e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                requestLayout();
1242e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            }
12554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
12654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        mThumb = thumb;
12754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        invalidate();
1282e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        if (needUpdate) {
1292e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            updateThumbPos(getWidth(), getHeight());
1300283a5573c0a8b239f88147fe4ecf1b379e2f0a4Adam Powell            if (thumb != null && thumb.isStateful()) {
1312e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                // Note that if the states are different this won't work.
1322e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                // For now, let's consider that an app bug.
1332e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                int[] state = getDrawableState();
1342e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato                thumb.setState(state);
1352e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            }
1362e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        }
13754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
13854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
13954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
1403004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     * Return the drawable used to represent the scroll thumb - the component that
1413004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     * the user can drag back and forth indicating the current value by its position.
1423004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     *
1433004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     * @return The current thumb drawable
1443004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell     */
1453004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell    public Drawable getThumb() {
1463004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell        return mThumb;
1473004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell    }
1483004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell
1493004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell    /**
15054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * @see #setThumbOffset(int)
15154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
15254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public int getThumbOffset() {
15354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        return mThumbOffset;
15454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
15554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
15654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
15754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * Sets the thumb offset that allows the thumb to extend out of the range of
15854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * the track.
15954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     *
16054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * @param thumbOffset The offset amount in pixels.
16154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
16254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public void setThumbOffset(int thumbOffset) {
16354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        mThumbOffset = thumbOffset;
16454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        invalidate();
16554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
16654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the amount of progress changed via the arrow keys.
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param increment The amount to increment or decrement when the user
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            presses the arrow keys.
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setKeyProgressIncrement(int increment) {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mKeyProgressIncrement = increment < 0 ? -increment : increment;
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the amount of progress changed via the arrow keys.
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * By default, this will be a value that is derived from the max progress.
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The amount to increment or decrement when the user presses the
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         arrow keys. This will be positive.
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getKeyProgressIncrement() {
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mKeyProgressIncrement;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized void setMax(int max) {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.setMax(max);
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // It will take the user too long to change this via keys, change it
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // to something more reasonable
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
20154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected boolean verifyDrawable(Drawable who) {
20254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        return who == mThumb || super.verifyDrawable(who);
20354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
20454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
20554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
206e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn    public void jumpDrawablesToCurrentState() {
207e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn        super.jumpDrawablesToCurrentState();
208e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn        if (mThumb != null) mThumb.jumpToCurrentState();
209e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn    }
210e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn
211e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn    @Override
21254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected void drawableStateChanged() {
21354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super.drawableStateChanged();
21454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
21554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        Drawable progressDrawable = getProgressDrawable();
21654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (progressDrawable != null) {
21754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
21854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
219b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project
220b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project        if (mThumb != null && mThumb.isStateful()) {
221b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project            int[] state = getDrawableState();
222b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project            mThumb.setState(state);
223b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project        }
22454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
22554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
22654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
2276518ad760f98a0aa5db8c49ce1564bf5907a2c15Svetoslav Ganov    void onProgressRefresh(float scale, boolean fromUser) {
2286518ad760f98a0aa5db8c49ce1564bf5907a2c15Svetoslav Ganov        super.onProgressRefresh(scale, fromUser);
22954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        Drawable thumb = mThumb;
23054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (thumb != null) {
231105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
23254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            /*
23354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project             * Since we draw translated, the drawable's bounds that it signals
23454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project             * for invalidation won't be the actual bounds we want invalidated,
23554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project             * so just invalidate this whole view.
23654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project             */
23754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            invalidate();
23854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
23954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
24054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
24154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
24254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
24354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
244f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        super.onSizeChanged(w, h, oldw, oldh);
2452e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        updateThumbPos(w, h);
2462e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    }
2472e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato
2482e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    private void updateThumbPos(int w, int h) {
24954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        Drawable d = getCurrentDrawable();
25054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        Drawable thumb = mThumb;
25154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
25254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        // The max height does not incorporate padding, whereas the height
25354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        // parameter does
25454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
25554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
25654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int max = getMax();
25754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        float scale = max > 0 ? (float) getProgress() / (float) max : 0;
25854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
25954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (thumbHeight > trackHeight) {
26054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            if (thumb != null) {
261105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                setThumbPos(w, thumb, scale, 0);
26254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            }
26354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            int gapForCenteringTrack = (thumbHeight - trackHeight) / 2;
26454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            if (d != null) {
26554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                // Canvas will be translated by the padding, so 0,0 is where we start drawing
26654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                d.setBounds(0, gapForCenteringTrack,
26754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                        w - mPaddingRight - mPaddingLeft, h - mPaddingBottom - gapForCenteringTrack
26854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                        - mPaddingTop);
26954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            }
27054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        } else {
27154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            if (d != null) {
27254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                // Canvas will be translated by the padding, so 0,0 is where we start drawing
27354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                d.setBounds(0, 0, w - mPaddingRight - mPaddingLeft, h - mPaddingBottom
27454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                        - mPaddingTop);
27554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            }
27654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            int gap = (trackHeight - thumbHeight) / 2;
27754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            if (thumb != null) {
278105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                setThumbPos(w, thumb, scale, gap);
27954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            }
28054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
28154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
28254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
28354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
28454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * @param gap If set to {@link Integer#MIN_VALUE}, this will be ignored and
28554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
286105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
28754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int available = w - mPaddingLeft - mPaddingRight;
28854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int thumbWidth = thumb.getIntrinsicWidth();
28954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int thumbHeight = thumb.getIntrinsicHeight();
29054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        available -= thumbWidth;
29154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
29254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        // The extra space for the thumb to move on the track
29354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        available += mThumbOffset * 2;
29454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
29554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int thumbPos = (int) (scale * available);
29654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
29754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int topBound, bottomBound;
29854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (gap == Integer.MIN_VALUE) {
29954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            Rect oldBounds = thumb.getBounds();
30054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            topBound = oldBounds.top;
30154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            bottomBound = oldBounds.bottom;
30254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        } else {
30354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            topBound = gap;
30454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            bottomBound = gap + thumbHeight;
30554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
30654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
30754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        // Canvas will be translated, so 0,0 is where we start drawing
30806849e8f5368831086b0c33f9037a015fb00e864Fabrice Di Meglio        final int left = isLayoutRtl() ? available - thumbPos : thumbPos;
30906849e8f5368831086b0c33f9037a015fb00e864Fabrice Di Meglio        thumb.setBounds(left, topBound, left + thumbWidth, bottomBound);
31054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
3110af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio
3124457e85a7090ad51726d50a4daf981d917cceeddFabrice Di Meglio    /**
3134457e85a7090ad51726d50a4daf981d917cceeddFabrice Di Meglio     * @hide
3144457e85a7090ad51726d50a4daf981d917cceeddFabrice Di Meglio     */
3150af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    @Override
3160af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    public void onResolveDrawables(int layoutDirection) {
3170af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        super.onResolveDrawables(layoutDirection);
3180af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio
3190af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        if (mThumb != null) {
3200af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            mThumb.setLayoutDirection(layoutDirection);
3210af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        }
3220af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    }
3230af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio
32454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
32554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected synchronized void onDraw(Canvas canvas) {
32654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super.onDraw(canvas);
32754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (mThumb != null) {
32854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            canvas.save();
32954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            // Translate the padding. For the x, we need to allow the thumb to
33054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            // draw in its extra space
33154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
33254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            mThumb.draw(canvas);
33354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            canvas.restore();
33454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
33554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
33654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
33754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
33854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
33954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        Drawable d = getCurrentDrawable();
34054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
34154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int thumbHeight = mThumb == null ? 0 : mThumb.getIntrinsicHeight();
34254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int dw = 0;
34354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int dh = 0;
34454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (d != null) {
34554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
34654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
34754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            dh = Math.max(thumbHeight, dh);
34854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
34954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        dw += mPaddingLeft + mPaddingRight;
35054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        dh += mPaddingTop + mPaddingBottom;
35154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
352189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn        setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
353189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn                resolveSizeAndState(dh, heightMeasureSpec, 0));
35454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
35554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
35654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
35754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    public boolean onTouchEvent(MotionEvent event) {
35854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (!mIsUserSeekable || !isEnabled()) {
35954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            return false;
36054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
36154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
36254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        switch (event.getAction()) {
36354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            case MotionEvent.ACTION_DOWN:
3641029866a12e04e9db52485e2ec0353e764d15549Adam Powell                if (isInScrollingContainer()) {
3651029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    mTouchDownX = event.getX();
3661029866a12e04e9db52485e2ec0353e764d15549Adam Powell                } else {
3671029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    setPressed(true);
3682c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                    if (mThumb != null) {
3692c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                        invalidate(mThumb.getBounds()); // This may be within the padding region
3702c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                    }
3711029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStartTrackingTouch();
3721029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    trackTouchEvent(event);
3731029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    attemptClaimDrag();
3741029866a12e04e9db52485e2ec0353e764d15549Adam Powell                }
37554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                break;
37654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
37754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            case MotionEvent.ACTION_MOVE:
3781029866a12e04e9db52485e2ec0353e764d15549Adam Powell                if (mIsDragging) {
3791029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    trackTouchEvent(event);
3801029866a12e04e9db52485e2ec0353e764d15549Adam Powell                } else {
3811029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    final float x = event.getX();
3821029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    if (Math.abs(x - mTouchDownX) > mScaledTouchSlop) {
3831029866a12e04e9db52485e2ec0353e764d15549Adam Powell                        setPressed(true);
3842c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                        if (mThumb != null) {
3852c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                            invalidate(mThumb.getBounds()); // This may be within the padding region
3862c5b8cc71bc8ac1efa944568c1292929073bbc36Adam Powell                        }
3871029866a12e04e9db52485e2ec0353e764d15549Adam Powell                        onStartTrackingTouch();
3881029866a12e04e9db52485e2ec0353e764d15549Adam Powell                        trackTouchEvent(event);
3891029866a12e04e9db52485e2ec0353e764d15549Adam Powell                        attemptClaimDrag();
3901029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    }
3911029866a12e04e9db52485e2ec0353e764d15549Adam Powell                }
39254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                break;
39354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
39454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            case MotionEvent.ACTION_UP:
3951029866a12e04e9db52485e2ec0353e764d15549Adam Powell                if (mIsDragging) {
3961029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    trackTouchEvent(event);
3971029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStopTrackingTouch();
3981029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    setPressed(false);
3991029866a12e04e9db52485e2ec0353e764d15549Adam Powell                } else {
4001029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    // Touch up when we never crossed the touch slop threshold should
4011029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    // be interpreted as a tap-seek to that location.
4021029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStartTrackingTouch();
4031029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    trackTouchEvent(event);
4041029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStopTrackingTouch();
4051029866a12e04e9db52485e2ec0353e764d15549Adam Powell                }
406eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                // ProgressBar doesn't know to repaint the thumb drawable
407eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                // in its inactive state when the touch stops (because the
408eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                // value has not apparently changed)
409eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                invalidate();
41054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                break;
41154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
41254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            case MotionEvent.ACTION_CANCEL:
4131029866a12e04e9db52485e2ec0353e764d15549Adam Powell                if (mIsDragging) {
4141029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    onStopTrackingTouch();
4151029866a12e04e9db52485e2ec0353e764d15549Adam Powell                    setPressed(false);
4161029866a12e04e9db52485e2ec0353e764d15549Adam Powell                }
417eb9fdc21b14368b2f8c71939eb063ddcee8c28a2Daniel Sandler                invalidate(); // see above explanation
41854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                break;
41954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
42054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        return true;
42154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
42254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
42354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    private void trackTouchEvent(MotionEvent event) {
42454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        final int width = getWidth();
42554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        final int available = width - mPaddingLeft - mPaddingRight;
42654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int x = (int)event.getX();
42754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        float scale;
42854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        float progress = 0;
4290af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        if (isLayoutRtl()) {
4300af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            if (x > width - mPaddingRight) {
4310af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = 0.0f;
4320af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            } else if (x < mPaddingLeft) {
4330af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = 1.0f;
4340af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            } else {
4350af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = (float)(available - x + mPaddingLeft) / (float)available;
4360af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                progress = mTouchProgressOffset;
4370af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            }
43854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        } else {
4390af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            if (x < mPaddingLeft) {
4400af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = 0.0f;
4410af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            } else if (x > width - mPaddingRight) {
4420af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = 1.0f;
4430af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            } else {
4440af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                scale = (float)(x - mPaddingLeft) / (float)available;
4450af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                progress = mTouchProgressOffset;
4460af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            }
44754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
44869577ae794751e6ecaca6a580b1b33545bd21082Jean-Baptiste Queru        final int max = getMax();
44954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        progress += scale * max;
45054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
45154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        setProgress((int) progress, true);
45254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
453f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project
454f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project    /**
455f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project     * Tries to claim the user's drag motion, and requests disallowing any
456f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project     * ancestors from stealing events in the drag.
457f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project     */
458f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project    private void attemptClaimDrag() {
459f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project        if (mParent != null) {
460f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project            mParent.requestDisallowInterceptTouchEvent(true);
461f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project        }
462f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project    }
46354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
46454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
46554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * This is called when the user has started touching this widget.
46654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
46754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    void onStartTrackingTouch() {
4681029866a12e04e9db52485e2ec0353e764d15549Adam Powell        mIsDragging = true;
46954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
47054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
47154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
47254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * This is called when the user either releases his touch or the touch is
47354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * canceled.
47454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
47554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    void onStopTrackingTouch() {
4761029866a12e04e9db52485e2ec0353e764d15549Adam Powell        mIsDragging = false;
47754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
47854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
479105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /**
480105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * Called when the user changes the seekbar's progress by using a key event.
481105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     */
482105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    void onKeyChange() {
483105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
484105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
485b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project    @Override
486b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
487992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy        if (isEnabled()) {
488992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            int progress = getProgress();
489992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            switch (keyCode) {
490992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                case KeyEvent.KEYCODE_DPAD_LEFT:
491992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    if (progress <= 0) break;
492992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    setProgress(progress - mKeyProgressIncrement, true);
493992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    onKeyChange();
494992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    return true;
495992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy
496992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                case KeyEvent.KEYCODE_DPAD_RIGHT:
497992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    if (progress >= getMax()) break;
498992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    setProgress(progress + mKeyProgressIncrement, true);
499992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    onKeyChange();
500992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy                    return true;
501992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            }
502b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project        }
503b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project
504b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project        return super.onKeyDown(keyCode, event);
505b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project    }
506b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project
5078a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
5088a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
5098a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
5108a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(AbsSeekBar.class.getName());
5118a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
5128a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
5138a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
5148a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
5158a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
5168a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(AbsSeekBar.class.getName());
517c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv
518c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        if (isEnabled()) {
519c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            final int progress = getProgress();
520c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            if (progress > 0) {
521c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
522c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            }
523c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            if (progress < getMax()) {
524c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
525c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            }
526c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        }
527c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv    }
528c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv
529c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv    @Override
530c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv    public boolean performAccessibilityAction(int action, Bundle arguments) {
531c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        if (super.performAccessibilityAction(action, arguments)) {
532c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            return true;
533c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        }
534c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        if (!isEnabled()) {
535c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            return false;
536c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        }
537c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        final int progress = getProgress();
538c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        final int increment = Math.max(1, Math.round((float) getMax() / 5));
539c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        switch (action) {
540c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
541c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                if (progress <= 0) {
542c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                    return false;
543c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                }
544c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                setProgress(progress - increment, true);
545c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                onKeyChange();
546c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                return true;
547c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            }
548c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
549c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                if (progress >= getMax()) {
550c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                    return false;
551c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                }
552c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                setProgress(progress + increment, true);
553c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                onKeyChange();
554c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv                return true;
555c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv            }
556c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        }
557c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv        return false;
5588a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
559f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio
560f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio    @Override
561f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio    public void onRtlPropertiesChanged(int layoutDirection) {
562f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        super.onRtlPropertiesChanged(layoutDirection);
563f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio
564f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        int max = getMax();
565f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        float scale = max > 0 ? (float) getProgress() / (float) max : 0;
566f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio
567f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        Drawable thumb = mThumb;
568f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        if (thumb != null) {
569f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio            setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
570f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio            /*
571f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio             * Since we draw translated, the drawable's bounds that it signals
572f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio             * for invalidation won't be the actual bounds we want invalidated,
573f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio             * so just invalidate this whole view.
574f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio             */
575f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio            invalidate();
576f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio        }
577f37df1b6c23316e3050a399f9218087c4000564aFabrice Di Meglio    }
57854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project}
579