blob: 402dfcfabeef16f86d1fb93e83ef80727cb8da49 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.gallery3d.app;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
/**
* The time bar view, which includes the current and total time, the progress
* bar, and the scrubber.
*/
public class TimeBar extends View {
public interface Listener {
void onScrubbingStart();
void onScrubbingMove(int time);
void onScrubbingEnd(int time, int start, int end);
}
// Padding around the scrubber to increase its touch target
private static final int SCRUBBER_PADDING_IN_DP = 10;
// The total padding, top plus bottom
private static final int V_PADDING_IN_DP = 30;
private static final int TEXT_SIZE_IN_DP = 14;
protected final Listener mListener;
// the bars we use for displaying the progress
protected final Rect mProgressBar;
protected final Rect mPlayedBar;
protected final Paint mProgressPaint;
protected final Paint mPlayedPaint;
protected final Paint mTimeTextPaint;
protected final Bitmap mScrubber;
protected int mScrubberPadding; // adds some touch tolerance around the
// scrubber
protected int mScrubberLeft;
protected int mScrubberTop;
protected int mScrubberCorrection;
protected boolean mScrubbing;
protected boolean mShowTimes;
protected boolean mShowScrubber;
protected int mTotalTime;
protected int mCurrentTime;
protected final Rect mTimeBounds;
protected int mVPaddingInPx;
public TimeBar(Context context, Listener listener) {
super(context);
mListener = Utils.checkNotNull(listener);
mShowTimes = true;
mShowScrubber = true;
mProgressBar = new Rect();
mPlayedBar = new Rect();
mProgressPaint = new Paint();
mProgressPaint.setColor(0xFF808080);
mPlayedPaint = new Paint();
mPlayedPaint.setColor(0xFFFFFFFF);
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float textSizeInPx = metrics.density * TEXT_SIZE_IN_DP;
mTimeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTimeTextPaint.setColor(0xFFCECECE);
mTimeTextPaint.setTextSize(textSizeInPx);
mTimeTextPaint.setTextAlign(Paint.Align.CENTER);
mTimeBounds = new Rect();
mTimeTextPaint.getTextBounds("0:00:00", 0, 7, mTimeBounds);
mScrubber = BitmapFactory.decodeResource(getResources(), R.drawable.scrubber_knob);
mScrubberPadding = (int) (metrics.density * SCRUBBER_PADDING_IN_DP);
mVPaddingInPx = (int) (metrics.density * V_PADDING_IN_DP);
}
private void update() {
mPlayedBar.set(mProgressBar);
if (mTotalTime > 0) {
mPlayedBar.right =
mPlayedBar.left + (int) ((mProgressBar.width() * (long) mCurrentTime) / mTotalTime);
} else {
mPlayedBar.right = mProgressBar.left;
}
if (!mScrubbing) {
mScrubberLeft = mPlayedBar.right - mScrubber.getWidth() / 2;
}
invalidate();
}
/**
* @return the preferred height of this view, including invisible padding
*/
public int getPreferredHeight() {
return mTimeBounds.height() + mVPaddingInPx + mScrubberPadding;
}
/**
* @return the height of the time bar, excluding invisible padding
*/
public int getBarHeight() {
return mTimeBounds.height() + mVPaddingInPx;
}
public void setTime(int currentTime, int totalTime,
int trimStartTime, int trimEndTime) {
if (mCurrentTime == currentTime && mTotalTime == totalTime) {
return;
}
mCurrentTime = currentTime;
mTotalTime = totalTime;
update();
}
private boolean inScrubber(float x, float y) {
int scrubberRight = mScrubberLeft + mScrubber.getWidth();
int scrubberBottom = mScrubberTop + mScrubber.getHeight();
return mScrubberLeft - mScrubberPadding < x && x < scrubberRight + mScrubberPadding
&& mScrubberTop - mScrubberPadding < y && y < scrubberBottom + mScrubberPadding;
}
private void clampScrubber() {
int half = mScrubber.getWidth() / 2;
int max = mProgressBar.right - half;
int min = mProgressBar.left - half;
mScrubberLeft = Math.min(max, Math.max(min, mScrubberLeft));
}
private int getScrubberTime() {
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) {
int w = r - l;
int h = b - t;
if (!mShowTimes && !mShowScrubber) {
mProgressBar.set(0, 0, w, h);
} else {
int margin = mScrubber.getWidth() / 3;
if (mShowTimes) {
margin += mTimeBounds.width();
}
int progressY = (h + mScrubberPadding) / 2;
mScrubberTop = progressY - mScrubber.getHeight() / 2 + 1;
mProgressBar.set(
getPaddingLeft() + margin, progressY,
w - getPaddingRight() - margin, progressY + 4);
}
update();
}
@Override
protected void onDraw(Canvas canvas) {
// draw progress bars
canvas.drawRect(mProgressBar, mProgressPaint);
canvas.drawRect(mPlayedBar, mPlayedPaint);
// draw scrubber and timers
if (mShowScrubber) {
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);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mShowScrubber) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
mScrubberCorrection = inScrubber(x, y)
? x - mScrubberLeft
: mScrubber.getWidth() / 2;
mScrubbing = true;
mListener.onScrubbingStart();
}
// fall-through
case MotionEvent.ACTION_MOVE: {
mScrubberLeft = x - mScrubberCorrection;
clampScrubber();
mCurrentTime = getScrubberTime();
mListener.onScrubbingMove(mCurrentTime);
invalidate();
return true;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
mListener.onScrubbingEnd(getScrubberTime(), 0, 0);
mScrubbing = false;
return true;
}
}
}
return false;
}
protected String stringForTime(long millis) {
int totalSeconds = (int) millis / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
if (hours > 0) {
return String.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return String.format("%02d:%02d", minutes, seconds).toString();
}
}
}