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