1f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen/*
2f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Copyright (C) 2007 The Android Open Source Project
3f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen *
4f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Licensed under the Apache License, Version 2.0 (the "License");
5f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * you may not use this file except in compliance with the License.
6f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * You may obtain a copy of the License at
7f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen *
8f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen *      http://www.apache.org/licenses/LICENSE-2.0
9f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen *
10f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Unless required by applicable law or agreed to in writing, software
11f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * distributed under the License is distributed on an "AS IS" BASIS,
12f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * See the License for the specific language governing permissions and
14f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * limitations under the License.
15f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */
16f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
17f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenpackage com.android.musicfx.seekbar;
18f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
19f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenimport android.content.Context;
20f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenimport android.content.res.TypedArray;
21f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenimport android.graphics.Canvas;
22f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenimport android.graphics.Rect;
23f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenimport android.graphics.drawable.Drawable;
24f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenimport android.util.AttributeSet;
25f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenimport android.view.KeyEvent;
26f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenimport android.view.MotionEvent;
27f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
28f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenpublic abstract class AbsSeekBar extends ProgressBar {
29f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    private Drawable mThumb;
30f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    private int mThumbOffset;
31f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
32f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
33f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * On touch, this offset plus the scaled value from the position of the
34f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * touch will form the progress value. Usually 0.
35f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
36f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    float mTouchProgressOffset;
37f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
38f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
39f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * Whether this is user seekable.
40f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
41f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    boolean mIsUserSeekable = true;
42f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
432deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen    boolean mIsVertical = false;
44f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
45f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * On key presses (right or left), the amount to increment/decrement the
46f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * progress.
47f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
48f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    private int mKeyProgressIncrement = 1;
49f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
50f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    private static final int NO_ALPHA = 0xFF;
51f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    private float mDisabledAlpha;
52f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
53f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public AbsSeekBar(Context context) {
54f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        super(context);
55f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
56f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
57f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public AbsSeekBar(Context context, AttributeSet attrs) {
58f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        super(context, attrs);
59f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
60f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
61f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public AbsSeekBar(Context context, AttributeSet attrs, int defStyle) {
62f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        super(context, attrs, defStyle);
63f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
64f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        TypedArray a = context.obtainStyledAttributes(attrs,
65f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                com.android.internal.R.styleable.SeekBar, defStyle, 0);
66f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
67f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        setThumb(thumb); // will guess mThumbOffset if thumb != null...
68f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        // ...but allow layout to override this
69f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        int thumbOffset = a.getDimensionPixelOffset(
70f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
71f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        setThumbOffset(thumbOffset);
72f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        a.recycle();
73f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
74f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        a = context.obtainStyledAttributes(attrs,
75f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                com.android.internal.R.styleable.Theme, 0, 0);
76f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.Theme_disabledAlpha, 0.5f);
77f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        a.recycle();
78f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
79f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
80f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
81f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * Sets the thumb that will be drawn at the end of the progress meter within the SeekBar.
82f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * <p>
83f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * If the thumb is a valid drawable (i.e. not null), half its width will be
84f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * used as the new thumb offset (@see #setThumbOffset(int)).
85f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     *
86f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * @param thumb Drawable representing the thumb
87f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
88f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public void setThumb(Drawable thumb) {
89f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        boolean needUpdate;
90f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        // This way, calling setThumb again with the same bitmap will result in
91f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        // it recalcuating mThumbOffset (if for example it the bounds of the
92f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        // drawable changed)
93f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (mThumb != null && thumb != mThumb) {
94f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            mThumb.setCallback(null);
95f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            needUpdate = true;
96f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        } else {
97f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            needUpdate = false;
98f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
99f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (thumb != null) {
100f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            thumb.setCallback(this);
101f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
102f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            // Assuming the thumb drawable is symmetric, set the thumb offset
103f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            // such that the thumb will hang halfway off either edge of the
104f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            // progress bar.
1052deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            if (mIsVertical) {
1062deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                mThumbOffset = thumb.getIntrinsicHeight() / 2;
1072deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else {
1082deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                mThumbOffset = thumb.getIntrinsicWidth() / 2;
1092deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            }
110f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
111f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            // If we're updating get the new states
112f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            if (needUpdate &&
113f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                    (thumb.getIntrinsicWidth() != mThumb.getIntrinsicWidth()
114f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                        || thumb.getIntrinsicHeight() != mThumb.getIntrinsicHeight())) {
115f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                requestLayout();
116f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            }
117f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
118f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        mThumb = thumb;
119f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        invalidate();
120f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (needUpdate) {
121f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            updateThumbPos(getWidth(), getHeight());
122f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            if (thumb.isStateful()) {
123f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                // Note that if the states are different this won't work.
124f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                // For now, let's consider that an app bug.
125f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                int[] state = getDrawableState();
126f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                thumb.setState(state);
127f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            }
128f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
129f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
130f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
131f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
132f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * @see #setThumbOffset(int)
133f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
134f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public int getThumbOffset() {
135f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        return mThumbOffset;
136f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
137f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
138f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
139f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * Sets the thumb offset that allows the thumb to extend out of the range of
140f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * the track.
141f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     *
142f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * @param thumbOffset The offset amount in pixels.
143f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
144f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public void setThumbOffset(int thumbOffset) {
145f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        mThumbOffset = thumbOffset;
146f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        invalidate();
147f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
148f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
149f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
150f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * Sets the amount of progress changed via the arrow keys.
151f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     *
152f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * @param increment The amount to increment or decrement when the user
153f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     *            presses the arrow keys.
154f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
155f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public void setKeyProgressIncrement(int increment) {
156f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        mKeyProgressIncrement = increment < 0 ? -increment : increment;
157f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
158f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
159f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
160f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * Returns the amount of progress changed via the arrow keys.
161f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * <p>
162f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * By default, this will be a value that is derived from the max progress.
163f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     *
164f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * @return The amount to increment or decrement when the user presses the
165f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     *         arrow keys. This will be positive.
166f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
167f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public int getKeyProgressIncrement() {
168f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        return mKeyProgressIncrement;
169f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
170f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
171f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
172f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public synchronized void setMax(int max) {
173f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        super.setMax(max);
174f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
175f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
176f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            // It will take the user too long to change this via keys, change it
177f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            // to something more reasonable
178f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
179f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
180f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
181f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
182f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
183f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    protected boolean verifyDrawable(Drawable who) {
184f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        return who == mThumb || super.verifyDrawable(who);
185f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
186f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
187f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
188f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public void jumpDrawablesToCurrentState() {
189f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        super.jumpDrawablesToCurrentState();
190f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (mThumb != null) mThumb.jumpToCurrentState();
191f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
192f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
193f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
194f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    protected void drawableStateChanged() {
195f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        super.drawableStateChanged();
196f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
197f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        Drawable progressDrawable = getProgressDrawable();
198f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (progressDrawable != null) {
199f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
200f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
201f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
202f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (mThumb != null && mThumb.isStateful()) {
203f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            int[] state = getDrawableState();
204f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            mThumb.setState(state);
205f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
206f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
207f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
208f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
209f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    void onProgressRefresh(float scale, boolean fromUser) {
210f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        super.onProgressRefresh(scale, fromUser);
211f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        Drawable thumb = mThumb;
212f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (thumb != null) {
2132deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            setThumbPos(getWidth(), getHeight(), thumb, scale, Integer.MIN_VALUE);
214f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            /*
215f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen             * Since we draw translated, the drawable's bounds that it signals
216f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen             * for invalidation won't be the actual bounds we want invalidated,
217f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen             * so just invalidate this whole view.
218f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen             */
219f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            invalidate();
220f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
221f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
222f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
223f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
224f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
225f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
226f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        updateThumbPos(w, h);
227f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
228f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
229f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    private void updateThumbPos(int w, int h) {
230f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        Drawable d = getCurrentDrawable();
231f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        Drawable thumb = mThumb;
2322deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        if (mIsVertical) {
2332deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int thumbWidth = thumb == null ? 0 : thumb.getIntrinsicWidth();
2342deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            // The max width does not incorporate padding, whereas the width
2352deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            // parameter does
2362deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int trackWidth = Math.min(mMaxWidth, w - mPaddingLeft - mPaddingRight);
2372deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen
2382deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int max = getMax();
2392deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            float scale = max > 0 ? (float) getProgress() / (float) max : 0;
2402deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen
2412deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            if (thumbWidth > trackWidth) {
2422deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (thumb != null) {
2432deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    setThumbPos(w, h, thumb, scale, 0);
2442deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
2452deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                int gapForCenteringTrack = (thumbWidth - trackWidth) / 2;
2462deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (d != null) {
2472deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    // Canvas will be translated by the padding, so 0,0 is where we start drawing
2482deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    d.setBounds(gapForCenteringTrack, 0,
2492deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                            w - mPaddingRight - gapForCenteringTrack - mPaddingLeft,
2502deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                            h - mPaddingBottom - mPaddingTop);
2512deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
2522deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else {
2532deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (d != null) {
2542deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    // Canvas will be translated by the padding, so 0,0 is where we start drawing
2552deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    d.setBounds(0, 0, w - mPaddingRight - mPaddingLeft, h - mPaddingBottom
2562deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                            - mPaddingTop);
2572deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
2582deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                int gap = (trackWidth - thumbWidth) / 2;
2592deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (thumb != null) {
2602deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    setThumbPos(w, h, thumb, scale, gap);
2612deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
262f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            }
263f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        } else {
2642deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
2652deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            // The max height does not incorporate padding, whereas the height
2662deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            // parameter does
2672deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
2682deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen
2692deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int max = getMax();
2702deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            float scale = max > 0 ? (float) getProgress() / (float) max : 0;
2712deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen
2722deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            if (thumbHeight > trackHeight) {
2732deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (thumb != null) {
2742deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    setThumbPos(w, h, thumb, scale, 0);
2752deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
2762deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                int gapForCenteringTrack = (thumbHeight - trackHeight) / 2;
2772deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (d != null) {
2782deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    // Canvas will be translated by the padding, so 0,0 is where we start drawing
2792deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    d.setBounds(0, gapForCenteringTrack,
2802deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                            w - mPaddingRight - mPaddingLeft, h - mPaddingBottom - gapForCenteringTrack
2812deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                            - mPaddingTop);
2822deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
2832deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else {
2842deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (d != null) {
2852deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    // Canvas will be translated by the padding, so 0,0 is where we start drawing
2862deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    d.setBounds(0, 0, w - mPaddingRight - mPaddingLeft, h - mPaddingBottom
2872deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                            - mPaddingTop);
2882deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
2892deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                int gap = (trackHeight - thumbHeight) / 2;
2902deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (thumb != null) {
2912deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    setThumbPos(w, h, thumb, scale, gap);
2922deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
293f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            }
294f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
295f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
296f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
297f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
298f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * @param gap If set to {@link Integer#MIN_VALUE}, this will be ignored and
299f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
3002deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen    private void setThumbPos(int w, int h, Drawable thumb, float scale, int gap) {
3012deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        int available;
302f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        int thumbWidth = thumb.getIntrinsicWidth();
303f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        int thumbHeight = thumb.getIntrinsicHeight();
3042deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        if (mIsVertical) {
3052deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            available = h - mPaddingTop - mPaddingBottom - thumbHeight;
3062deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        } else {
3072deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            available = w - mPaddingLeft - mPaddingRight - thumbWidth;
3082deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        }
309f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
310f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        // The extra space for the thumb to move on the track
311f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        available += mThumbOffset * 2;
312f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
313f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
3142deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        if (mIsVertical) {
3152deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int thumbPos = (int) ((1.0f - scale) * available);
3162deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int leftBound, rightBound;
3172deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            if (gap == Integer.MIN_VALUE) {
3182deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                Rect oldBounds = thumb.getBounds();
3192deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                leftBound = oldBounds.left;
3202deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                rightBound = oldBounds.right;
3212deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else {
3222deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                leftBound = gap;
3232deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                rightBound = gap + thumbWidth;
3242deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            }
3252deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen
3262deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            // Canvas will be translated, so 0,0 is where we start drawing
3272deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            thumb.setBounds(leftBound, thumbPos, rightBound, thumbPos + thumbHeight);
328f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        } else {
3292deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int thumbPos = (int) (scale * available);
3302deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int topBound, bottomBound;
3312deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            if (gap == Integer.MIN_VALUE) {
3322deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                Rect oldBounds = thumb.getBounds();
3332deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                topBound = oldBounds.top;
3342deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                bottomBound = oldBounds.bottom;
3352deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else {
3362deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                topBound = gap;
3372deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                bottomBound = gap + thumbHeight;
3382deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            }
3392deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen
3402deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            // Canvas will be translated, so 0,0 is where we start drawing
3412deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            thumb.setBounds(thumbPos, topBound, thumbPos + thumbWidth, bottomBound);
342f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
343f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
344f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
345f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
346f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    protected synchronized void onDraw(Canvas canvas) {
347f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        super.onDraw(canvas);
348f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (mThumb != null) {
349f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            canvas.save();
3502deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            // Translate the padding. For the x/y, we need to allow the thumb to
351f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            // draw in its extra space
3522deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            if (mIsVertical) {
3532deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                canvas.translate(mPaddingLeft, mPaddingTop - mThumbOffset);
3542deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                mThumb.draw(canvas);
3552deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                canvas.restore();
3562deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else {
3572deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
3582deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                mThumb.draw(canvas);
3592deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                canvas.restore();
3602deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            }
361f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
362f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
363f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
364f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
365f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
366f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        Drawable d = getCurrentDrawable();
367f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
368f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        int thumbHeight = mThumb == null ? 0 : mThumb.getIntrinsicHeight();
369f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        int dw = 0;
370f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        int dh = 0;
371f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (d != null) {
372f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
373f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
374f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            dh = Math.max(thumbHeight, dh);
375f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
376f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        dw += mPaddingLeft + mPaddingRight;
377f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        dh += mPaddingTop + mPaddingBottom;
378f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
379f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
380f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                resolveSizeAndState(dh, heightMeasureSpec, 0));
3812deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen
3822deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        // TODO should probably make this an explicit attribute instead of implicitly
3832deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        // setting it based on the size
3842deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        if (getMeasuredHeight() > getMeasuredWidth()) {
3852deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            mIsVertical = true;
3862deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        }
387f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
388f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
389f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
390f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public boolean onTouchEvent(MotionEvent event) {
391f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (!mIsUserSeekable || !isEnabled()) {
392f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            return false;
393f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
394f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
395f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        switch (event.getAction()) {
396f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            case MotionEvent.ACTION_DOWN:
397f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                setPressed(true);
398f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                onStartTrackingTouch();
399f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                trackTouchEvent(event);
400f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                break;
401f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
402f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            case MotionEvent.ACTION_MOVE:
403f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                trackTouchEvent(event);
404f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                attemptClaimDrag();
405f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                break;
406f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
407f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            case MotionEvent.ACTION_UP:
408f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                trackTouchEvent(event);
409f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                onStopTrackingTouch();
410f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                setPressed(false);
411f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                // ProgressBar doesn't know to repaint the thumb drawable
412f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                // in its inactive state when the touch stops (because the
413f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                // value has not apparently changed)
414f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                invalidate();
415f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                break;
416f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
417f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            case MotionEvent.ACTION_CANCEL:
418f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                onStopTrackingTouch();
419f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                setPressed(false);
420f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                invalidate(); // see above explanation
421f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                break;
422f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
423f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        return true;
424f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
425f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
426f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    private void trackTouchEvent(MotionEvent event) {
427f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        float progress = 0;
4282deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen        if (mIsVertical) {
4292deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            final int height = getHeight();
4302deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            final int available = height - mPaddingTop - mPaddingBottom;
4312deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int y = (int)event.getY();
4322deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            float scale;
4332deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            if (y < mPaddingTop) {
4342deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                scale = 1.0f;
4352deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else if (y > height - mPaddingBottom) {
4362deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                scale = 0.0f;
4372deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else {
4382deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                scale = 1.0f - (float)(y - mPaddingTop) / (float)available;
4392deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                progress = mTouchProgressOffset;
4402deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            }
4412deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen
4422deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            final int max = getMax();
4432deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            progress += scale * max;
444f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        } else {
4452deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            final int width = getWidth();
4462deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            final int available = width - mPaddingLeft - mPaddingRight;
4472deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            int x = (int)event.getX();
4482deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            float scale;
4492deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            if (x < mPaddingLeft) {
4502deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                scale = 0.0f;
4512deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else if (x > width - mPaddingRight) {
4522deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                scale = 1.0f;
4532deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else {
4542deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                scale = (float)(x - mPaddingLeft) / (float)available;
4552deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                progress = mTouchProgressOffset;
4562deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            }
4572deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen
4582deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            final int max = getMax();
4592deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            progress += scale * max;
460f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
461f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
462f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        setProgress((int) progress, true);
463f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
464f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
465f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
466f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * Tries to claim the user's drag motion, and requests disallowing any
467f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * ancestors from stealing events in the drag.
468f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
469f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    private void attemptClaimDrag() {
470f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (mParent != null) {
471f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            mParent.requestDisallowInterceptTouchEvent(true);
472f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
473f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
474f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
475f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
476f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * This is called when the user has started touching this widget.
477f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
478f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    void onStartTrackingTouch() {
479f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
480f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
481f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
482f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * This is called when the user either releases his touch or the touch is
483f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * canceled.
484f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
485f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    void onStopTrackingTouch() {
486f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
487f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
488f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    /**
489f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     * Called when the user changes the seekbar's progress by using a key event.
490f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen     */
491f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    void onKeyChange() {
492f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
493f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
494f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    @Override
495f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    public boolean onKeyDown(int keyCode, KeyEvent event) {
496f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        if (isEnabled()) {
497f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            int progress = getProgress();
4982deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            if ((keyCode == KeyEvent.KEYCODE_DPAD_LEFT && !mIsVertical)
4992deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    || (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && mIsVertical)) {
5002deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (progress > 0) {
501f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                    setProgress(progress - mKeyProgressIncrement, true);
502f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                    onKeyChange();
503f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                    return true;
5042deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
5052deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen            } else if ((keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && !mIsVertical)
5062deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                    || (keyCode == KeyEvent.KEYCODE_DPAD_UP && mIsVertical)) {
5072deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                if (progress < getMax()) {
508f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                    setProgress(progress + mKeyProgressIncrement, true);
509f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                    onKeyChange();
510f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen                    return true;
5112deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen                }
512f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen            }
513f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        }
514f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
515f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen        return super.onKeyDown(keyCode, event);
516f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen    }
517f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen
518f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen}
519