blob: 1f36306225bb752c4439778493ce125f97de2811 [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);
}
// 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;
private final Listener listener;
// the bars we use for displaying the progress
private final Rect progressBar;
private final Rect playedBar;
private final Paint progressPaint;
private final Paint playedPaint;
private final Paint timeTextPaint;
private final Bitmap scrubber;
private final int scrubberPadding; // adds some touch tolerance around the scrubber
private int scrubberLeft;
private int scrubberTop;
private int scrubberCorrection;
private boolean scrubbing;
private boolean showTimes;
private boolean showScrubber;
private int totalTime;
private int currentTime;
private final Rect timeBounds;
private int vPaddingInPx;
public TimeBar(Context context, Listener listener) {
super(context);
this.listener = Utils.checkNotNull(listener);
showTimes = true;
showScrubber = true;
progressBar = new Rect();
playedBar = new Rect();
progressPaint = new Paint();
progressPaint.setColor(0xFF808080);
playedPaint = new Paint();
playedPaint.setColor(0xFFFFFFFF);
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float textSizeInPx = metrics.density * TEXT_SIZE_IN_DP;
timeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
timeTextPaint.setColor(0xFFCECECE);
timeTextPaint.setTextSize(textSizeInPx);
timeTextPaint.setTextAlign(Paint.Align.CENTER);
timeBounds = new Rect();
timeTextPaint.getTextBounds("0:00:00", 0, 7, timeBounds);
scrubber = BitmapFactory.decodeResource(getResources(), R.drawable.scrubber_knob);
scrubberPadding = (int) (metrics.density * SCRUBBER_PADDING_IN_DP);
vPaddingInPx = (int) (metrics.density * V_PADDING_IN_DP);
}
private void update() {
playedBar.set(progressBar);
if (totalTime > 0) {
playedBar.right =
playedBar.left + (int) ((progressBar.width() * (long) currentTime) / totalTime);
} else {
playedBar.right = progressBar.left;
}
if (!scrubbing) {
scrubberLeft = playedBar.right - scrubber.getWidth() / 2;
}
invalidate();
}
/**
* @return the preferred height of this view, including invisible padding
*/
public int getPreferredHeight() {
return timeBounds.height() + vPaddingInPx + scrubberPadding;
}
/**
* @return the height of the time bar, excluding invisible padding
*/
public int getBarHeight() {
return timeBounds.height() + vPaddingInPx;
}
public void setTime(int currentTime, int totalTime) {
if (this.currentTime == currentTime && this.totalTime == totalTime) {
return;
}
this.currentTime = currentTime;
this.totalTime = totalTime;
update();
}
public void setShowTimes(boolean showTimes) {
this.showTimes = showTimes;
requestLayout();
}
public void resetTime() {
setTime(0, 0);
}
public void setShowScrubber(boolean showScrubber) {
this.showScrubber = showScrubber;
if (!showScrubber && scrubbing) {
listener.onScrubbingEnd(getScrubberTime());
scrubbing = false;
}
requestLayout();
}
private boolean inScrubber(float x, float y) {
int scrubberRight = scrubberLeft + scrubber.getWidth();
int scrubberBottom = scrubberTop + scrubber.getHeight();
return scrubberLeft - scrubberPadding < x && x < scrubberRight + scrubberPadding
&& scrubberTop - scrubberPadding < y && y < scrubberBottom + scrubberPadding;
}
private void clampScrubber() {
int half = scrubber.getWidth() / 2;
int max = progressBar.right - half;
int min = progressBar.left - half;
scrubberLeft = Math.min(max, Math.max(min, scrubberLeft));
}
private int getScrubberTime() {
return (int) ((long) (scrubberLeft + scrubber.getWidth() / 2 - progressBar.left)
* totalTime / progressBar.width());
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int w = r - l;
int h = b - t;
if (!showTimes && !showScrubber) {
progressBar.set(0, 0, w, h);
} else {
int margin = scrubber.getWidth() / 3;
if (showTimes) {
margin += timeBounds.width();
}
int progressY = (h + scrubberPadding) / 2;
scrubberTop = progressY - scrubber.getHeight() / 2 + 1;
progressBar.set(
getPaddingLeft() + margin, progressY,
w - getPaddingRight() - margin, progressY + 4);
}
update();
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
// draw progress bars
canvas.drawRect(progressBar, progressPaint);
canvas.drawRect(playedBar, playedPaint);
// draw scrubber and timers
if (showScrubber) {
canvas.drawBitmap(scrubber, scrubberLeft, scrubberTop, null);
}
if (showTimes) {
canvas.drawText(
stringForTime(currentTime),
timeBounds.width() / 2 + getPaddingLeft(),
timeBounds.height() + vPaddingInPx / 2 + scrubberPadding + 1,
timeTextPaint);
canvas.drawText(
stringForTime(totalTime),
getWidth() - getPaddingRight() - timeBounds.width() / 2,
timeBounds.height() + vPaddingInPx / 2 + scrubberPadding + 1,
timeTextPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (showScrubber) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (inScrubber(x, y)) {
scrubbing = true;
scrubberCorrection = x - scrubberLeft;
listener.onScrubbingStart();
return true;
}
break;
case MotionEvent.ACTION_MOVE:
if (scrubbing) {
scrubberLeft = x - scrubberCorrection;
clampScrubber();
currentTime = getScrubberTime();
listener.onScrubbingMove(currentTime);
invalidate();
return true;
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (scrubbing) {
listener.onScrubbingEnd(getScrubberTime());
scrubbing = false;
return true;
}
break;
}
}
return false;
}
private 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();
}
}
}