diff options
Diffstat (limited to 'src/com/android/gallery3d/app/TimeBar.java')
-rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/app/TimeBar.java | 373 |
1 files changed, 346 insertions, 27 deletions
diff --git a/src/com/android/gallery3d/app/TimeBar.java b/src/com/android/gallery3d/app/TimeBar.java index 246346a56..2870c489c 100644..100755 --- a/src/com/android/gallery3d/app/TimeBar.java +++ b/src/com/android/gallery3d/app/TimeBar.java @@ -22,13 +22,17 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; +import android.text.TextUtils; import android.util.DisplayMetrics; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import com.android.gallery3d.R; import com.android.gallery3d.common.Utils; +import java.util.Locale; + /** * The time bar view, which includes the current and total time, the progress * bar, and the scrubber. @@ -51,6 +55,10 @@ public class TimeBar extends View { private static final int TEXT_SIZE_IN_DP = 14; + private static final String TAG = "Gallery3D/TimeBar"; + private static final boolean LOG = false; + public static final int UNKNOWN = -1; + protected final Listener mListener; // the bars we use for displaying the progress @@ -71,6 +79,7 @@ public class TimeBar extends View { protected boolean mScrubbing; protected boolean mShowTimes; protected boolean mShowScrubber; + private boolean mEnableScrubbing; protected int mTotalTime; protected int mCurrentTime; @@ -78,6 +87,11 @@ public class TimeBar extends View { protected final Rect mTimeBounds; protected int mVPaddingInPx; + private int mLastShowTime = UNKNOWN; + + private ITimeBarSecondaryProgressExt mSecondaryProgressExt = new TimeBarSecondaryProgressExtImpl(); + private ITimeBarInfoExt mInfoExt = new TimeBarInfoExtImpl(); + private ITimeBarLayoutExt mLayoutExt = new TimeBarLayoutExtImpl(); public TimeBar(Context context, Listener listener) { super(context); @@ -108,21 +122,53 @@ public class TimeBar extends View { mScrubberPadding = (int) (metrics.density * SCRUBBER_PADDING_IN_DP); mVPaddingInPx = (int) (metrics.density * V_PADDING_IN_DP); + mLayoutExt.init(mScrubberPadding, mVPaddingInPx); + mInfoExt.init(textSizeInPx); + mSecondaryProgressExt.init(); } private void update() { mPlayedBar.set(mProgressBar); if (mTotalTime > 0) { - mPlayedBar.right = - mPlayedBar.left + (int) ((mProgressBar.width() * (long) mCurrentTime) / mTotalTime); + if (View.LAYOUT_DIRECTION_RTL == TextUtils + .getLayoutDirectionFromLocale(Locale.getDefault())) { + // The progress bar should be reversed in RTL. + mPlayedBar.left = mPlayedBar.right + - (int) ((mProgressBar.width() * (long) mCurrentTime) / mTotalTime); + } else { + mPlayedBar.right = mPlayedBar.left + + (int) ((mProgressBar.width() * (long) mCurrentTime) / mTotalTime); + } + /* + * M: if duration is not accurate, here just adjust playedBar we + * also show the accurate position text to final user. + */ + if (mPlayedBar.right > mProgressBar.right) { + mPlayedBar.right = mProgressBar.right; + } } else { - mPlayedBar.right = mProgressBar.left; + if (View.LAYOUT_DIRECTION_RTL == TextUtils + .getLayoutDirectionFromLocale(Locale.getDefault())) { + // The progress bar should be reversed in RTL. + mPlayedBar.left = mProgressBar.right; + } else { + mPlayedBar.right = mProgressBar.left; + } } if (!mScrubbing) { - mScrubberLeft = mPlayedBar.right - mScrubber.getWidth() / 2; + if (View.LAYOUT_DIRECTION_RTL == TextUtils.getLayoutDirectionFromLocale( + Locale.getDefault())) { + // The progress bar should be reversed in RTL. + mScrubberLeft = mPlayedBar.left - mScrubber.getWidth() / 2; + } else { + mScrubberLeft = mPlayedBar.right - mScrubber.getWidth() / 2; + } } + // update text bounds when layout changed or time changed + updateBounds(); + mInfoExt.updateVisibleText(this, mProgressBar, mTimeBounds); invalidate(); } @@ -130,14 +176,16 @@ public class TimeBar extends View { * @return the preferred height of this view, including invisible padding */ public int getPreferredHeight() { - return mTimeBounds.height() + mVPaddingInPx + mScrubberPadding; + int preferredHeight = mTimeBounds.height() + mVPaddingInPx + mScrubberPadding; + return mLayoutExt.getPreferredHeight(preferredHeight, mTimeBounds); } /** * @return the height of the time bar, excluding invisible padding */ public int getBarHeight() { - return mTimeBounds.height() + mVPaddingInPx; + int barHeight = mTimeBounds.height() + mVPaddingInPx; + return mLayoutExt.getBarHeight(barHeight, mTimeBounds); } public void setTime(int currentTime, int totalTime, @@ -146,7 +194,10 @@ public class TimeBar extends View { return; } mCurrentTime = currentTime; - mTotalTime = totalTime; + mTotalTime = Math.abs(totalTime); + if (totalTime <= 0) { /// M: disable scrubbing before mediaplayer ready. + setScrubbing(false); + } update(); } @@ -165,9 +216,17 @@ public class TimeBar extends View { } private int getScrubberTime() { - return (int) ((long) (mScrubberLeft + mScrubber.getWidth() / 2 - mProgressBar.left) - * mTotalTime / mProgressBar.width()); - } + if (View.LAYOUT_DIRECTION_RTL == TextUtils + .getLayoutDirectionFromLocale(Locale.getDefault())) { + // The progress bar's scrubber time should be reversed in RTL. + return (int) ((long) (mProgressBar.width() - (mScrubberLeft + + mScrubber.getWidth() / 2 - mProgressBar.left)) + * mTotalTime / mProgressBar.width()); + } else { + return (int) ((long) (mScrubberLeft + mScrubber.getWidth() / 2 - mProgressBar.left) + * mTotalTime / mProgressBar.width()); + } + } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { @@ -180,7 +239,8 @@ public class TimeBar extends View { if (mShowTimes) { margin += mTimeBounds.width(); } - int progressY = (h + mScrubberPadding) / 2; + margin = mLayoutExt.getProgressMargin(margin); + int progressY = (h + mScrubberPadding) / 2 + mLayoutExt.getProgressOffset(mTimeBounds); mScrubberTop = progressY - mScrubber.getHeight() / 2 + 1; mProgressBar.set( getPaddingLeft() + margin, progressY, @@ -191,8 +251,10 @@ public class TimeBar extends View { @Override protected void onDraw(Canvas canvas) { + super.onDraw(canvas); // draw progress bars canvas.drawRect(mProgressBar, mProgressPaint); + mSecondaryProgressExt.draw(canvas, mProgressBar); canvas.drawRect(mPlayedBar, mPlayedPaint); // draw scrubber and timers @@ -200,22 +262,44 @@ public class TimeBar extends View { canvas.drawBitmap(mScrubber, mScrubberLeft, mScrubberTop, null); } if (mShowTimes) { - canvas.drawText( - stringForTime(mCurrentTime), - mTimeBounds.width() / 2 + getPaddingLeft(), - mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, - mTimeTextPaint); - canvas.drawText( - stringForTime(mTotalTime), - getWidth() - getPaddingRight() - mTimeBounds.width() / 2, - mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, - mTimeTextPaint); + if (View.LAYOUT_DIRECTION_RTL == TextUtils + .getLayoutDirectionFromLocale(Locale.getDefault())) { + // The progress bar's time should be reversed in RTL. + canvas.drawText( + stringForTime(mCurrentTime), + getWidth() - getPaddingRight() - mTimeBounds.width() / 2, + mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, + mTimeTextPaint); + canvas.drawText( + stringForTime(mTotalTime), + mTimeBounds.width() / 2 + getPaddingLeft(), + mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, + mTimeTextPaint); + } else { + canvas.drawText( + stringForTime(mCurrentTime), + mTimeBounds.width() / 2 + getPaddingLeft(), + mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, + mTimeTextPaint); + canvas.drawText( + stringForTime(mTotalTime), + getWidth() - getPaddingRight() - mTimeBounds.width() / 2, + mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, + mTimeTextPaint); + } } + mInfoExt.draw(canvas, mLayoutExt.getInfoBounds(this, mTimeBounds)); } @Override public boolean onTouchEvent(MotionEvent event) { - if (mShowScrubber) { + if (LOG) { + Log.v(TAG, "onTouchEvent() showScrubber=" + mShowScrubber + + ", enableScrubbing=" + mEnableScrubbing + ", totalTime=" + + mTotalTime + ", scrubbing=" + mScrubbing + ", event=" + + event); + } + if (mShowScrubber && mEnableScrubbing) { int x = (int) event.getX(); int y = (int) event.getY(); @@ -233,15 +317,19 @@ public class TimeBar extends View { clampScrubber(); mCurrentTime = getScrubberTime(); mListener.onScrubbingMove(mCurrentTime); + update(); invalidate(); return true; } case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - mListener.onScrubbingEnd(getScrubberTime(), 0, 0); - mScrubbing = false; - return true; - } + case MotionEvent.ACTION_UP: + if (mScrubbing) { + mListener.onScrubbingEnd(getScrubberTime(), 0, 0); + mScrubbing = false; + update(); + return true; + } + break; } } return false; @@ -263,4 +351,235 @@ public class TimeBar extends View { mShowScrubber = canSeek; } + private void updateBounds() { + int showTime = mTotalTime > mCurrentTime ? mTotalTime : mCurrentTime; + if (mLastShowTime == showTime) { + // do not need to recompute the bounds. + return; + } + String durationText = stringForTime(showTime); + int length = durationText.length(); + mTimeTextPaint.getTextBounds(durationText, 0, length, mTimeBounds); + mLastShowTime = showTime; + if (LOG) { + Log.v(TAG, "updateBounds() durationText=" + durationText + ", timeBounds=" + + mTimeBounds); + } + } + + public void setScrubbing(boolean enable) { + if (LOG) { + Log.v(TAG, "setScrubbing(" + enable + ") scrubbing=" + mScrubbing); + } + mEnableScrubbing = enable; + if (mScrubbing) { // if it is scrubbing, change it to false + mListener.onScrubbingEnd(getScrubberTime(), 0, 0); + mScrubbing = false; + } + } + + public boolean getScrubbing() { + if (LOG) { + Log.v(TAG, "mEnableScrubbing=" + mEnableScrubbing); + } + return mEnableScrubbing; + } + + public void setInfo(String info) { + if (LOG) { + Log.v(TAG, "setInfo(" + info + ")"); + } + mInfoExt.setInfo(info); + mInfoExt.updateVisibleText(this, mProgressBar, mTimeBounds); + invalidate(); + } + + public void setSecondaryProgress(int percent) { + if (LOG) { + Log.v(TAG, "setSecondaryProgress(" + percent + ")"); + } + mSecondaryProgressExt.setSecondaryProgress(mProgressBar, percent); + invalidate(); + } +} + +interface ITimeBarInfoExt { + void init(float textSizeInPx); + + void setInfo(String info); + + void draw(Canvas canvas, Rect infoBounds); + + void updateVisibleText(View parent, Rect progressBar, Rect timeBounds); +} + +interface ITimeBarSecondaryProgressExt { + void init(); + + void setSecondaryProgress(Rect progressBar, int percent); + + void draw(Canvas canvas, Rect progressBounds); +} + +interface ITimeBarLayoutExt { + void init(int scrubberPadding, int vPaddingInPx); + + int getPreferredHeight(int originalPreferredHeight, Rect timeBounds); + + int getBarHeight(int originalBarHeight, Rect timeBounds); + + int getProgressMargin(int originalMargin); + + int getProgressOffset(Rect timeBounds); + + int getTimeOffset(); + + Rect getInfoBounds(View parent, Rect timeBounds); +} + +class TimeBarInfoExtImpl implements ITimeBarInfoExt { + private static final String TAG = "TimeBarInfoExtensionImpl"; + private static final boolean LOG = false; + private static final String ELLIPSE = "..."; + + private Paint mInfoPaint; + private Rect mInfoBounds; + private String mInfoText; + private String mVisibleText; + private int mEllipseLength; + + @Override + public void init(float textSizeInPx) { + mInfoPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mInfoPaint.setColor(0xFFCECECE); + mInfoPaint.setTextSize(textSizeInPx); + mInfoPaint.setTextAlign(Paint.Align.CENTER); + + mEllipseLength = (int) Math.ceil(mInfoPaint.measureText(ELLIPSE)); + } + + @Override + public void draw(Canvas canvas, Rect infoBounds) { + if (mInfoText != null && mVisibleText != null) { + canvas.drawText(mVisibleText, infoBounds.centerX(), infoBounds.centerY(), mInfoPaint); + } + } + + @Override + public void setInfo(String info) { + mInfoText = info; + } + + public void updateVisibleText(View parent, Rect progressBar, Rect timeBounds) { + if (mInfoText == null) { + mVisibleText = null; + return; + } + float tw = mInfoPaint.measureText(mInfoText); + float space = progressBar.width() - timeBounds.width() * 2 - parent.getPaddingLeft() + - parent.getPaddingRight(); + if (tw > 0 && space > 0 && tw > space) { + // we need to cut the info text for visible + float originalNum = mInfoText.length(); + int realNum = (int) ((space - mEllipseLength) * originalNum / tw); + if (LOG) { + Log.v(TAG, "updateVisibleText() infoText=" + mInfoText + " text width=" + tw + + ", space=" + space + ", originalNum=" + originalNum + ", realNum=" + + realNum + + ", getPaddingLeft()=" + parent.getPaddingLeft() + ", getPaddingRight()=" + + parent.getPaddingRight() + + ", progressBar=" + progressBar + ", timeBounds=" + timeBounds); + } + mVisibleText = mInfoText.substring(0, realNum) + ELLIPSE; + } else { + mVisibleText = mInfoText; + } + if (LOG) { + Log.v(TAG, "updateVisibleText() infoText=" + mInfoText + ", visibleText=" + + mVisibleText + + ", text width=" + tw + ", space=" + space); + } + } +} + +class TimeBarSecondaryProgressExtImpl implements ITimeBarSecondaryProgressExt { + private static final String TAG = "TimeBarSecondaryProgressExtensionImpl"; + private static final boolean LOG = false; + + private int mBufferPercent; + private Rect mSecondaryBar; + private Paint mSecondaryPaint; + + @Override + public void init() { + mSecondaryBar = new Rect(); + mSecondaryPaint = new Paint(); + mSecondaryPaint.setColor(0xFF5CA0C5); + } + + @Override + public void draw(Canvas canvas, Rect progressBounds) { + if (mBufferPercent >= 0) { + mSecondaryBar.set(progressBounds); + mSecondaryBar.right = mSecondaryBar.left + + (int) (mBufferPercent * progressBounds.width() / 100); + canvas.drawRect(mSecondaryBar, mSecondaryPaint); + } + if (LOG) { + Log.v(TAG, "draw() bufferPercent=" + mBufferPercent + ", secondaryBar=" + + mSecondaryBar); + } + } + + @Override + public void setSecondaryProgress(Rect progressBar, int percent) { + mBufferPercent = percent; + } +} + +class TimeBarLayoutExtImpl implements ITimeBarLayoutExt { + private static final String TAG = "TimeBarLayoutExtensionImpl"; + private static final boolean LOG = false; + + private int mTextPadding; + private int mVPaddingInPx; + + @Override + public void init(int scrubberPadding, int vPaddingInPx) { + mTextPadding = scrubberPadding / 2; + mVPaddingInPx = vPaddingInPx; + } + + @Override + public int getPreferredHeight(int originalPreferredHeight, Rect timeBounds) { + return originalPreferredHeight + timeBounds.height() + mTextPadding; + } + + @Override + public int getBarHeight(int originalBarHeight, Rect timeBounds) { + return originalBarHeight + timeBounds.height() + mTextPadding; + } + + @Override + public int getProgressMargin(int originalMargin) { + return 0; + } + + @Override + public int getProgressOffset(Rect timeBounds) { + return (timeBounds.height() + mTextPadding) / 2; + } + + @Override + public int getTimeOffset() { + return mTextPadding - mVPaddingInPx / 2; + } + + @Override + public Rect getInfoBounds(View parent, Rect timeBounds) { + Rect bounds = new Rect(parent.getPaddingLeft(), 0, + parent.getWidth() - parent.getPaddingRight(), + (timeBounds.height() + mTextPadding * 3 + 1) * 2); + return bounds; + } } |