2 * Copyright (C) 2012 The CyanogenMod Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.cyanogenmod.filemanager.ui.widgets;
19 import android.content.Context;
20 import android.graphics.*;
21 import android.util.AttributeSet;
22 import android.view.View;
23 import android.widget.Toast;
24 import com.cyanogenmod.filemanager.R;
25 import com.cyanogenmod.filemanager.model.DiskUsage;
26 import com.cyanogenmod.filemanager.model.DiskUsageCategory;
27 import com.cyanogenmod.filemanager.ui.ThemeManager;
28 import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.concurrent.ExecutorService;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.Future;
38 * A class that display graphically the usage of a mount point.
40 public class DiskUsageGraph extends View {
43 * This is a list for accessing the loaded colors
45 public static final List<Integer> COLOR_LIST = new ArrayList<Integer>();
47 * This is an internal color id reference
49 private static final List<Integer> INTERNAL_COLOR_LIST = new ArrayList<Integer>() {
53 add(R.color.material_palette_blue_1);
54 add(R.color.material_palette_blue_2);
55 add(R.color.material_palette_blue_3);
56 add(R.color.material_palette_blue_4);
59 add(R.color.material_palette_green_1);
60 add(R.color.material_palette_green_2);
61 add(R.color.material_palette_green_3);
62 add(R.color.material_palette_green_4);
65 add(R.color.material_palette_orange_1);
66 add(R.color.material_palette_orange_2);
67 add(R.color.material_palette_orange_3);
68 add(R.color.material_palette_orange_4);
71 add(R.color.material_palette_pink_1);
72 add(R.color.material_palette_pink_2);
73 add(R.color.material_palette_pink_3);
74 add(R.color.material_palette_pink_4);
81 * Initialize the color assets into memory for direct access
83 private void initializeColors() {
84 // Only load the colors if needed
85 if (COLOR_LIST.size() == 0) {
86 for (int colorId : INTERNAL_COLOR_LIST) {
87 COLOR_LIST.add(getContext().getResources().getColor(colorId));
95 int mDiskWarningAngle = (360 * 95) / 100;
97 private static String sWarningText;
102 final List<DrawingObject> mDrawingObjects =
103 Collections.synchronizedList(new ArrayList<DiskUsageGraph.DrawingObject>(2));
107 * drawing objects lock
109 static final int[] LOCK = new int[0];
112 * Constructor of <code>DiskUsageGraph</code>.
114 * @param context The current context
116 public DiskUsageGraph(Context context) {
121 * Constructor of <code>DiskUsageGraph</code>.
123 * @param context The current context
124 * @param attrs The attributes of the XML tag that is inflating the view.
126 public DiskUsageGraph(Context context, AttributeSet attrs) {
127 this(context, attrs, 0);
131 * Constructor of <code>DiskUsageGraph</code>.
133 * @param context The current context
134 * @param attrs The attributes of the XML tag that is inflating the view.
135 * @param defStyle The default style to apply to this view. If 0, no style
136 * will be applied (beyond what is included in the theme). This may
137 * either be an attribute resource, whose value will be retrieved
138 * from the current theme, or an explicit style resource.
140 public DiskUsageGraph(Context context, AttributeSet attrs, int defStyle) {
141 super(context, attrs, defStyle);
143 if (sWarningText == null) {
144 sWarningText = context.getResources().getString(R.string.pref_disk_usage_warning_level);
152 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
153 int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
154 int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
155 int size = Math.min(parentWidth, parentHeight);
156 this.setMeasuredDimension(size, size);
160 * Method that sets the free disk space percentage after the widget change his color to advise
163 * @param percentage The free disk space percentage
165 public void setFreeDiskSpaceWarningLevel(int percentage) {
166 this.mDiskWarningAngle = (360 * percentage) / 100;
169 // Handle thread for drawing calculations
170 private Future mAnimationFuture = null;
171 private static ExecutorService sThreadPool = Executors.newFixedThreadPool(1);
174 * Method that draw the disk usage.
176 * @param diskUsage {@link com.cyanogenmod.filemanager.model.DiskUsage} The disk usage params
178 public void drawDiskUsage(DiskUsage diskUsage) {
180 // Clear if a current drawing exit
181 if (mAnimationFuture != null && !mAnimationFuture.isCancelled()) {
182 mAnimationFuture.cancel(true);
186 synchronized (LOCK) {
187 this.mDrawingObjects.clear();
191 // Start drawing thread
192 AnimationDrawingRunnable animationDrawingRunnable = new AnimationDrawingRunnable(diskUsage);
193 mAnimationFuture = sThreadPool.submit(animationDrawingRunnable);
201 protected void onDraw(Canvas canvas) {
203 super.onDraw(canvas);
205 //Draw all the drawing objects
206 synchronized (LOCK) {
207 for (DrawingObject dwo : this.mDrawingObjects) {
208 canvas.drawArc(dwo.mRectF, dwo.mStartAngle, dwo.mSweepAngle, false, dwo.mPaint);
214 * A thread for drawing the animation of the graph.
216 private class AnimationDrawingRunnable implements Runnable {
218 private final DiskUsage mDiskUsage;
220 // Delay in between UI updates and slow down calculations
221 private static final long ANIMATION_DELAY = 1l;
223 // Slop space adjustment for space between segments
224 private static final int SLOP = 2;
227 private static final boolean USE_COLORS = true;
230 * Constructor of <code>AnimationDrawingThread</code>.
232 * @param diskUsage The disk usage
234 public AnimationDrawingRunnable(DiskUsage diskUsage) {
235 this.mDiskUsage = diskUsage;
238 private void sleepyTime() {
240 Thread.sleep(ANIMATION_DELAY);
241 } catch (InterruptedException ignored) {
245 private void redrawCanvas() {
247 post(new Runnable() {
255 private void drawTotal(Rect rect, int stroke) {
257 DrawingObject drawingObject = createDrawingObject(rect, "disk_usage_total_color",
259 synchronized (LOCK) {
260 mDrawingObjects.add(drawingObject);
262 while (drawingObject.mSweepAngle < 360) {
263 drawingObject.mSweepAngle++;
269 private void drawUsed(Rect rect, int stroke, float used) {
271 DrawingObject drawingObject = createDrawingObject(rect, "disk_usage_used_color", stroke);
272 synchronized (LOCK) {
273 mDrawingObjects.add(drawingObject);
275 while (drawingObject.mSweepAngle < used) {
276 drawingObject.mSweepAngle++;
282 private void drawUsedWithColors(Rect rect, int stroke) {
283 // Draw used segments
284 if (mDiskUsage != null) {
285 int lastSweepAngle = 0;
286 float catUsed = 100.0f;
289 for (DiskUsageCategory category : mDiskUsage.getUsageCategoryList()) {
290 catUsed = (category.getSizeBytes() * 100) / mDiskUsage.getTotal(); // calc percent
291 catUsed = (catUsed < 1) ? 1 : catUsed; // Normalize
292 catUsed = (360 * catUsed) / 100; // calc angle
294 // Figure out a color
295 if (index > -1 && index < COLOR_LIST.size()) {
296 color = COLOR_LIST.get(index);
300 color = COLOR_LIST.get(index);
303 DrawingObject drawingObject = createDrawingObjectNoTheme(rect, color, stroke);
304 drawingObject.mStartAngle += lastSweepAngle;
305 synchronized (LOCK) {
306 mDrawingObjects.add(drawingObject);
308 while (drawingObject.mSweepAngle < catUsed + SLOP) {
309 drawingObject.mSweepAngle++;
313 lastSweepAngle += drawingObject.mSweepAngle - SLOP;
323 //Get information about the drawing zone, and adjust the size
324 Rect rect = new Rect();
325 getDrawingRect(rect);
326 int stroke = (rect.width() / 2) / 2;
327 rect.left += stroke / 2;
328 rect.right -= stroke / 2;
329 rect.top += stroke / 2;
330 rect.bottom -= stroke / 2;
333 if (this.mDiskUsage != null && this.mDiskUsage.getTotal() != 0) {
334 used = (this.mDiskUsage.getUsed() * 100) / this.mDiskUsage.getTotal();
337 used = (360 * used) / 100;
339 // Draws out the graph background color
340 drawTotal(rect, stroke);
344 drawUsedWithColors(rect, stroke);
346 drawUsed(rect, stroke, used);
349 if (used >= mDiskWarningAngle) {
350 Toast.makeText(getContext(), sWarningText, Toast.LENGTH_SHORT).show();
356 * Method that creates the drawing object.
358 * @param rect The area of drawing
359 * @param colorResourceThemeId The theme resource identifier of the color
360 * @param stroke The stroke width
362 * @return DrawingObject The drawing object
364 private DrawingObject createDrawingObject(
365 Rect rect, String colorResourceThemeId, int stroke) {
366 DrawingObject out = new DrawingObject();
368 Theme theme = ThemeManager.getCurrentTheme(getContext());
369 out.mPaint.setColor(theme.getColor(getContext(), colorResourceThemeId));
370 out.mPaint.setStrokeWidth(stroke);
371 out.mPaint.setAntiAlias(true);
372 out.mPaint.setStrokeCap(Paint.Cap.BUTT);
373 out.mPaint.setStyle(Paint.Style.STROKE);
374 out.mRectF = new RectF(rect);
379 * Method that creates the drawing object.
381 * @param rect The area of drawing
382 * @param color Integer id of the color
383 * @param stroke The stroke width
385 * @return DrawingObject The drawing object
387 * [TODO][MSB]: Implement colors for sections into theme
390 private DrawingObject createDrawingObjectNoTheme(
391 Rect rect, int color, int stroke) {
392 DrawingObject out = new DrawingObject();
394 out.mPaint.setColor(color);
395 out.mPaint.setStrokeWidth(stroke);
396 out.mPaint.setAntiAlias(true);
397 out.mPaint.setStrokeCap(Paint.Cap.BUTT);
398 out.mPaint.setStyle(Paint.Style.STROKE);
399 out.mRectF = new RectF(rect);
405 * A class with information about a drawing object.
407 private class DrawingObject {
408 DrawingObject() {/**NON BLOCK**/}
410 int mStartAngle = -180;
412 Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
413 RectF mRectF = new RectF();