/* * 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 com.android.gallery3d.common.Utils; import com.android.gallery3d.R; 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; /** * 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_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(); } } }