Home | History | Annotate | Download | only in menu
      1 /*
      2  * Copyright (C) 2017 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.tv.menu;
     18 
     19 import android.content.Context;
     20 import android.content.res.TypedArray;
     21 import android.graphics.Canvas;
     22 import android.graphics.Rect;
     23 import android.graphics.drawable.Drawable;
     24 import android.graphics.drawable.LayerDrawable;
     25 import android.util.AttributeSet;
     26 import android.view.View;
     27 import com.android.tv.R;
     28 
     29 /** A progress bar control which has two progresses which start in the middle of the control. */
     30 public class PlaybackProgressBar extends View {
     31     private final LayerDrawable mProgressDrawable;
     32     private final Drawable mPrimaryDrawable;
     33     private final Drawable mSecondaryDrawable;
     34     private long mMax = 100;
     35     private long mProgressStart = 0;
     36     private long mProgressEnd = 0;
     37     private long mProgress = 0;
     38 
     39     public PlaybackProgressBar(Context context) {
     40         this(context, null);
     41     }
     42 
     43     public PlaybackProgressBar(Context context, AttributeSet attrs) {
     44         this(context, attrs, 0);
     45     }
     46 
     47     public PlaybackProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
     48         this(context, attrs, defStyleAttr, 0);
     49     }
     50 
     51     public PlaybackProgressBar(
     52             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     53         super(context, attrs, defStyleAttr, defStyleRes);
     54         TypedArray a =
     55                 context.obtainStyledAttributes(
     56                         attrs, R.styleable.PlaybackProgressBar, defStyleAttr, defStyleRes);
     57         mProgressDrawable =
     58                 (LayerDrawable) a.getDrawable(R.styleable.PlaybackProgressBar_progressDrawable);
     59         mPrimaryDrawable = mProgressDrawable.findDrawableByLayerId(android.R.id.progress);
     60         mSecondaryDrawable =
     61                 mProgressDrawable.findDrawableByLayerId(android.R.id.secondaryProgress);
     62         a.recycle();
     63         refreshProgress();
     64     }
     65 
     66     @Override
     67     protected void onDraw(Canvas canvas) {
     68         final int saveCount = canvas.save();
     69         canvas.translate(getPaddingLeft(), getPaddingTop());
     70         mProgressDrawable.draw(canvas);
     71         canvas.restoreToCount(saveCount);
     72     }
     73 
     74     @Override
     75     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
     76         super.onSizeChanged(w, h, oldw, oldh);
     77         refreshProgress();
     78     }
     79 
     80     public void setMax(long max) {
     81         if (max < 0) {
     82             max = 0;
     83         }
     84         if (max != mMax) {
     85             mMax = max;
     86             if (mProgressStart > max) {
     87                 mProgressStart = max;
     88             }
     89             if (mProgressEnd > max) {
     90                 mProgressEnd = max;
     91             }
     92             if (mProgress > max) {
     93                 mProgress = max;
     94             }
     95             refreshProgress();
     96         }
     97     }
     98 
     99     /** Sets the start and end position of the progress. */
    100     public void setProgressRange(long start, long end) {
    101         start = constrain(start, 0, mMax);
    102         end = constrain(end, start, mMax);
    103         mProgress = constrain(mProgress, start, end);
    104         if (start != mProgressStart || end != mProgressEnd) {
    105             mProgressStart = start;
    106             mProgressEnd = end;
    107             setProgressLevels();
    108         }
    109     }
    110 
    111     /** Sets the progress position. */
    112     public void setProgress(long progress) {
    113         progress = constrain(progress, mProgressStart, mProgressEnd);
    114         if (progress != mProgress) {
    115             mProgress = progress;
    116             setProgressLevels();
    117         }
    118     }
    119 
    120     private long constrain(long value, long min, long max) {
    121         return Math.min(Math.max(value, min), max);
    122     }
    123 
    124     private void refreshProgress() {
    125         int width = getWidth() - getPaddingStart() - getPaddingEnd();
    126         int height = getHeight() - getPaddingTop() - getPaddingBottom();
    127         mProgressDrawable.setBounds(0, 0, width, height);
    128         setProgressLevels();
    129     }
    130 
    131     private void setProgressLevels() {
    132         boolean progressUpdated = setProgressBound(mPrimaryDrawable, mProgressStart, mProgress);
    133         progressUpdated |= setProgressBound(mSecondaryDrawable, mProgress, mProgressEnd);
    134         if (progressUpdated) {
    135             postInvalidate();
    136         }
    137     }
    138 
    139     private boolean setProgressBound(Drawable drawable, long start, long end) {
    140         Rect oldBounds = drawable.getBounds();
    141         if (mMax == 0) {
    142             if (!isEqualRect(oldBounds, 0, 0, 0, 0)) {
    143                 drawable.setBounds(0, 0, 0, 0);
    144                 return true;
    145             }
    146             return false;
    147         }
    148         int width = mProgressDrawable.getBounds().width();
    149         int height = mProgressDrawable.getBounds().height();
    150         int left = (int) (width * start / mMax);
    151         int right = (int) (width * end / mMax);
    152         if (!isEqualRect(oldBounds, left, 0, right, height)) {
    153             drawable.setBounds(left, 0, right, height);
    154             return true;
    155         }
    156         return false;
    157     }
    158 
    159     private boolean isEqualRect(Rect rect, int left, int top, int right, int bottom) {
    160         return rect.left == left && rect.top == top && rect.right == right && rect.bottom == bottom;
    161     }
    162 }
    163