165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/* 265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Copyright (C) 2014 The Android Open Source Project 365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Licensed under the Apache License, Version 2.0 (the "License"); 565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * you may not use this file except in compliance with the License. 665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * You may obtain a copy of the License at 765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * http://www.apache.org/licenses/LICENSE-2.0 965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 1065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Unless required by applicable law or agreed to in writing, software 1165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * distributed under the License is distributed on an "AS IS" BASIS, 1265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * See the License for the specific language governing permissions and 1465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * limitations under the License. 1565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 1665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepackage com.android.tv.settings.device.storage; 1865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.Canvas; 2065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.ColorFilter; 2165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.Paint; 2265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.PixelFormat; 2365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.drawable.Drawable; 2465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Parcel; 2565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Parcelable; 2665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 2765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.ArrayList; 2865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 2965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/** 3065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Draws a horizontal bar chart with colored slices, each represented by 3165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * {@link Entry}. Pulled from Android Settings App. 3265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 3365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepublic class PercentageBarChart extends Drawable { 3465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 3565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static class Entry implements Comparable<Entry>, Parcelable { 3665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 3765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final int order; 3865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final float percentage; 3965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final Paint paint; 4065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public Entry(int order, float percentage, int color) { 4265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this.order = order; 4365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this.percentage = percentage; 4465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this.paint = new Paint(); 4565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this.paint.setColor(color); 4665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this.paint.setStyle(Paint.Style.FILL); 4765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 4865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 5065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int compareTo(Entry another) { 5165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return order - another.order; 5265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 5365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 5565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int describeContents() { 5665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return 0; 5765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 5865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 6065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void writeToParcel(Parcel dest, int flags) { 6165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeInt(order); 6265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeFloat(percentage); 6365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeInt(paint.getColor()); 6465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 6565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 6665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static final Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator<Entry>() { 6765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 6865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public Entry createFromParcel(Parcel in) { 6965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new Entry(in.readInt(), in.readFloat(), in.readInt()); 7065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 7165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 7365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public Entry[] newArray(int size) { 7465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new Entry[size]; 7565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 7665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }; 7765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 7865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final ArrayList<Entry> mEntries; 8065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final int mBackgroundColor; 8165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final int mMinTickWidth; 8265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final int mWidth; 8365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final int mHeight; 8465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final boolean mIsLayoutRtl; 8565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final Paint mEmptyPaint; 8665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public PercentageBarChart(ArrayList<Entry> entries, int backgroundColor, int minTickWidth, 8865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int width, int height, boolean isLayoutRtl) { 8965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane super(); 9065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mEntries = entries; 9165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mBackgroundColor = backgroundColor; 9265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mMinTickWidth = minTickWidth; 9365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mWidth = width; 9465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mHeight = height; 9565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mIsLayoutRtl = isLayoutRtl; 9665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mEmptyPaint = new Paint(); 9765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mEmptyPaint.setColor(backgroundColor); 9865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mEmptyPaint.setStyle(Paint.Style.FILL); 9965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 10165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 10265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int getIntrinsicHeight() { 10365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mHeight; 10465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 10665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 10765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int getIntrinsicWidth() { 10865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mWidth; 10965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 11065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 11265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void draw(Canvas canvas) { 11365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mEmptyPaint.setColor(mBackgroundColor); 11465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float end = (mIsLayoutRtl) ? 0 : mWidth; 11665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float lastX = (mIsLayoutRtl) ? mWidth : 0; 11765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (final Entry e : mEntries) { 11965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (e.percentage == 0.0f) { 12065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane continue; 12165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 12265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 12365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final float entryWidth = Math.max(mMinTickWidth, mWidth * e.percentage); 12465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 12565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // progress toward the end. 12665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final float nextX = lastX + ((lastX < end) ? entryWidth : -entryWidth); 12765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 12865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // if we've hit the limit, stop drawing. 12965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (drawEntry(canvas, lastX, nextX, e.paint)) { 13065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return; 13165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane lastX = nextX; 13365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane drawEntry(canvas, lastX, end, mEmptyPaint); 13665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 13965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void setAlpha(int alpha) { 14065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 14265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 14365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void setColorFilter(ColorFilter cf) { 14465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 14665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 14765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int getOpacity() { 14865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return PixelFormat.OPAQUE; 14965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 15065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 15165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 15265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Draws a rectangle from the lesser of the two x inputs to the greater of 15365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * the two. If either of the two x inputs lie outside the bounds of this 15465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * drawable, limit the rectangle drawn to the bounds. 15565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 15665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * @param canvas the canvas to draw to. 15765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * @param x1 the first x input. This may be greater or smaller than x2. 15865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * @param x2 the second x input. This may be greater or smaller than x1. 15965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * @param paint the color to draw. 16065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * @return true if either of the x inputs was beyond the bounds of this 16165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * drawable, false otherwise. 16265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 16365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private boolean drawEntry(Canvas canvas, float x1, float x2, Paint paint) { 16465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane boolean hitLimit = false; 16565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float left = x1 > x2 ? x2 : x1; 16665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float right = x1 > x2 ? x1 : x2; 16765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (left < 0) { 16865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane left = 0; 16965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane hitLimit = true; 17065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (right > mWidth) { 17265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane right = mWidth; 17365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane hitLimit = true; 17465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane canvas.drawRect(left, 0, right, mHeight, paint); 17665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return hitLimit; 17765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane} 179