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 com.android.gallery3d.common.Utils;
     20 import com.android.gallery3d.R;
     21 
     22 import android.content.Context;
     23 import android.graphics.Bitmap;
     24 import android.graphics.BitmapFactory;
     25 import android.graphics.Canvas;
     26 import android.graphics.Paint;
     27 import android.graphics.Rect;
     28 import android.util.DisplayMetrics;
     29 import android.view.MotionEvent;
     30 import android.view.View;
     31 
     32 /**
     33  * The time bar view, which includes the current and total time, the progress bar,
     34  * and the scrubber.
     35  */
     36 public class TimeBar extends View {
     37 
     38   public interface Listener {
     39     void onScrubbingStart();
     40     void onScrubbingMove(int time);
     41     void onScrubbingEnd(int time);
     42   }
     43 
     44   // Padding around the scrubber to increase its touch target
     45   private static final int SCRUBBER_PADDING_IN_DP = 10;
     46 
     47   // The total padding, top plus bottom
     48   private static final int V_PADDING_IN_DP = 30;
     49 
     50   private static final int TEXT_SIZE_IN_DP = 14;
     51 
     52   private final Listener listener;
     53 
     54   // the bars we use for displaying the progress
     55   private final Rect progressBar;
     56   private final Rect playedBar;
     57 
     58   private final Paint progressPaint;
     59   private final Paint playedPaint;
     60   private final Paint timeTextPaint;
     61 
     62   private final Bitmap scrubber;
     63   private final int scrubberPadding; // adds some touch tolerance around the scrubber
     64 
     65   private int scrubberLeft;
     66   private int scrubberTop;
     67   private int scrubberCorrection;
     68   private boolean scrubbing;
     69   private boolean showTimes;
     70   private boolean showScrubber;
     71 
     72   private int totalTime;
     73   private int currentTime;
     74 
     75   private final Rect timeBounds;
     76 
     77   private int vPaddingInPx;
     78 
     79   public TimeBar(Context context, Listener listener) {
     80     super(context);
     81     this.listener = Utils.checkNotNull(listener);
     82 
     83     showTimes = true;
     84     showScrubber = true;
     85 
     86     progressBar = new Rect();
     87     playedBar = new Rect();
     88 
     89     progressPaint = new Paint();
     90     progressPaint.setColor(0xFF808080);
     91     playedPaint = new Paint();
     92     playedPaint.setColor(0xFFFFFFFF);
     93 
     94     DisplayMetrics metrics = context.getResources().getDisplayMetrics();
     95     float textSizeInPx = metrics.density * TEXT_SIZE_IN_DP;
     96     timeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     97     timeTextPaint.setColor(0xFFCECECE);
     98     timeTextPaint.setTextSize(textSizeInPx);
     99     timeTextPaint.setTextAlign(Paint.Align.CENTER);
    100 
    101     timeBounds = new Rect();
    102     timeTextPaint.getTextBounds("0:00:00", 0, 7, timeBounds);
    103 
    104     scrubber = BitmapFactory.decodeResource(getResources(), R.drawable.scrubber_knob);
    105     scrubberPadding = (int) (metrics.density * SCRUBBER_PADDING_IN_DP);
    106 
    107     vPaddingInPx = (int) (metrics.density * V_PADDING_IN_DP);
    108   }
    109 
    110   private void update() {
    111     playedBar.set(progressBar);
    112 
    113     if (totalTime > 0) {
    114       playedBar.right =
    115           playedBar.left + (int) ((progressBar.width() * (long) currentTime) / totalTime);
    116     } else {
    117       playedBar.right = progressBar.left;
    118     }
    119 
    120     if (!scrubbing) {
    121       scrubberLeft = playedBar.right - scrubber.getWidth() / 2;
    122     }
    123     invalidate();
    124   }
    125 
    126   /**
    127    * @return the preferred height of this view, including invisible padding
    128    */
    129   public int getPreferredHeight() {
    130     return timeBounds.height() + vPaddingInPx + scrubberPadding;
    131   }
    132 
    133   /**
    134    * @return the height of the time bar, excluding invisible padding
    135    */
    136   public int getBarHeight() {
    137     return timeBounds.height() + vPaddingInPx;
    138   }
    139 
    140   public void setTime(int currentTime, int totalTime) {
    141     if (this.currentTime == currentTime && this.totalTime == totalTime) {
    142         return;
    143     }
    144     this.currentTime = currentTime;
    145     this.totalTime = totalTime;
    146     update();
    147   }
    148 
    149   public void setShowTimes(boolean showTimes) {
    150     this.showTimes = showTimes;
    151     requestLayout();
    152   }
    153 
    154   public void resetTime() {
    155     setTime(0, 0);
    156   }
    157 
    158   public void setShowScrubber(boolean showScrubber) {
    159     this.showScrubber = showScrubber;
    160     if (!showScrubber && scrubbing) {
    161       listener.onScrubbingEnd(getScrubberTime());
    162       scrubbing = false;
    163     }
    164     requestLayout();
    165   }
    166 
    167   private boolean inScrubber(float x, float y) {
    168     int scrubberRight = scrubberLeft + scrubber.getWidth();
    169     int scrubberBottom = scrubberTop + scrubber.getHeight();
    170     return scrubberLeft - scrubberPadding < x && x < scrubberRight + scrubberPadding
    171         && scrubberTop - scrubberPadding < y && y < scrubberBottom + scrubberPadding;
    172   }
    173 
    174   private void clampScrubber() {
    175     int half = scrubber.getWidth() / 2;
    176     int max = progressBar.right - half;
    177     int min = progressBar.left - half;
    178     scrubberLeft = Math.min(max, Math.max(min, scrubberLeft));
    179   }
    180 
    181   private int getScrubberTime() {
    182     return (int) ((long) (scrubberLeft + scrubber.getWidth() / 2 - progressBar.left)
    183         * totalTime / progressBar.width());
    184   }
    185 
    186   @Override
    187   protected void onLayout(boolean changed, int l, int t, int r, int b) {
    188     int w = r - l;
    189     int h = b - t;
    190     if (!showTimes && !showScrubber) {
    191       progressBar.set(0, 0, w, h);
    192     } else {
    193       int margin = scrubber.getWidth() / 3;
    194       if (showTimes) {
    195         margin += timeBounds.width();
    196       }
    197       int progressY = (h + scrubberPadding) / 2;
    198       scrubberTop = progressY - scrubber.getHeight() / 2 + 1;
    199       progressBar.set(
    200           getPaddingLeft() + margin, progressY,
    201           w - getPaddingRight() - margin, progressY + 4);
    202     }
    203     update();
    204   }
    205 
    206   @Override
    207   public void draw(Canvas canvas) {
    208     super.draw(canvas);
    209 
    210     // draw progress bars
    211     canvas.drawRect(progressBar, progressPaint);
    212     canvas.drawRect(playedBar, playedPaint);
    213 
    214     // draw scrubber and timers
    215     if (showScrubber) {
    216       canvas.drawBitmap(scrubber, scrubberLeft, scrubberTop, null);
    217     }
    218     if (showTimes) {
    219       canvas.drawText(
    220           stringForTime(currentTime),
    221           timeBounds.width() / 2 + getPaddingLeft(),
    222           timeBounds.height() + vPaddingInPx / 2 + scrubberPadding + 1,
    223           timeTextPaint);
    224       canvas.drawText(
    225           stringForTime(totalTime),
    226           getWidth() - getPaddingRight() - timeBounds.width() / 2,
    227           timeBounds.height() + vPaddingInPx / 2 + scrubberPadding + 1,
    228           timeTextPaint);
    229     }
    230   }
    231 
    232   @Override
    233   public boolean onTouchEvent(MotionEvent event) {
    234 
    235     if (showScrubber) {
    236       int x = (int) event.getX();
    237       int y = (int) event.getY();
    238 
    239       switch (event.getAction()) {
    240         case MotionEvent.ACTION_DOWN:
    241           if (inScrubber(x, y)) {
    242             scrubbing = true;
    243             scrubberCorrection = x - scrubberLeft;
    244             listener.onScrubbingStart();
    245             return true;
    246           }
    247           break;
    248         case MotionEvent.ACTION_MOVE:
    249           if (scrubbing) {
    250             scrubberLeft = x - scrubberCorrection;
    251             clampScrubber();
    252             currentTime = getScrubberTime();
    253             listener.onScrubbingMove(currentTime);
    254             invalidate();
    255             return true;
    256           }
    257           break;
    258         case MotionEvent.ACTION_UP:
    259           if (scrubbing) {
    260             listener.onScrubbingEnd(getScrubberTime());
    261             scrubbing = false;
    262             return true;
    263           }
    264           break;
    265       }
    266     }
    267     return false;
    268   }
    269 
    270   private String stringForTime(long millis) {
    271     int totalSeconds = (int) millis / 1000;
    272     int seconds = totalSeconds % 60;
    273     int minutes = (totalSeconds / 60) % 60;
    274     int hours = totalSeconds / 3600;
    275     if (hours > 0) {
    276       return String.format("%d:%02d:%02d", hours, minutes, seconds).toString();
    277     } else {
    278       return String.format("%02d:%02d", minutes, seconds).toString();
    279     }
    280   }
    281 
    282 }
    283