/* * Copyright (C) 2012 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.view.MotionEvent; import com.android.gallery3d.R; /** * The trim time bar view, which includes the current and total time, the progress * bar, and the scrubbers for current time, start and end time for trimming. */ public class TrimTimeBar extends TimeBar { public static final int SCRUBBER_NONE = 0; public static final int SCRUBBER_START = 1; public static final int SCRUBBER_CURRENT = 2; public static final int SCRUBBER_END = 3; private int mPressedThumb = SCRUBBER_NONE; // On touch event, the setting order is Scrubber Position -> Time -> // PlayedBar. At the setTimes(), activity can update the Time directly, then // PlayedBar will be updated too. private int mTrimStartScrubberLeft; private int mTrimEndScrubberLeft; private int mTrimStartScrubberTop; private int mTrimEndScrubberTop; private int mTrimStartTime; private int mTrimEndTime; private final Bitmap mTrimStartScrubber; private final Bitmap mTrimEndScrubber; public TrimTimeBar(Context context, Listener listener) { super(context, listener); mTrimStartTime = 0; mTrimEndTime = 0; mTrimStartScrubberLeft = 0; mTrimEndScrubberLeft = 0; mTrimStartScrubberTop = 0; mTrimEndScrubberTop = 0; mTrimStartScrubber = BitmapFactory.decodeResource(getResources(), R.drawable.text_select_handle_left); mTrimEndScrubber = BitmapFactory.decodeResource(getResources(), R.drawable.text_select_handle_right); // Increase the size of this trimTimeBar, but minimize the scrubber // touch padding since we have 3 scrubbers now. mScrubberPadding = 0; mVPaddingInPx = mVPaddingInPx * 3 / 2; } private int getBarPosFromTime(int time) { return mProgressBar.left + (int) ((mProgressBar.width() * (long) time) / mTotalTime); } private int trimStartScrubberTipOffset() { return mTrimStartScrubber.getWidth() * 3 / 4; } private int trimEndScrubberTipOffset() { return mTrimEndScrubber.getWidth() / 4; } // Based on all the time info (current, total, trimStart, trimEnd), we // decide the playedBar size. private void updatePlayedBarAndScrubberFromTime() { // According to the Time, update the Played Bar mPlayedBar.set(mProgressBar); if (mTotalTime > 0) { // set playedBar according to the trim time. mPlayedBar.left = getBarPosFromTime(mTrimStartTime); mPlayedBar.right = getBarPosFromTime(mCurrentTime); if (!mScrubbing) { mScrubberLeft = mPlayedBar.right - mScrubber.getWidth() / 2; mTrimStartScrubberLeft = mPlayedBar.left - trimStartScrubberTipOffset(); mTrimEndScrubberLeft = getBarPosFromTime(mTrimEndTime) - trimEndScrubberTipOffset(); } } else { // If the video is not prepared, just show the scrubber at the end // of progressBar mPlayedBar.right = mProgressBar.left; mScrubberLeft = mProgressBar.left - mScrubber.getWidth() / 2; mTrimStartScrubberLeft = mProgressBar.left - trimStartScrubberTipOffset(); mTrimEndScrubberLeft = mProgressBar.right - trimEndScrubberTipOffset(); } } private void initTrimTimeIfNeeded() { if (mTotalTime > 0 && mTrimEndTime == 0) { mTrimEndTime = mTotalTime; } } private void update() { initTrimTimeIfNeeded(); updatePlayedBarAndScrubberFromTime(); invalidate(); } @Override public void setTime(int currentTime, int totalTime, int trimStartTime, int trimEndTime) { if (mCurrentTime == currentTime && mTotalTime == totalTime && mTrimStartTime == trimStartTime && mTrimEndTime == trimEndTime) { return; } mCurrentTime = currentTime; mTotalTime = totalTime; mTrimStartTime = trimStartTime; mTrimEndTime = trimEndTime; update(); } private int whichScrubber(float x, float y) { if (inScrubber(x, y, mTrimStartScrubberLeft, mTrimStartScrubberTop, mTrimStartScrubber)) { return SCRUBBER_START; } else if (inScrubber(x, y, mTrimEndScrubberLeft, mTrimEndScrubberTop, mTrimEndScrubber)) { return SCRUBBER_END; } else if (inScrubber(x, y, mScrubberLeft, mScrubberTop, mScrubber)) { return SCRUBBER_CURRENT; } return SCRUBBER_NONE; } private boolean inScrubber(float x, float y, int startX, int startY, Bitmap scrubber) { int scrubberRight = startX + scrubber.getWidth(); int scrubberBottom = startY + scrubber.getHeight(); return startX < x && x < scrubberRight && startY < y && y < scrubberBottom; } private int clampScrubber(int scrubberLeft, int offset, int lowerBound, int upperBound) { int max = upperBound - offset; int min = lowerBound - offset; return Math.min(max, Math.max(min, scrubberLeft)); } private int getScrubberTime(int scrubberLeft, int offset) { return (int) ((long) (scrubberLeft + offset - 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 / 4; int scrubberY = progressY - mScrubber.getHeight() / 2 + 1; mScrubberTop = scrubberY; mTrimStartScrubberTop = progressY; mTrimEndScrubberTop = progressY; 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); if (mShowTimes) { canvas.drawText( stringForTime(mCurrentTime), mTimeBounds.width() / 2 + getPaddingLeft(), mTimeBounds.height() / 2 + mTrimStartScrubberTop, mTimeTextPaint); canvas.drawText( stringForTime(mTotalTime), getWidth() - getPaddingRight() - mTimeBounds.width() / 2, mTimeBounds.height() / 2 + mTrimStartScrubberTop, mTimeTextPaint); } // draw extra scrubbers if (mShowScrubber) { canvas.drawBitmap(mScrubber, mScrubberLeft, mScrubberTop, null); canvas.drawBitmap(mTrimStartScrubber, mTrimStartScrubberLeft, mTrimStartScrubberTop, null); canvas.drawBitmap(mTrimEndScrubber, mTrimEndScrubberLeft, mTrimEndScrubberTop, null); } } private void updateTimeFromPos() { mCurrentTime = getScrubberTime(mScrubberLeft, mScrubber.getWidth() / 2); mTrimStartTime = getScrubberTime(mTrimStartScrubberLeft, trimStartScrubberTipOffset()); mTrimEndTime = getScrubberTime(mTrimEndScrubberLeft, trimEndScrubberTipOffset()); } @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: mPressedThumb = whichScrubber(x, y); switch (mPressedThumb) { case SCRUBBER_NONE: break; case SCRUBBER_CURRENT: mScrubbing = true; mScrubberCorrection = x - mScrubberLeft; break; case SCRUBBER_START: mScrubbing = true; mScrubberCorrection = x - mTrimStartScrubberLeft; break; case SCRUBBER_END: mScrubbing = true; mScrubberCorrection = x - mTrimEndScrubberLeft; break; } if (mScrubbing == true) { mListener.onScrubbingStart(); return true; } break; case MotionEvent.ACTION_MOVE: if (mScrubbing) { int seekToTime = -1; int lowerBound = mTrimStartScrubberLeft + trimStartScrubberTipOffset(); int upperBound = mTrimEndScrubberLeft + trimEndScrubberTipOffset(); switch (mPressedThumb) { case SCRUBBER_CURRENT: mScrubberLeft = x - mScrubberCorrection; mScrubberLeft = clampScrubber(mScrubberLeft, mScrubber.getWidth() / 2, lowerBound, upperBound); seekToTime = getScrubberTime(mScrubberLeft, mScrubber.getWidth() / 2); break; case SCRUBBER_START: mTrimStartScrubberLeft = x - mScrubberCorrection; // Limit start <= end if (mTrimStartScrubberLeft > mTrimEndScrubberLeft) { mTrimStartScrubberLeft = mTrimEndScrubberLeft; } lowerBound = mProgressBar.left; mTrimStartScrubberLeft = clampScrubber(mTrimStartScrubberLeft, trimStartScrubberTipOffset(), lowerBound, upperBound); seekToTime = getScrubberTime(mTrimStartScrubberLeft, trimStartScrubberTipOffset()); break; case SCRUBBER_END: mTrimEndScrubberLeft = x - mScrubberCorrection; upperBound = mProgressBar.right; mTrimEndScrubberLeft = clampScrubber(mTrimEndScrubberLeft, trimEndScrubberTipOffset(), lowerBound, upperBound); seekToTime = getScrubberTime(mTrimEndScrubberLeft, trimEndScrubberTipOffset()); break; } updateTimeFromPos(); updatePlayedBarAndScrubberFromTime(); if (seekToTime != -1) { mListener.onScrubbingMove(seekToTime); } invalidate(); return true; } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: if (mScrubbing) { int seekToTime = 0; switch (mPressedThumb) { case SCRUBBER_CURRENT: seekToTime = getScrubberTime(mScrubberLeft, mScrubber.getWidth() / 2); break; case SCRUBBER_START: seekToTime = getScrubberTime(mTrimStartScrubberLeft, trimStartScrubberTipOffset()); mScrubberLeft = mTrimStartScrubberLeft + trimStartScrubberTipOffset() - mScrubber.getWidth() / 2; break; case SCRUBBER_END: seekToTime = getScrubberTime(mTrimEndScrubberLeft, trimEndScrubberTipOffset()); mScrubberLeft = mTrimEndScrubberLeft + trimEndScrubberTipOffset() - mScrubber.getWidth() / 2; break; } updateTimeFromPos(); mListener.onScrubbingEnd(seekToTime, getScrubberTime(mTrimStartScrubberLeft, trimStartScrubberTipOffset()), getScrubberTime(mTrimEndScrubberLeft, trimEndScrubberTipOffset())); mScrubbing = false; mPressedThumb = SCRUBBER_NONE; return true; } break; } } return false; } }