Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.gallery3d.app;
     18 
     19 import android.content.Context;
     20 import android.graphics.Bitmap;
     21 import android.graphics.BitmapFactory;
     22 import android.graphics.Canvas;
     23 import android.graphics.Paint;
     24 import android.graphics.Rect;
     25 import android.util.DisplayMetrics;
     26 import android.view.MotionEvent;
     27 import android.view.View;
     28 
     29 import com.android.gallery3d.R;
     30 import com.android.gallery3d.common.Utils;
     31 
     32 /**
     33  * The time bar view, which includes the current and total time, the progress
     34  * bar, and the scrubber.
     35  */
     36 public class TimeBar extends View {
     37 
     38     public interface Listener {
     39         void onScrubbingStart();
     40 
     41         void onScrubbingMove(int time);
     42 
     43         void onScrubbingEnd(int time, int start, int end);
     44     }
     45 
     46     // Padding around the scrubber to increase its touch target
     47     private static final int SCRUBBER_PADDING_IN_DP = 10;
     48 
     49     // The total padding, top plus bottom
     50     private static final int V_PADDING_IN_DP = 30;
     51 
     52     private static final int TEXT_SIZE_IN_DP = 14;
     53 
     54     protected final Listener mListener;
     55 
     56     // the bars we use for displaying the progress
     57     protected final Rect mProgressBar;
     58     protected final Rect mPlayedBar;
     59 
     60     protected final Paint mProgressPaint;
     61     protected final Paint mPlayedPaint;
     62     protected final Paint mTimeTextPaint;
     63 
     64     protected final Bitmap mScrubber;
     65     protected int mScrubberPadding; // adds some touch tolerance around the
     66                                     // scrubber
     67 
     68     protected int mScrubberLeft;
     69     protected int mScrubberTop;
     70     protected int mScrubberCorrection;
     71     protected boolean mScrubbing;
     72     protected boolean mShowTimes;
     73     protected boolean mShowScrubber;
     74 
     75     protected int mTotalTime;
     76     protected int mCurrentTime;
     77 
     78     protected final Rect mTimeBounds;
     79 
     80     protected int mVPaddingInPx;
     81 
     82     public TimeBar(Context context, Listener listener) {
     83         super(context);
     84         mListener = Utils.checkNotNull(listener);
     85 
     86         mShowTimes = true;
     87         mShowScrubber = true;
     88 
     89         mProgressBar = new Rect();
     90         mPlayedBar = new Rect();
     91 
     92         mProgressPaint = new Paint();
     93         mProgressPaint.setColor(0xFF808080);
     94         mPlayedPaint = new Paint();
     95         mPlayedPaint.setColor(0xFFFFFFFF);
     96 
     97         DisplayMetrics metrics = context.getResources().getDisplayMetrics();
     98         float textSizeInPx = metrics.density * TEXT_SIZE_IN_DP;
     99         mTimeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    100         mTimeTextPaint.setColor(0xFFCECECE);
    101         mTimeTextPaint.setTextSize(textSizeInPx);
    102         mTimeTextPaint.setTextAlign(Paint.Align.CENTER);
    103 
    104         mTimeBounds = new Rect();
    105         mTimeTextPaint.getTextBounds("0:00:00", 0, 7, mTimeBounds);
    106 
    107         mScrubber = BitmapFactory.decodeResource(getResources(), R.drawable.scrubber_knob);
    108         mScrubberPadding = (int) (metrics.density * SCRUBBER_PADDING_IN_DP);
    109 
    110         mVPaddingInPx = (int) (metrics.density * V_PADDING_IN_DP);
    111     }
    112 
    113     private void update() {
    114         mPlayedBar.set(mProgressBar);
    115 
    116         if (mTotalTime > 0) {
    117             mPlayedBar.right =
    118                     mPlayedBar.left + (int) ((mProgressBar.width() * (long) mCurrentTime) / mTotalTime);
    119         } else {
    120             mPlayedBar.right = mProgressBar.left;
    121         }
    122 
    123         if (!mScrubbing) {
    124             mScrubberLeft = mPlayedBar.right - mScrubber.getWidth() / 2;
    125         }
    126         invalidate();
    127     }
    128 
    129     /**
    130      * @return the preferred height of this view, including invisible padding
    131      */
    132     public int getPreferredHeight() {
    133         return mTimeBounds.height() + mVPaddingInPx + mScrubberPadding;
    134     }
    135 
    136     /**
    137      * @return the height of the time bar, excluding invisible padding
    138      */
    139     public int getBarHeight() {
    140         return mTimeBounds.height() + mVPaddingInPx;
    141     }
    142 
    143     public void setTime(int currentTime, int totalTime,
    144             int trimStartTime, int trimEndTime) {
    145         if (mCurrentTime == currentTime && mTotalTime == totalTime) {
    146             return;
    147         }
    148         mCurrentTime = currentTime;
    149         mTotalTime = totalTime;
    150         update();
    151     }
    152 
    153     private boolean inScrubber(float x, float y) {
    154         int scrubberRight = mScrubberLeft + mScrubber.getWidth();
    155         int scrubberBottom = mScrubberTop + mScrubber.getHeight();
    156         return mScrubberLeft - mScrubberPadding < x && x < scrubberRight + mScrubberPadding
    157                 && mScrubberTop - mScrubberPadding < y && y < scrubberBottom + mScrubberPadding;
    158     }
    159 
    160     private void clampScrubber() {
    161         int half = mScrubber.getWidth() / 2;
    162         int max = mProgressBar.right - half;
    163         int min = mProgressBar.left - half;
    164         mScrubberLeft = Math.min(max, Math.max(min, mScrubberLeft));
    165     }
    166 
    167     private int getScrubberTime() {
    168         return (int) ((long) (mScrubberLeft + mScrubber.getWidth() / 2 - mProgressBar.left)
    169                 * mTotalTime / mProgressBar.width());
    170     }
    171 
    172     @Override
    173     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    174         int w = r - l;
    175         int h = b - t;
    176         if (!mShowTimes && !mShowScrubber) {
    177             mProgressBar.set(0, 0, w, h);
    178         } else {
    179             int margin = mScrubber.getWidth() / 3;
    180             if (mShowTimes) {
    181                 margin += mTimeBounds.width();
    182             }
    183             int progressY = (h + mScrubberPadding) / 2;
    184             mScrubberTop = progressY - mScrubber.getHeight() / 2 + 1;
    185             mProgressBar.set(
    186                     getPaddingLeft() + margin, progressY,
    187                     w - getPaddingRight() - margin, progressY + 4);
    188         }
    189         update();
    190     }
    191 
    192     @Override
    193     protected void onDraw(Canvas canvas) {
    194         // draw progress bars
    195         canvas.drawRect(mProgressBar, mProgressPaint);
    196         canvas.drawRect(mPlayedBar, mPlayedPaint);
    197 
    198         // draw scrubber and timers
    199         if (mShowScrubber) {
    200             canvas.drawBitmap(mScrubber, mScrubberLeft, mScrubberTop, null);
    201         }
    202         if (mShowTimes) {
    203             canvas.drawText(
    204                     stringForTime(mCurrentTime),
    205                             mTimeBounds.width() / 2 + getPaddingLeft(),
    206                             mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1,
    207                     mTimeTextPaint);
    208             canvas.drawText(
    209                     stringForTime(mTotalTime),
    210                             getWidth() - getPaddingRight() - mTimeBounds.width() / 2,
    211                             mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1,
    212                     mTimeTextPaint);
    213         }
    214     }
    215 
    216     @Override
    217     public boolean onTouchEvent(MotionEvent event) {
    218         if (mShowScrubber) {
    219             int x = (int) event.getX();
    220             int y = (int) event.getY();
    221 
    222             switch (event.getAction()) {
    223                 case MotionEvent.ACTION_DOWN: {
    224                     mScrubberCorrection = inScrubber(x, y)
    225                             ? x - mScrubberLeft
    226                             : mScrubber.getWidth() / 2;
    227                     mScrubbing = true;
    228                     mListener.onScrubbingStart();
    229                 }
    230                 // fall-through
    231                 case MotionEvent.ACTION_MOVE: {
    232                     mScrubberLeft = x - mScrubberCorrection;
    233                     clampScrubber();
    234                     mCurrentTime = getScrubberTime();
    235                     mListener.onScrubbingMove(mCurrentTime);
    236                     invalidate();
    237                     return true;
    238                 }
    239                 case MotionEvent.ACTION_CANCEL:
    240                 case MotionEvent.ACTION_UP: {
    241                     mListener.onScrubbingEnd(getScrubberTime(), 0, 0);
    242                     mScrubbing = false;
    243                     return true;
    244                 }
    245             }
    246         }
    247         return false;
    248     }
    249 
    250     protected String stringForTime(long millis) {
    251         int totalSeconds = (int) millis / 1000;
    252         int seconds = totalSeconds % 60;
    253         int minutes = (totalSeconds / 60) % 60;
    254         int hours = totalSeconds / 3600;
    255         if (hours > 0) {
    256             return String.format("%d:%02d:%02d", hours, minutes, seconds).toString();
    257         } else {
    258             return String.format("%02d:%02d", minutes, seconds).toString();
    259         }
    260     }
    261 
    262     public void setSeekable(boolean canSeek) {
    263         mShowScrubber = canSeek;
    264     }
    265 
    266 }
    267