package com.samknows.ui2.activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Typeface; import android.util.AttributeSet; import android.view.View; import com.samknows.libcore.SKPorting; import com.samknows.libcore.R; import com.samknows.libcore.SKTypeface; import com.samknows.measurement.SKApplication; import com.samknows.libcore.SKAndroidUI; /** * This class is responsible for painting the gauge in the home screen. * <p/> * All rights reserved SamKnows * * @author pablo@samknows.com */ class GaugeView extends View { // *** CONSTANTS *** // private static final int TEST_NO_TEST = -1; private static final int TEST_DOWNLOAD = 0; private static final int TEST_UPLOAD = 1; private static final int TEST_LATENCY_LOSS = 2; // *** VARIABLES *** // private int kindOfTest = TEST_NO_TEST; private float textHeight, textOffset; private double result; // UI elements private Typeface robotoCondensedTypeface = null; // Classes private Paint drawPaint, textPaint; // Other stuff private final Context mContext; // *** CONSTRUCTOR *** // public GaugeView(Context context, AttributeSet attributeSet) { super(context, attributeSet); mContext = context; setUpResources(); } // *** CUSTOM METHODS *** // /** * Create, bind and set up the resources (fonts, paints...) */ private void setUpResources() { // Set up the fonts View view = this; // findViewById(android.R.id.content); SKTypeface.sChangeChildrenToDefaultFontTypeface(view); // The createFromAsset call will fail in Edit mode in Eclipse! if (isInEditMode() == false) { robotoCondensedTypeface = SKTypeface.sGetTypefaceWithPathInAssets("fonts/roboto_condensed_regular.ttf"); } // Draw Paint drawPaint = new Paint(); drawPaint.setStyle(Paint.Style.STROKE); drawPaint.setStrokeWidth(SKAndroidUI.sConvertDpToPixels(10, mContext)); drawPaint.setColor(mContext.getResources().getColor(R.color.white)); drawPaint.setAntiAlias(true); // Text Paint textPaint = new Paint(); textPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.text_size_large)); textPaint.setTextAlign(Paint.Align.CENTER); if (robotoCondensedTypeface != null) { textPaint.setTypeface(robotoCondensedTypeface); } textPaint.setColor(mContext.getResources().getColor(R.color.MainColourDialInnerLabelText)); // This let us centre vertically the text textHeight = textPaint.descent() - textPaint.ascent(); textOffset = (textHeight / 2) - textPaint.descent(); } /** * Set the main gauge measurement value field * * @param pResult is the value to be shown in the gauge */ public void setAngleByValue(Double value) { this.result = value; invalidate(); } /** * Set the kind of test. 0 is download. 1 is upload. 2 is latency / packet loss / jitter * * @param pKindOfTest */ public void setKindOfTest(int pKindOfTest) { this.kindOfTest = pKindOfTest; invalidate(); } private String getLabelForValue(double doubleValue) { double fractionalPart = doubleValue - (double) ((int) doubleValue); if (fractionalPart > 0.4) { // Something like 0.5, 1.5 etc. return String.format("%.1f", doubleValue); } else { return String.valueOf((int) doubleValue); } } // *** ONDRAW METHOD *** // @Override protected void onDraw(Canvas canvas) { double angleForDots; float radius, smallCircleCenterX, smallCircleCenterY; super.onDraw(canvas); // Calculate the centre of the current canvas RectF bounds = new RectF(canvas.getClipBounds()); float centerX = bounds.centerX(); float centerY = bounds.centerY(); // The radius will be the shorter rectangle edge to make the draw fit in the rectangle //Log.d("Pixels to DP", String.valueOf(convertPixelsToDp(50, mContext))); //Log.d("DP to Pixels", String.valueOf(convertDpToPixel(17, mContext))); //radius = Math.min(bounds.width() / 2, bounds.height() / 2) - 50; radius = Math.min(bounds.width() / 2, bounds.height() / 2) - SKAndroidUI.sConvertDpToPixels(17, mContext); //double arrSegmentMaxValues_Download[] = {1.0, 2.0, 5.0, 10.0, 30.0, 100.0}; //double arrSegmentMaxValues_Upload[] = {0.5, 1.0, 1.5, 2.0, 10.0, 50.0}; double arrSegmentMaxValues_Download[] = SKApplication.sGetDownloadSixSegmentMaxValues(); double arrSegmentMaxValues_Upload[] = SKApplication.sGetUploadSixSegmentMaxValues(); double arrSegmentMaxValues[] = arrSegmentMaxValues_Download; switch (this.kindOfTest) { case TEST_DOWNLOAD: break; case TEST_UPLOAD: arrSegmentMaxValues = arrSegmentMaxValues_Upload; break; case TEST_LATENCY_LOSS: { double arrSegmentMaxValues_LatencyLoss[] = {100.0, 200.0, 300.0, 400.0, 500.0, 600.0}; arrSegmentMaxValues = arrSegmentMaxValues_LatencyLoss; } break; default: break; } // Loop drawing the elements // We start in the red zone. // Once the ticks represent a value > than the measured value, we go to the grey zone. boolean bGoneToGreyZone = false; for (int i = 0; i <= 60; i++) { switch (this.kindOfTest) { case TEST_DOWNLOAD: case TEST_UPLOAD: case TEST_LATENCY_LOSS: { // Which segment are we rendering? int segmentIndex = i / 10; if (segmentIndex >= 6) { segmentIndex = 5; } // What colour is this tick? if (bGoneToGreyZone == true) { // Already in the grey zone. } else { // Red - but potentially, moving to grey... double segmentStartValue = 0.0; if (segmentIndex > 0) { segmentStartValue = arrSegmentMaxValues[segmentIndex - 1]; } if (segmentStartValue >= this.result) { // This segment starts with a value greater than our measured value. Draw as grey! bGoneToGreyZone = true; } else { double segmentMaxValue = arrSegmentMaxValues[segmentIndex]; if (segmentMaxValue <= this.result) { // Stay red... } else { double fractionalPositionInIndex0To1 = ((this.result - segmentStartValue) / (segmentMaxValue - segmentStartValue)); if (fractionalPositionInIndex0To1 < 0) { SKPorting.sAssert(getClass(), false); fractionalPositionInIndex0To1 = 0; } else if (fractionalPositionInIndex0To1 > 1.0F) { SKPorting.sAssert(getClass(), false); fractionalPositionInIndex0To1 = 1.0F; } int fractionalPositionInIndex0To10 = (int) (fractionalPositionInIndex0To1 * 10.0); if ((i % 10) > fractionalPositionInIndex0To10) { // Grey! bGoneToGreyZone = true; } } } } if (bGoneToGreyZone == true) { drawPaint.setColor(mContext.getResources().getColor(R.color.MainColourDialArcGreyZone)); } else { drawPaint.setColor(mContext.getResources().getColor(R.color.MainColourDialArcRedZone)); } } break; default: // For other tests, we always draw simple grey - we don't have a red zone. drawPaint.setColor(mContext.getResources().getColor(R.color.MainColourDialArcGreyZone)); break; } //Draw outer arcs canvas.drawArc(new RectF(centerX - radius - SKAndroidUI.sConvertDpToPixels(10, mContext), centerY - radius - SKAndroidUI.sConvertDpToPixels(10, mContext), centerX + radius + SKAndroidUI.sConvertDpToPixels(10, mContext), centerY + radius + SKAndroidUI.sConvertDpToPixels(10, mContext)), 135 + (float) (i * (360.0 / 80) - 360.0 / 160 + 360.0 / 800), (float) ((360.0 / 80) - 360.0 / 400), false, drawPaint); // Draw the inner arcs which mark the six segments... and any associated labels... if (i % 10 == 0) { SKPorting.sAssert(getClass(), i >= 0 && i <= 60); SKPorting.sAssert(getClass(), ((i % 10) == 0)); // // Inner arcs... // angleForDots = 1.75 * Math.PI - i * (Math.PI / 40); // Calculate circles position smallCircleCenterX = (float) (centerX + (radius - SKAndroidUI.sConvertDpToPixels(20, mContext)) * Math.sin(angleForDots)); smallCircleCenterY = (float) (centerY + (radius - SKAndroidUI.sConvertDpToPixels(20, mContext)) * Math.cos(angleForDots)); drawPaint.setColor(mContext.getResources().getColor(R.color.MainColourDialInnerTicks)); //Draw small arcs canvas.drawArc(new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius), 135 + (float) (i * (360.0 / 80) - 360.0 / 160 + 360.0 / 800), (float) ((360.0 / 80) - 360.0 / 400), false, drawPaint); // // Draw labels associated with the inner arcs - if required! // switch (kindOfTest) { case TEST_DOWNLOAD: case TEST_UPLOAD: case TEST_LATENCY_LOSS: switch (i) { case 0: canvas.drawText("0", smallCircleCenterX, smallCircleCenterY + textOffset, textPaint); break; default: canvas.drawText(getLabelForValue(arrSegmentMaxValues[(i - 10) / 10]), smallCircleCenterX, smallCircleCenterY + textOffset, textPaint); break; } break; case TEST_NO_TEST: canvas.drawText("", smallCircleCenterX, smallCircleCenterY + textOffset, textPaint); break; default: break; } } } } }