From 4c42df11dac51e16673dad78c7e8533e62c7c430 Mon Sep 17 00:00:00 2001 From: Viktor Batytskyi Date: Thu, 30 Apr 2015 21:57:43 +0300 Subject: [PATCH] KAA-465: improve design, fix gauge chart scaling issues --- .../powerplant-android/AndroidManifest.xml | 3 +- .../res/drawable-mdpi/drop_shadow_down.xml | 25 ++++ .../res/drawable-mdpi/drop_shadow_right.xml | 25 ++++ .../res/layout/fragment_dashboard.xml | 83 ++++++++++++-- .../powerplant-android/res/values/strings.xml | 2 +- .../powerplant/data/RestDataEndpoint.java | 2 +- .../fragment/DashboardFragment.java | 107 +++++++++++------- .../kaa/demo/powerplant/view/GaugeChart.java | 73 ++++++------ 8 files changed, 223 insertions(+), 97 deletions(-) create mode 100644 examples/powerplant-android/res/drawable-mdpi/drop_shadow_down.xml create mode 100644 examples/powerplant-android/res/drawable-mdpi/drop_shadow_right.xml diff --git a/examples/powerplant-android/AndroidManifest.xml b/examples/powerplant-android/AndroidManifest.xml index 87f7ec0d15..c7fb03243b 100644 --- a/examples/powerplant-android/AndroidManifest.xml +++ b/examples/powerplant-android/AndroidManifest.xml @@ -38,7 +38,8 @@ android:name=".PowerPlantActivity" android:screenOrientation="landscape" android:configChanges="keyboardHidden|orientation|screenSize" - android:label="@string/app_name" > + android:label="@string/app_name" + android:hardwareAccelerated="false"> diff --git a/examples/powerplant-android/res/drawable-mdpi/drop_shadow_down.xml b/examples/powerplant-android/res/drawable-mdpi/drop_shadow_down.xml new file mode 100644 index 0000000000..6d4728fe22 --- /dev/null +++ b/examples/powerplant-android/res/drawable-mdpi/drop_shadow_down.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/examples/powerplant-android/res/drawable-mdpi/drop_shadow_right.xml b/examples/powerplant-android/res/drawable-mdpi/drop_shadow_right.xml new file mode 100644 index 0000000000..fde9c50c0b --- /dev/null +++ b/examples/powerplant-android/res/drawable-mdpi/drop_shadow_right.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/examples/powerplant-android/res/layout/fragment_dashboard.xml b/examples/powerplant-android/res/layout/fragment_dashboard.xml index c86027eba9..112e661a14 100644 --- a/examples/powerplant-android/res/layout/fragment_dashboard.xml +++ b/examples/powerplant-android/res/layout/fragment_dashboard.xml @@ -26,13 +26,12 @@ android:background="#E0E0E0" android:layout_marginTop="10dp"> - - + + + + - + + + + + + + + android:layout_marginLeft="18dp"> - - + + + + + + android:paddingBottom="16dp" + android:paddingRight="2dp"> + + + + + diff --git a/examples/powerplant-android/res/values/strings.xml b/examples/powerplant-android/res/values/strings.xml index d0a585484d..df7d423d4f 100644 --- a/examples/powerplant-android/res/values/strings.xml +++ b/examples/powerplant-android/res/values/strings.xml @@ -18,7 +18,7 @@ - City Guide Demo + Power plant Please wait... diff --git a/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/data/RestDataEndpoint.java b/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/data/RestDataEndpoint.java index a96b67fa8c..d7bfe43d09 100644 --- a/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/data/RestDataEndpoint.java +++ b/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/data/RestDataEndpoint.java @@ -25,7 +25,7 @@ public class RestDataEndpoint extends AbstractDataEndpoint { private static final String TAG = RestDataEndpoint.class.getSimpleName(); - private static final String BASE_URL = "http://10.2.2.89:10000/api/data"; + private static final String BASE_URL = "http://192.168.13.100:10000/api/data"; private static final String LATEST_URL = BASE_URL + "/latest"; @Override diff --git a/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/fragment/DashboardFragment.java b/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/fragment/DashboardFragment.java index a2d2d6f2a0..b899358940 100644 --- a/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/fragment/DashboardFragment.java +++ b/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/fragment/DashboardFragment.java @@ -18,12 +18,13 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import lecho.lib.hellocharts.formatter.AxisValueFormatter; import lecho.lib.hellocharts.model.Axis; @@ -40,24 +41,22 @@ import org.kaaproject.kaa.demo.powerplant.R; import org.kaaproject.kaa.demo.powerplant.data.DataEndpoint; import org.kaaproject.kaa.demo.powerplant.data.FakeDataEndpoint; -import org.kaaproject.kaa.demo.powerplant.data.RestDataEndpoint; import org.kaaproject.kaa.demo.powerplant.pojo.DataPoint; import org.kaaproject.kaa.demo.powerplant.pojo.DataReport; import org.kaaproject.kaa.demo.powerplant.view.GaugeChart; import android.app.Activity; import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Typeface; import android.os.Bundle; import android.support.v4.app.Fragment; import android.text.Html; +import android.text.Spanned; +import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.EditText; import android.widget.TextView; /** @@ -67,7 +66,6 @@ */ public class DashboardFragment extends Fragment { private static final String EMPTY_STRING = ""; - private static final String LOG_BOX_TEXT = "logBoxText"; private static final String TAG = DashboardFragment.class.getSimpleName(); @@ -97,7 +95,13 @@ public class DashboardFragment extends Fragment { private static final int LINE_CHART_AXIS_COLOR = Color.parseColor("#85919F"); private static final int LINE_CHART_AXIS_TEXT_SIZE = 22; private static final int LINE_CHART_AXIS_TEXT_COLOR = Color.parseColor("#B7B7B8"); - private int times = 0; + private static final int MAX_LOGS_TO_SAVE = 20; + private static final String OUTAGE_LOG_COLOR = "red"; + private static final String BACK_TO_NORMAL_LOG_COLOR = "#009d5d"; + private static final String OUTAGE_LOG_TAG = "[WARN]"; + private static final String BACK_TO_NORMAL_LOG_TAG = "[INFO]"; + private static final String OUTAGE_LOG_TEXT = "voltage outage detected"; + private static final String BACK_TO_NORMAL_LOG_TEXT = "voltage is back to normal"; protected PowerPlantActivity mActivity; private LineChartView lineChart; @@ -109,7 +113,9 @@ public class DashboardFragment extends Fragment { private final boolean[] isPanelsOutage = new boolean[NUM_PANELS]; private TextView logBox; private LinkedList savedLogs = new LinkedList<>(); - + private StringBuilder curLogString = new StringBuilder(); + private ExecutorService executor = Executors.newSingleThreadExecutor(); + private Line line; private DataEndpoint endpoint; @@ -135,6 +141,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa gaugeCharts.add((GaugeChart) rootView.findViewById(R.id.gaugeChart22)); gaugeCharts.add((GaugeChart) rootView.findViewById(R.id.gaugeChart23)); logBox = (TextView) rootView.findViewById(R.id.logBox); + logBox.setMovementMethod(new ScrollingMovementMethod()); Thread updateThread = new Thread(new Runnable() { @@ -195,7 +202,6 @@ public void run() { PieChartData data = pieChart.getPieChartData(); float plantVoltage = 0.0f; - Log.d(TAG, "Now it's " + (times + 1) + "th repetition"); int counter = 0; for (DataPoint dp : latestData.getDataPoints()) { plantVoltage += dp.getVoltage(); @@ -205,13 +211,11 @@ public void run() { showLogIfNeeded(counter, dp.getVoltage()); // sliceValue.setLabel(String.format(PIE_CHART_VALUE_FORMAT, // dp.getVoltage())); - Log.d(TAG, "Panel #" + (counter + 1) + ", voltage: " + dp.getVoltage()); counter++; } - times++; float gridVoltage = latestData.getPowerConsumption() - plantVoltage; - SliceValue gridValue = data.getValues().get(NUM_PANELS).setTarget(gridVoltage); +// SliceValue gridValue = data.getValues().get(NUM_PANELS).setTarget(gridVoltage); // gridValue.setLabel(String.format(PIE_CHART_VALUE_FORMAT, gridVoltage)); pieChart.startDataAnimation(UPDATE_PERIOD / 2); updateLabels(plantVoltage, gridVoltage); @@ -418,37 +422,58 @@ private void showLogIfNeeded(int panelIndex, double curVoltage) { } } - private void prependToLogBox(final boolean isOutage, final int panelIndex) { - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - Calendar cal = Calendar.getInstance(); - SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss a "); - String log; - if (isOutage) { - log = "" + sdf.format(cal.getTime()) + " [WARN] Panel " + - (panelIndex + 1) + " voltage outage detected"; - } else { - log = "" + sdf.format(cal.getTime()) + " [INFO] Panel " + - (panelIndex + 1) + " voltage is back to normal"; - } - - if (savedLogs.size() > 30) { - savedLogs.removeLast(); - } - savedLogs.addFirst(log); - - logBox.setText(Html.fromHtml(getLogString())); - } - }); + private void prependToLogBox(boolean isOutage, int panelIndex) { + executor.execute(new UpdateLogBoxThread(isOutage, panelIndex)); + } + + private String generateLogString(boolean isOutage, int panelIndex) { + Calendar cal = Calendar.getInstance(); + SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss a "); + String logColor; + String logTag; + String logText; + + if (isOutage) { + logColor = OUTAGE_LOG_COLOR; + logTag = OUTAGE_LOG_TAG; + logText = OUTAGE_LOG_TEXT; + } else { + logColor = BACK_TO_NORMAL_LOG_COLOR; + logTag = BACK_TO_NORMAL_LOG_TAG; + logText = BACK_TO_NORMAL_LOG_TEXT; + } + + return String.format(" %s %s Panel %d %s
", logColor, + sdf.format(cal.getTime()), logTag, panelIndex + 1, logText); } - private String getLogString() { - StringBuilder res = new StringBuilder(); - for (String log : savedLogs) { - res.append(log); - res.append("\n"); + private class UpdateLogBoxThread extends Thread { + private boolean isOutage; + private int panelIndex; + + public UpdateLogBoxThread(boolean isOutage, int panelIndex) { + this.isOutage = isOutage; + this.panelIndex = panelIndex; + } + + public void run() { + String log = generateLogString(isOutage, panelIndex); + if (savedLogs.size() > MAX_LOGS_TO_SAVE) { + String last = savedLogs.removeLast(); + curLogString.delete(curLogString.length() - last.length(), curLogString.length()); + } + savedLogs.addFirst(log); + curLogString.insert(0, log); + + final Spanned coloredLog = Html.fromHtml(log); + + mActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + logBox.append(coloredLog); +// logBox.setText(Html.fromHtml(curLogString.toString())); + } + }); } - return res.toString(); } } diff --git a/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/view/GaugeChart.java b/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/view/GaugeChart.java index 3a3b8816ad..ad8005e293 100644 --- a/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/view/GaugeChart.java +++ b/examples/powerplant-android/src/org/kaaproject/kaa/demo/powerplant/view/GaugeChart.java @@ -1,13 +1,14 @@ package org.kaaproject.kaa.demo.powerplant.view; import org.kaaproject.kaa.demo.powerplant.R; - +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Paint.Style; import android.graphics.Path; import android.graphics.RectF; import android.graphics.Shader; @@ -15,6 +16,8 @@ import android.graphics.Typeface; import android.os.Bundle; import android.os.Parcelable; +import android.text.Layout; +import android.text.TextPaint; import android.util.AttributeSet; import android.util.Log; import android.view.View; @@ -47,7 +50,6 @@ public class GaugeChart extends View { private Paint facePaint; // scale - private static final float SCALE_POSITION = 0.045f; private static final float SCALE_LINE_POSITION = 0.1f; private static final float SCALE_LINE_WIDTH = 0.062f; private static final float SCALE_FONT_SIZE = 0.07f; @@ -72,12 +74,10 @@ public class GaugeChart extends View { private static final float POWER_LABEL_POS_Y = 0.45f; private static final float PANEL_NAME_LABEL_POS_Y = 0.75f; private static final float MEASURES_LABEL_POS_Y = 0.65f; - private static final float MAGIC_LABEL_ALIGN_COEFF = 5f; - private static final float MAGIC_MEASURE_ALIGN_COEFF = 3f; private String panelName; private Paint textPaint; - private Paint labelPaint; - private Paint measuresPaint; + private TextPaint labelPaint; + private TextPaint measuresPaint; // hand private static final float HAND_CIRCLE_RADIUS = 0.01f; @@ -87,7 +87,6 @@ public class GaugeChart extends View { private Paint handScrewPaint; // physics - private static final float VELOCITY_BARRIER = 90.0f; private float handleAccelerationCoef = 3f; private boolean isHandInitialized = false; private float handTarget = CENTER_POWER; @@ -100,6 +99,7 @@ public class GaugeChart extends View { public GaugeChart(Context context) { super(context); + setLayerType(View.LAYER_TYPE_SOFTWARE, null); init(); } @@ -113,16 +113,18 @@ public GaugeChart(Context context, AttributeSet attrs) { try { panelName = a.getString(R.styleable.GaugeChart_panel_name); handleAccelerationCoef = a.getFloat(R.styleable.GaugeChart_update_time_s, 1.0f); - handleAccelerationCoef *= 0.9; + handleAccelerationCoef *= 1.2; } finally { a.recycle(); } + setLayerType(View.LAYER_TYPE_SOFTWARE, null); init(); Log.d(TAG, panelName + " has initialized"); } public GaugeChart(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + setLayerType(View.LAYER_TYPE_SOFTWARE, null); init(); } @@ -163,6 +165,14 @@ private void regenerateBackground() { background = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas backgroundCanvas = new Canvas(background); + + + Paint paint = new Paint(); + paint.setColor(Color.WHITE); + paint.setStyle(Style.FILL); + backgroundCanvas.drawPaint(paint); + + float scale = (float) getWidth(); backgroundCanvas.scale(scale, scale); @@ -298,6 +308,7 @@ private void initDrawingTools() { handPaint.setAntiAlias(true); handPaint.setColor(HAND_COLOR); handPaint.setStyle(Paint.Style.FILL); + handPaint.setPathEffect(null); handPath = new Path(); handPath.moveTo(CENTER_X, CENTER_Y + 0.05f); @@ -307,27 +318,29 @@ private void initDrawingTools() { handPath.lineTo(CENTER_X + 0.010f, CENTER_Y + 0.05f - 0.007f); handPath.lineTo(CENTER_X, CENTER_Y + 0.05f); handPath.addCircle(CENTER_X, CENTER_Y, 0.02f, Path.Direction.CW); + handPath.close(); handScrewPaint = new Paint(); handScrewPaint.setAntiAlias(true); handScrewPaint.setColor(0xff493f3c); handScrewPaint.setStyle(Paint.Style.FILL); - labelPaint = new Paint(); + labelPaint = new TextPaint(); labelPaint.setAntiAlias(true); labelPaint.setColor(TEXT_COLOR); labelPaint.setTextSize(TEXT_FONT_SIZE); labelPaint.setTypeface(Typeface.SANS_SERIF); - labelPaint.setTextAlign(Paint.Align.LEFT); + labelPaint.setTextAlign(Paint.Align.CENTER); labelPaint.setLinearText(true); // measures (x.y kW) - measuresPaint = new Paint(); - measuresPaint.setAntiAlias(true); + measuresPaint = new TextPaint(); measuresPaint.setColor(TEXT_COLOR); + measuresPaint.setAntiAlias(true); + measuresPaint.setStyle(Style.FILL); measuresPaint.setTextSize(TEXT_MEASURE_FONT_SIZE); measuresPaint.setTypeface(Typeface.SANS_SERIF); - measuresPaint.setTextAlign(Paint.Align.LEFT); + measuresPaint.setTextAlign(Paint.Align.CENTER); measuresPaint.setLinearText(true); } @@ -345,10 +358,10 @@ private void drawFace(Canvas canvas) { } private void drawLabels(Canvas canvas) { - drawFullText(canvas, POWER_LABEL, CENTER_X - getSpacedTextWidth(labelPaint, POWER_LABEL, MAGIC_LABEL_ALIGN_COEFF) / - 2, POWER_LABEL_POS_Y, labelPaint, MAGIC_LABEL_ALIGN_COEFF); - drawFullText(canvas, panelName, CENTER_X - getSpacedTextWidth(labelPaint, panelName, MAGIC_LABEL_ALIGN_COEFF) / - 2, PANEL_NAME_LABEL_POS_Y, labelPaint, MAGIC_LABEL_ALIGN_COEFF); + Log.d(TAG, labelPaint.measureText(POWER_LABEL) + ""); +// canvas.drawText(POWER_LABEL, CENTER_X - Layout.getDesiredWidth(POWER_LABEL, labelPaint) / 2, + canvas.drawText(POWER_LABEL, CENTER_X, POWER_LABEL_POS_Y, labelPaint); + canvas.drawText(panelName, CENTER_X, PANEL_NAME_LABEL_POS_Y, labelPaint); } @Override @@ -416,11 +429,11 @@ private void drawHand(Canvas canvas) { } } + @SuppressLint("DefaultLocale") private void drawMeasures(Canvas canvas) { if (isHandInitialized) { String measures = String.format("%2.1f kW", handPosition); - drawFullText(canvas, measures, CENTER_X - getSpacedTextWidth(measuresPaint, measures, MAGIC_MEASURE_ALIGN_COEFF) / 2, - MEASURES_LABEL_POS_Y, measuresPaint, MAGIC_MEASURE_ALIGN_COEFF); + canvas.drawText(measures, CENTER_X, MEASURES_LABEL_POS_Y, measuresPaint); } } @@ -439,18 +452,10 @@ private void moveHand() { prevHandTarget = handTarget; } -/* if (panelName.equals("Panel 6")) { - Log.d(TAG, "handVelocity: " + handVelocity + "handAcceleration: " + handAcceleration + - ", delta: " + delta + ", handPosition: " + handPosition); - }*/ handPosition += handVelocity * delta + handAcceleration * delta * delta / 2; handVelocity += handAcceleration * delta; float curDistance = Math.abs(handTarget - handPosition); -/* if (panelName.equals("Panel 6")) { - Log.d(TAG, "handTarget: " + handTarget + ", handPosition: " + handPosition + - ", prevDistance: " + prevDistance + ", cur distance: " + curDistance); - }*/ if (curDistance >= prevDistance) { handPosition = handTarget; handVelocity = ZERO; @@ -487,18 +492,4 @@ private float degreeToAngle(float degree) { private boolean handNeedsToMove() { return Math.abs(handPosition - handTarget) > EPS; } - - private void drawFullText(Canvas canvas, String text, float left, float top, Paint paint, float magicCoef) { - float currentLeft = left; - - for (int i = 0; i < text.length(); i++) { - String c = String.valueOf(text.charAt(i)); - canvas.drawText(c, currentLeft, top, paint); - currentLeft += (paint.measureText(c) / getWidth() / magicCoef); - } - } - - private float getSpacedTextWidth(Paint paint, String text, float magicCoef) { - return paint.measureText(text) / getWidth() / magicCoef; - } }