Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2012 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.view.MotionEvent;
     24 
     25 import com.android.gallery3d.R;
     26 
     27 /**
     28  * The trim time bar view, which includes the current and total time, the progress
     29  * bar, and the scrubbers for current time, start and end time for trimming.
     30  */
     31 public class TrimTimeBar extends TimeBar {
     32 
     33     public static final int SCRUBBER_NONE = 0;
     34     public static final int SCRUBBER_START = 1;
     35     public static final int SCRUBBER_CURRENT = 2;
     36     public static final int SCRUBBER_END = 3;
     37 
     38     private int mPressedThumb = SCRUBBER_NONE;
     39 
     40     // On touch event, the setting order is Scrubber Position -> Time ->
     41     // PlayedBar. At the setTimes(), activity can update the Time directly, then
     42     // PlayedBar will be updated too.
     43     private int mTrimStartScrubberLeft;
     44     private int mTrimEndScrubberLeft;
     45 
     46     private int mTrimStartScrubberTop;
     47     private int mTrimEndScrubberTop;
     48 
     49     private int mTrimStartTime;
     50     private int mTrimEndTime;
     51 
     52     private final Bitmap mTrimStartScrubber;
     53     private final Bitmap mTrimEndScrubber;
     54     public TrimTimeBar(Context context, Listener listener) {
     55         super(context, listener);
     56 
     57         mTrimStartTime = 0;
     58         mTrimEndTime = 0;
     59         mTrimStartScrubberLeft = 0;
     60         mTrimEndScrubberLeft = 0;
     61         mTrimStartScrubberTop = 0;
     62         mTrimEndScrubberTop = 0;
     63 
     64         mTrimStartScrubber = BitmapFactory.decodeResource(getResources(),
     65                 R.drawable.text_select_handle_left);
     66         mTrimEndScrubber = BitmapFactory.decodeResource(getResources(),
     67                 R.drawable.text_select_handle_right);
     68         // Increase the size of this trimTimeBar, but minimize the scrubber
     69         // touch padding since we have 3 scrubbers now.
     70         mScrubberPadding = 0;
     71         mVPaddingInPx = mVPaddingInPx * 3 / 2;
     72     }
     73 
     74     private int getBarPosFromTime(int time) {
     75         return mProgressBar.left +
     76                 (int) ((mProgressBar.width() * (long) time) / mTotalTime);
     77     }
     78 
     79     private int trimStartScrubberTipOffset() {
     80         return mTrimStartScrubber.getWidth() * 3 / 4;
     81     }
     82 
     83     private int trimEndScrubberTipOffset() {
     84         return mTrimEndScrubber.getWidth() / 4;
     85     }
     86 
     87     // Based on all the time info (current, total, trimStart, trimEnd), we
     88     // decide the playedBar size.
     89     private void updatePlayedBarAndScrubberFromTime() {
     90         // According to the Time, update the Played Bar
     91         mPlayedBar.set(mProgressBar);
     92         if (mTotalTime > 0) {
     93             // set playedBar according to the trim time.
     94             mPlayedBar.left = getBarPosFromTime(mTrimStartTime);
     95             mPlayedBar.right = getBarPosFromTime(mCurrentTime);
     96             if (!mScrubbing) {
     97                 mScrubberLeft = mPlayedBar.right - mScrubber.getWidth() / 2;
     98                 mTrimStartScrubberLeft = mPlayedBar.left - trimStartScrubberTipOffset();
     99                 mTrimEndScrubberLeft = getBarPosFromTime(mTrimEndTime)
    100                         - trimEndScrubberTipOffset();
    101             }
    102         } else {
    103             // If the video is not prepared, just show the scrubber at the end
    104             // of progressBar
    105             mPlayedBar.right = mProgressBar.left;
    106             mScrubberLeft = mProgressBar.left - mScrubber.getWidth() / 2;
    107             mTrimStartScrubberLeft = mProgressBar.left - trimStartScrubberTipOffset();
    108             mTrimEndScrubberLeft = mProgressBar.right - trimEndScrubberTipOffset();
    109         }
    110     }
    111 
    112     private void initTrimTimeIfNeeded() {
    113         if (mTotalTime > 0 && mTrimEndTime == 0) {
    114             mTrimEndTime = mTotalTime;
    115         }
    116     }
    117 
    118     private void update() {
    119         initTrimTimeIfNeeded();
    120         updatePlayedBarAndScrubberFromTime();
    121         invalidate();
    122     }
    123 
    124     @Override
    125     public void setTime(int currentTime, int totalTime,
    126             int trimStartTime, int trimEndTime) {
    127         if (mCurrentTime == currentTime && mTotalTime == totalTime
    128                 && mTrimStartTime == trimStartTime && mTrimEndTime == trimEndTime) {
    129             return;
    130         }
    131         mCurrentTime = currentTime;
    132         mTotalTime = totalTime;
    133         mTrimStartTime = trimStartTime;
    134         mTrimEndTime = trimEndTime;
    135         update();
    136     }
    137 
    138     private int whichScrubber(float x, float y) {
    139         if (inScrubber(x, y, mTrimStartScrubberLeft, mTrimStartScrubberTop, mTrimStartScrubber)) {
    140             return SCRUBBER_START;
    141         } else if (inScrubber(x, y, mTrimEndScrubberLeft, mTrimEndScrubberTop, mTrimEndScrubber)) {
    142             return SCRUBBER_END;
    143         } else if (inScrubber(x, y, mScrubberLeft, mScrubberTop, mScrubber)) {
    144             return SCRUBBER_CURRENT;
    145         }
    146         return SCRUBBER_NONE;
    147     }
    148 
    149     private boolean inScrubber(float x, float y, int startX, int startY, Bitmap scrubber) {
    150         int scrubberRight = startX + scrubber.getWidth();
    151         int scrubberBottom = startY + scrubber.getHeight();
    152         return startX < x && x < scrubberRight && startY < y && y < scrubberBottom;
    153     }
    154 
    155     private int clampScrubber(int scrubberLeft, int offset, int lowerBound, int upperBound) {
    156         int max = upperBound - offset;
    157         int min = lowerBound - offset;
    158         return Math.min(max, Math.max(min, scrubberLeft));
    159     }
    160 
    161     private int getScrubberTime(int scrubberLeft, int offset) {
    162         return (int) ((long) (scrubberLeft + offset - mProgressBar.left)
    163                 * mTotalTime / mProgressBar.width());
    164     }
    165 
    166     @Override
    167     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    168         int w = r - l;
    169         int h = b - t;
    170         if (!mShowTimes && !mShowScrubber) {
    171             mProgressBar.set(0, 0, w, h);
    172         } else {
    173             int margin = mScrubber.getWidth() / 3;
    174             if (mShowTimes) {
    175                 margin += mTimeBounds.width();
    176             }
    177             int progressY = h / 4;
    178             int scrubberY = progressY - mScrubber.getHeight() / 2 + 1;
    179             mScrubberTop = scrubberY;
    180             mTrimStartScrubberTop = progressY;
    181             mTrimEndScrubberTop = progressY;
    182             mProgressBar.set(
    183                     getPaddingLeft() + margin, progressY,
    184                     w - getPaddingRight() - margin, progressY + 4);
    185         }
    186         update();
    187     }
    188 
    189     @Override
    190     protected void onDraw(Canvas canvas) {
    191         // draw progress bars
    192         canvas.drawRect(mProgressBar, mProgressPaint);
    193         canvas.drawRect(mPlayedBar, mPlayedPaint);
    194 
    195         if (mShowTimes) {
    196             canvas.drawText(
    197                     stringForTime(mCurrentTime),
    198                             mTimeBounds.width() / 2 + getPaddingLeft(),
    199                             mTimeBounds.height() / 2 +  mTrimStartScrubberTop,
    200                     mTimeTextPaint);
    201             canvas.drawText(
    202                     stringForTime(mTotalTime),
    203                             getWidth() - getPaddingRight() - mTimeBounds.width() / 2,
    204                             mTimeBounds.height() / 2 +  mTrimStartScrubberTop,
    205                     mTimeTextPaint);
    206         }
    207 
    208         // draw extra scrubbers
    209         if (mShowScrubber) {
    210             canvas.drawBitmap(mScrubber, mScrubberLeft, mScrubberTop, null);
    211             canvas.drawBitmap(mTrimStartScrubber, mTrimStartScrubberLeft,
    212                     mTrimStartScrubberTop, null);
    213             canvas.drawBitmap(mTrimEndScrubber, mTrimEndScrubberLeft,
    214                     mTrimEndScrubberTop, null);
    215         }
    216     }
    217 
    218     private void updateTimeFromPos() {
    219         mCurrentTime = getScrubberTime(mScrubberLeft, mScrubber.getWidth() / 2);
    220         mTrimStartTime = getScrubberTime(mTrimStartScrubberLeft, trimStartScrubberTipOffset());
    221         mTrimEndTime = getScrubberTime(mTrimEndScrubberLeft, trimEndScrubberTipOffset());
    222     }
    223 
    224     @Override
    225     public boolean onTouchEvent(MotionEvent event) {
    226         if (mShowScrubber) {
    227             int x = (int) event.getX();
    228             int y = (int) event.getY();
    229 
    230             switch (event.getAction()) {
    231                 case MotionEvent.ACTION_DOWN:
    232                     mPressedThumb = whichScrubber(x, y);
    233                     switch (mPressedThumb) {
    234                         case SCRUBBER_NONE:
    235                             break;
    236                         case SCRUBBER_CURRENT:
    237                             mScrubbing = true;
    238                             mScrubberCorrection = x - mScrubberLeft;
    239                             break;
    240                         case SCRUBBER_START:
    241                             mScrubbing = true;
    242                             mScrubberCorrection = x - mTrimStartScrubberLeft;
    243                             break;
    244                         case SCRUBBER_END:
    245                             mScrubbing = true;
    246                             mScrubberCorrection = x - mTrimEndScrubberLeft;
    247                             break;
    248                     }
    249                     if (mScrubbing == true) {
    250                         mListener.onScrubbingStart();
    251                         return true;
    252                     }
    253                     break;
    254                 case MotionEvent.ACTION_MOVE:
    255                     if (mScrubbing) {
    256                         int seekToTime = -1;
    257                         int lowerBound = mTrimStartScrubberLeft + trimStartScrubberTipOffset();
    258                         int upperBound = mTrimEndScrubberLeft + trimEndScrubberTipOffset();
    259                         switch (mPressedThumb) {
    260                             case SCRUBBER_CURRENT:
    261                                 mScrubberLeft = x - mScrubberCorrection;
    262                                 mScrubberLeft =
    263                                         clampScrubber(mScrubberLeft,
    264                                                 mScrubber.getWidth() / 2,
    265                                                 lowerBound, upperBound);
    266                                 seekToTime = getScrubberTime(mScrubberLeft,
    267                                         mScrubber.getWidth() / 2);
    268                                 break;
    269                             case SCRUBBER_START:
    270                                 mTrimStartScrubberLeft = x - mScrubberCorrection;
    271                                 // Limit start <= end
    272                                 if (mTrimStartScrubberLeft > mTrimEndScrubberLeft) {
    273                                     mTrimStartScrubberLeft = mTrimEndScrubberLeft;
    274                                 }
    275                                 lowerBound = mProgressBar.left;
    276                                 mTrimStartScrubberLeft =
    277                                         clampScrubber(mTrimStartScrubberLeft,
    278                                                 trimStartScrubberTipOffset(),
    279                                                 lowerBound, upperBound);
    280                                 seekToTime = getScrubberTime(mTrimStartScrubberLeft,
    281                                         trimStartScrubberTipOffset());
    282                                 break;
    283                             case SCRUBBER_END:
    284                                 mTrimEndScrubberLeft = x - mScrubberCorrection;
    285                                 upperBound = mProgressBar.right;
    286                                 mTrimEndScrubberLeft =
    287                                         clampScrubber(mTrimEndScrubberLeft,
    288                                                 trimEndScrubberTipOffset(),
    289                                                 lowerBound, upperBound);
    290                                 seekToTime = getScrubberTime(mTrimEndScrubberLeft,
    291                                         trimEndScrubberTipOffset());
    292                                 break;
    293                         }
    294                         updateTimeFromPos();
    295                         updatePlayedBarAndScrubberFromTime();
    296                         if (seekToTime != -1) {
    297                             mListener.onScrubbingMove(seekToTime);
    298                         }
    299                         invalidate();
    300                         return true;
    301                     }
    302                     break;
    303                 case MotionEvent.ACTION_CANCEL:
    304                 case MotionEvent.ACTION_UP:
    305                     if (mScrubbing) {
    306                         int seekToTime = 0;
    307                         switch (mPressedThumb) {
    308                             case SCRUBBER_CURRENT:
    309                                 seekToTime = getScrubberTime(mScrubberLeft,
    310                                         mScrubber.getWidth() / 2);
    311                                 break;
    312                             case SCRUBBER_START:
    313                                 seekToTime = getScrubberTime(mTrimStartScrubberLeft,
    314                                         trimStartScrubberTipOffset());
    315                                 mScrubberLeft = mTrimStartScrubberLeft +
    316                                         trimStartScrubberTipOffset() - mScrubber.getWidth() / 2;
    317                                 break;
    318                             case SCRUBBER_END:
    319                                 seekToTime = getScrubberTime(mTrimEndScrubberLeft,
    320                                         trimEndScrubberTipOffset());
    321                                 mScrubberLeft = mTrimEndScrubberLeft +
    322                                         trimEndScrubberTipOffset() - mScrubber.getWidth() / 2;
    323                                 break;
    324                         }
    325                         updateTimeFromPos();
    326                         mListener.onScrubbingEnd(seekToTime,
    327                                 getScrubberTime(mTrimStartScrubberLeft,
    328                                         trimStartScrubberTipOffset()),
    329                                 getScrubberTime(mTrimEndScrubberLeft, trimEndScrubberTipOffset()));
    330                         mScrubbing = false;
    331                         mPressedThumb = SCRUBBER_NONE;
    332                         return true;
    333                     }
    334                     break;
    335             }
    336         }
    337         return false;
    338     }
    339 }
    340