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; 270962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissenimport android.view.ViewConfiguration; 28f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 29f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissenpublic abstract class AbsSeekBar extends ProgressBar { 30f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen private Drawable mThumb; 31f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen private int mThumbOffset; 32f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 33f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 34f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * On touch, this offset plus the scaled value from the position of the 35f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * touch will form the progress value. Usually 0. 36f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 37f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen float mTouchProgressOffset; 38f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 39f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 40f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Whether this is user seekable. 41f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 42f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen boolean mIsUserSeekable = true; 43f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 442deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen boolean mIsVertical = false; 45f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 46f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * On key presses (right or left), the amount to increment/decrement the 47f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * progress. 48f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 49f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen private int mKeyProgressIncrement = 1; 50f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 51f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen private static final int NO_ALPHA = 0xFF; 52f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen private float mDisabledAlpha; 53f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 540962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen private int mScaledTouchSlop; 550962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen private float mTouchDownX; 56d9fc04055aed9130f02627a73414ee12865a473dMarco Nelissen private float mTouchDownY; 570962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen private boolean mIsDragging; 580962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen 59f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public AbsSeekBar(Context context) { 60f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen super(context); 61f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 62f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 63f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public AbsSeekBar(Context context, AttributeSet attrs) { 64f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen super(context, attrs); 65f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 66f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 67f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public AbsSeekBar(Context context, AttributeSet attrs, int defStyle) { 68f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen super(context, attrs, defStyle); 69f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 70f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen TypedArray a = context.obtainStyledAttributes(attrs, 71f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen com.android.internal.R.styleable.SeekBar, defStyle, 0); 72f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb); 73f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen setThumb(thumb); // will guess mThumbOffset if thumb != null... 74f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // ...but allow layout to override this 75f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen int thumbOffset = a.getDimensionPixelOffset( 76f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset()); 77f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen setThumbOffset(thumbOffset); 78f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen a.recycle(); 79f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 80f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen a = context.obtainStyledAttributes(attrs, 81f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen com.android.internal.R.styleable.Theme, 0, 0); 82f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.Theme_disabledAlpha, 0.5f); 83f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen a.recycle(); 840962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen 850962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 86f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 87f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 88f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 89f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Sets the thumb that will be drawn at the end of the progress meter within the SeekBar. 90f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * <p> 91f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * If the thumb is a valid drawable (i.e. not null), half its width will be 92f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * used as the new thumb offset (@see #setThumbOffset(int)). 93f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * 94f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * @param thumb Drawable representing the thumb 95f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 96f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public void setThumb(Drawable thumb) { 97f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen boolean needUpdate; 98f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // This way, calling setThumb again with the same bitmap will result in 99f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // it recalcuating mThumbOffset (if for example it the bounds of the 100f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // drawable changed) 101f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (mThumb != null && thumb != mThumb) { 102f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen mThumb.setCallback(null); 103f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen needUpdate = true; 104f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } else { 105f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen needUpdate = false; 106f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 107f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (thumb != null) { 108f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen thumb.setCallback(this); 109f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 110f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // Assuming the thumb drawable is symmetric, set the thumb offset 111f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // such that the thumb will hang halfway off either edge of the 112f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // progress bar. 1132deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (mIsVertical) { 1142deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen mThumbOffset = thumb.getIntrinsicHeight() / 2; 1152deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else { 1162deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen mThumbOffset = thumb.getIntrinsicWidth() / 2; 1172deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 118f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 119f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // If we're updating get the new states 120f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (needUpdate && 121f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen (thumb.getIntrinsicWidth() != mThumb.getIntrinsicWidth() 122f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen || thumb.getIntrinsicHeight() != mThumb.getIntrinsicHeight())) { 123f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen requestLayout(); 124f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 125f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 126f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen mThumb = thumb; 127f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen invalidate(); 128f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (needUpdate) { 129f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen updateThumbPos(getWidth(), getHeight()); 130f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (thumb.isStateful()) { 131f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // Note that if the states are different this won't work. 132f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // For now, let's consider that an app bug. 133f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen int[] state = getDrawableState(); 134f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen thumb.setState(state); 135f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 136f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 137f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 138f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 139f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 140f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * @see #setThumbOffset(int) 141f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 142f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public int getThumbOffset() { 143f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen return mThumbOffset; 144f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 145f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 146f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 147f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Sets the thumb offset that allows the thumb to extend out of the range of 148f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * the track. 149f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * 150f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * @param thumbOffset The offset amount in pixels. 151f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 152f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public void setThumbOffset(int thumbOffset) { 153f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen mThumbOffset = thumbOffset; 154f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen invalidate(); 155f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 156f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 157f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 158f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Sets the amount of progress changed via the arrow keys. 159f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * 160f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * @param increment The amount to increment or decrement when the user 161f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * presses the arrow keys. 162f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 163f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public void setKeyProgressIncrement(int increment) { 164f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen mKeyProgressIncrement = increment < 0 ? -increment : increment; 165f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 166f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 167f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 168f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Returns the amount of progress changed via the arrow keys. 169f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * <p> 170f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * By default, this will be a value that is derived from the max progress. 171f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * 172f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * @return The amount to increment or decrement when the user presses the 173f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * arrow keys. This will be positive. 174f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 175f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public int getKeyProgressIncrement() { 176f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen return mKeyProgressIncrement; 177f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 178f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 179f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 180f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public synchronized void setMax(int max) { 181f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen super.setMax(max); 182f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 183f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) { 184f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // It will take the user too long to change this via keys, change it 185f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // to something more reasonable 186f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20))); 187f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 188f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 189f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 190f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 191f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen protected boolean verifyDrawable(Drawable who) { 192f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen return who == mThumb || super.verifyDrawable(who); 193f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 194f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 195f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 196f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public void jumpDrawablesToCurrentState() { 197f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen super.jumpDrawablesToCurrentState(); 198f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (mThumb != null) mThumb.jumpToCurrentState(); 199f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 200f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 201f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 202f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen protected void drawableStateChanged() { 203f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen super.drawableStateChanged(); 204f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 205f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen Drawable progressDrawable = getProgressDrawable(); 206f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (progressDrawable != null) { 207f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha)); 208f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 209f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 210f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (mThumb != null && mThumb.isStateful()) { 211f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen int[] state = getDrawableState(); 212f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen mThumb.setState(state); 213f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 214f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 215f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 216f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 217f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen void onProgressRefresh(float scale, boolean fromUser) { 218f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen super.onProgressRefresh(scale, fromUser); 219f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen Drawable thumb = mThumb; 220f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (thumb != null) { 2212deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen setThumbPos(getWidth(), getHeight(), thumb, scale, Integer.MIN_VALUE); 222f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /* 223f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Since we draw translated, the drawable's bounds that it signals 224f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * for invalidation won't be the actual bounds we want invalidated, 225f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * so just invalidate this whole view. 226f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 227f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen invalidate(); 228f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 229f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 230f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 231f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 232f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 233f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen protected void onSizeChanged(int w, int h, int oldw, int oldh) { 234f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen updateThumbPos(w, h); 235f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 236f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 237f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen private void updateThumbPos(int w, int h) { 238f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen Drawable d = getCurrentDrawable(); 239f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen Drawable thumb = mThumb; 2402deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (mIsVertical) { 2412deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int thumbWidth = thumb == null ? 0 : thumb.getIntrinsicWidth(); 2422deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // The max width does not incorporate padding, whereas the width 2432deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // parameter does 2442deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int trackWidth = Math.min(mMaxWidth, w - mPaddingLeft - mPaddingRight); 2452deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen 2462deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int max = getMax(); 2472deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen float scale = max > 0 ? (float) getProgress() / (float) max : 0; 2482deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen 2492deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (thumbWidth > trackWidth) { 2502deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (thumb != null) { 2512deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen setThumbPos(w, h, thumb, scale, 0); 2522deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 2532deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int gapForCenteringTrack = (thumbWidth - trackWidth) / 2; 2542deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (d != null) { 2552deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // Canvas will be translated by the padding, so 0,0 is where we start drawing 2562deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen d.setBounds(gapForCenteringTrack, 0, 2572deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen w - mPaddingRight - gapForCenteringTrack - mPaddingLeft, 2582deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen h - mPaddingBottom - mPaddingTop); 2592deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 2602deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else { 2612deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (d != null) { 2622deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // Canvas will be translated by the padding, so 0,0 is where we start drawing 2632deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen d.setBounds(0, 0, w - mPaddingRight - mPaddingLeft, h - mPaddingBottom 2642deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen - mPaddingTop); 2652deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 2662deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int gap = (trackWidth - thumbWidth) / 2; 2672deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (thumb != null) { 2682deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen setThumbPos(w, h, thumb, scale, gap); 2692deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 270f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 271f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } else { 2722deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight(); 2732deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // The max height does not incorporate padding, whereas the height 2742deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // parameter does 2752deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom); 2762deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen 2772deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int max = getMax(); 2782deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen float scale = max > 0 ? (float) getProgress() / (float) max : 0; 2792deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen 2802deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (thumbHeight > trackHeight) { 2812deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (thumb != null) { 2822deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen setThumbPos(w, h, thumb, scale, 0); 2832deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 2842deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int gapForCenteringTrack = (thumbHeight - trackHeight) / 2; 2852deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (d != null) { 2862deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // Canvas will be translated by the padding, so 0,0 is where we start drawing 2872deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen d.setBounds(0, gapForCenteringTrack, 2882deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen w - mPaddingRight - mPaddingLeft, h - mPaddingBottom - gapForCenteringTrack 2892deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen - mPaddingTop); 2902deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 2912deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else { 2922deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (d != null) { 2932deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // Canvas will be translated by the padding, so 0,0 is where we start drawing 2942deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen d.setBounds(0, 0, w - mPaddingRight - mPaddingLeft, h - mPaddingBottom 2952deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen - mPaddingTop); 2962deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 2972deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int gap = (trackHeight - thumbHeight) / 2; 2982deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (thumb != null) { 2992deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen setThumbPos(w, h, thumb, scale, gap); 3002deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 301f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 302f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 303f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 304f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 305f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 306f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * @param gap If set to {@link Integer#MIN_VALUE}, this will be ignored and 307f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 3082deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen private void setThumbPos(int w, int h, Drawable thumb, float scale, int gap) { 3092deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int available; 310f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen int thumbWidth = thumb.getIntrinsicWidth(); 311f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen int thumbHeight = thumb.getIntrinsicHeight(); 3122deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (mIsVertical) { 3132deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen available = h - mPaddingTop - mPaddingBottom - thumbHeight; 3142deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else { 3152deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen available = w - mPaddingLeft - mPaddingRight - thumbWidth; 3162deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 317f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 318f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // The extra space for the thumb to move on the track 319f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen available += mThumbOffset * 2; 320f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 321f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 3222deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (mIsVertical) { 3232deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int thumbPos = (int) ((1.0f - scale) * available); 3242deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int leftBound, rightBound; 3252deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (gap == Integer.MIN_VALUE) { 3262deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen Rect oldBounds = thumb.getBounds(); 3272deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen leftBound = oldBounds.left; 3282deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen rightBound = oldBounds.right; 3292deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else { 3302deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen leftBound = gap; 3312deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen rightBound = gap + thumbWidth; 3322deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 3332deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen 3342deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // Canvas will be translated, so 0,0 is where we start drawing 3352deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen thumb.setBounds(leftBound, thumbPos, rightBound, thumbPos + thumbHeight); 336f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } else { 3372deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int thumbPos = (int) (scale * available); 3382deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int topBound, bottomBound; 3392deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (gap == Integer.MIN_VALUE) { 3402deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen Rect oldBounds = thumb.getBounds(); 3412deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen topBound = oldBounds.top; 3422deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen bottomBound = oldBounds.bottom; 3432deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else { 3442deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen topBound = gap; 3452deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen bottomBound = gap + thumbHeight; 3462deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 3472deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen 3482deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // Canvas will be translated, so 0,0 is where we start drawing 3492deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen thumb.setBounds(thumbPos, topBound, thumbPos + thumbWidth, bottomBound); 350f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 351f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 352f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 353f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 354f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen protected synchronized void onDraw(Canvas canvas) { 355f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen super.onDraw(canvas); 356f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (mThumb != null) { 357f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen canvas.save(); 3582deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // Translate the padding. For the x/y, we need to allow the thumb to 359f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // draw in its extra space 3602deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (mIsVertical) { 3612deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen canvas.translate(mPaddingLeft, mPaddingTop - mThumbOffset); 3622deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen mThumb.draw(canvas); 3632deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen canvas.restore(); 3642deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else { 3652deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop); 3662deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen mThumb.draw(canvas); 3672deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen canvas.restore(); 3682deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 369f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 370f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 371f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 372f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 373f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 374f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen Drawable d = getCurrentDrawable(); 375f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 376f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen int thumbHeight = mThumb == null ? 0 : mThumb.getIntrinsicHeight(); 377f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen int dw = 0; 378f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen int dh = 0; 379f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (d != null) { 380f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth())); 381f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight())); 382f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen dh = Math.max(thumbHeight, dh); 383f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 384f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen dw += mPaddingLeft + mPaddingRight; 385f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen dh += mPaddingTop + mPaddingBottom; 386f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 387f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0), 388f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen resolveSizeAndState(dh, heightMeasureSpec, 0)); 3892deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen 3902deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // TODO should probably make this an explicit attribute instead of implicitly 3912deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen // setting it based on the size 3922deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (getMeasuredHeight() > getMeasuredWidth()) { 3932deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen mIsVertical = true; 3942deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 395f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 396f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 397f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 398f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public boolean onTouchEvent(MotionEvent event) { 399f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (!mIsUserSeekable || !isEnabled()) { 400f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen return false; 401f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 402f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 403f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen switch (event.getAction()) { 404f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen case MotionEvent.ACTION_DOWN: 4050962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen if (isInScrollingContainer()) { 4060962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen mTouchDownX = event.getX(); 407d9fc04055aed9130f02627a73414ee12865a473dMarco Nelissen mTouchDownY = event.getY(); 4080962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } else { 4090962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen setPressed(true); 4100962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen if (mThumb != null) { 4110962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen invalidate(mThumb.getBounds()); // This may be within the padding region 4120962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } 4130962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen onStartTrackingTouch(); 4140962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen trackTouchEvent(event); 4150962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen attemptClaimDrag(); 4160962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } 417f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen break; 418f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 419f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen case MotionEvent.ACTION_MOVE: 4200962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen if (mIsDragging) { 4210962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen trackTouchEvent(event); 4220962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } else { 4230962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen final float x = event.getX(); 424d9fc04055aed9130f02627a73414ee12865a473dMarco Nelissen final float y = event.getX(); 425d9fc04055aed9130f02627a73414ee12865a473dMarco Nelissen if (Math.abs(mIsVertical ? 426d9fc04055aed9130f02627a73414ee12865a473dMarco Nelissen (y - mTouchDownY) : (x - mTouchDownX)) > mScaledTouchSlop) { 4270962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen setPressed(true); 4280962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen if (mThumb != null) { 4290962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen invalidate(mThumb.getBounds()); // This may be within the padding region 4300962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } 4310962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen onStartTrackingTouch(); 4320962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen trackTouchEvent(event); 4330962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen attemptClaimDrag(); 4340962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } 4350962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } 436f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen break; 437f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 438f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen case MotionEvent.ACTION_UP: 4390962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen if (mIsDragging) { 4400962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen trackTouchEvent(event); 4410962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen onStopTrackingTouch(); 4420962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen setPressed(false); 4430962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } else { 4440962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen // Touch up when we never crossed the touch slop threshold should 4450962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen // be interpreted as a tap-seek to that location. 4460962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen onStartTrackingTouch(); 4470962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen trackTouchEvent(event); 4480962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen onStopTrackingTouch(); 4490962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } 450f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // ProgressBar doesn't know to repaint the thumb drawable 451f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // in its inactive state when the touch stops (because the 452f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen // value has not apparently changed) 453f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen invalidate(); 454f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen break; 455f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 456f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen case MotionEvent.ACTION_CANCEL: 4570962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen if (mIsDragging) { 4580962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen onStopTrackingTouch(); 4590962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen setPressed(false); 4600962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen } 461f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen invalidate(); // see above explanation 462f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen break; 463f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 464f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen return true; 465f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 466f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 467f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen private void trackTouchEvent(MotionEvent event) { 468f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen float progress = 0; 4692deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (mIsVertical) { 4702deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen final int height = getHeight(); 4712deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen final int available = height - mPaddingTop - mPaddingBottom; 4722deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int y = (int)event.getY(); 4732deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen float scale; 4742deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (y < mPaddingTop) { 4752deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen scale = 1.0f; 4762deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else if (y > height - mPaddingBottom) { 4772deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen scale = 0.0f; 4782deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else { 4792deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen scale = 1.0f - (float)(y - mPaddingTop) / (float)available; 4802deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen progress = mTouchProgressOffset; 4812deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 4822deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen 4832deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen final int max = getMax(); 4842deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen progress += scale * max; 485f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } else { 4862deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen final int width = getWidth(); 4872deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen final int available = width - mPaddingLeft - mPaddingRight; 4882deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen int x = (int)event.getX(); 4892deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen float scale; 4902deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (x < mPaddingLeft) { 4912deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen scale = 0.0f; 4922deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else if (x > width - mPaddingRight) { 4932deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen scale = 1.0f; 4942deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else { 4952deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen scale = (float)(x - mPaddingLeft) / (float)available; 4962deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen progress = mTouchProgressOffset; 4972deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 4982deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen 4992deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen final int max = getMax(); 5002deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen progress += scale * max; 501f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 502f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 503f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen setProgress((int) progress, true); 504f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 505f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 506f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 507f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Tries to claim the user's drag motion, and requests disallowing any 508f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * ancestors from stealing events in the drag. 509f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 510f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen private void attemptClaimDrag() { 511f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (mParent != null) { 512f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen mParent.requestDisallowInterceptTouchEvent(true); 513f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 514f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 515f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 516f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 517f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * This is called when the user has started touching this widget. 518f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 519f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen void onStartTrackingTouch() { 5200962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen mIsDragging = true; 521f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 522f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 523f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 524f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * This is called when the user either releases his touch or the touch is 525f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * canceled. 526f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 527f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen void onStopTrackingTouch() { 5280962a4b159ae5d4ea427c9e6fc32ff3722cbc16cMarco Nelissen mIsDragging = false; 529f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 530f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 531f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen /** 532f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen * Called when the user changes the seekbar's progress by using a key event. 533f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen */ 534f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen void onKeyChange() { 535f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 536f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 537f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen @Override 538f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen public boolean onKeyDown(int keyCode, KeyEvent event) { 539f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen if (isEnabled()) { 540f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen int progress = getProgress(); 5412deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if ((keyCode == KeyEvent.KEYCODE_DPAD_LEFT && !mIsVertical) 5422deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen || (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && mIsVertical)) { 5432deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (progress > 0) { 544f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen setProgress(progress - mKeyProgressIncrement, true); 545f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen onKeyChange(); 546f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen return true; 5472deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 5482deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } else if ((keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && !mIsVertical) 5492deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen || (keyCode == KeyEvent.KEYCODE_DPAD_UP && mIsVertical)) { 5502deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen if (progress < getMax()) { 551f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen setProgress(progress + mKeyProgressIncrement, true); 552f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen onKeyChange(); 553f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen return true; 5542deae778cee2b40946bfe08f8702761b77fc223fMarco Nelissen } 555f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 556f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 557f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 558f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen return super.onKeyDown(keyCode, event); 559f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen } 560f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen 561f568b605f08a5d8401e21387bf9c4a83167d1160Marco Nelissen} 562