Java tutorial
/******************************************************************************* * Copyright 2013-2015 alladin-IT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package at.alladin.rmbt.android.views; import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.content.res.Configuration; import android.graphics.Color; import android.os.Bundle; import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.ScrollView; import at.alladin.rmbt.android.graphview.CustomizableGraphView; import at.alladin.rmbt.android.graphview.GraphService; import at.alladin.rmbt.android.graphview.GraphView; import at.alladin.rmbt.android.graphview.GraphView.GraphLabel; import at.alladin.rmbt.android.main.RMBTMainActivity; import at.alladin.rmbt.android.test.RMBTTestFragment; import at.alladin.rmbt.android.test.SmoothGraph; import at.alladin.rmbt.android.test.StaticGraph; import at.alladin.rmbt.android.util.CheckTestResultDetailTask; import at.alladin.rmbt.android.util.EndTaskListener; import at.alladin.rmbt.android.util.InformationCollector; import at.alladin.rmbt.android.util.net.NetworkUtil; import at.alladin.rmbt.android.util.net.NetworkUtil.MinMax; import at.alladin.rmbt.android.views.ResultDetailsView.ResultDetailType; import at.alladin.rmbt.client.helper.IntermediateResult; import at.alladin.openrmbt.android.R; public class ResultGraphView extends ScrollView implements EndTaskListener { public final static List<GraphLabel> SPEED_LABELS; static { SPEED_LABELS = new ArrayList<GraphView.GraphLabel>(); SPEED_LABELS.add(new GraphLabel("0.0", "#C800f940")); SPEED_LABELS.add(new GraphLabel("0.1", "#C800f940")); SPEED_LABELS.add(new GraphLabel("1.0", "#C800f940")); SPEED_LABELS.add(new GraphLabel("10", "#C800f940")); SPEED_LABELS.add(new GraphLabel("100", "#C800f940")); } private View view; //private static final String DEBUG_TAG = "ResultGraphView"; public final static String COLOR_SIGNAL_3G = "#ffe000"; public final static String COLOR_SIGNAL_4G = "#40a0f8"; public final static String COLOR_SIGNAL_WLAN = "#f8a000"; public final static String SIGNAL_COLOR_MARKER = "#cccccc"; public final static String COLOR_UL_GRAPH = "#81c1dc"; public final static String COLOR_DL_GRAPH = "#31d13c"; public static final String ARG_UID = "uid"; private RMBTMainActivity activity; private String uid; private String openTestUid; private JSONArray testResult; private EndTaskListener resultFetchEndTaskListener; private CheckTestResultDetailTask testResultOpenDataTask; private JSONArray uploadArray; private JSONArray downloadArray; private JSONArray signalArray; private CustomizableGraphView signalGraph; private CustomizableGraphView ulGraph; private CustomizableGraphView dlGraph; private ProgressBar dlProgress; private ProgressBar ulProgress; private ProgressBar signalProgress; /** * * @param context */ public ResultGraphView(Context context, RMBTMainActivity activity, String uid, String openTestUid, JSONArray testResult, ViewGroup vg) { this(context, null, activity, uid, openTestUid, testResult, vg); } /** * * @param context * @param attrs */ public ResultGraphView(Context context, AttributeSet attrs, RMBTMainActivity activity, String uid, String openTestUid, JSONArray testResult, ViewGroup vg) { super(context, attrs); setFillViewport(true); this.activity = activity; this.uid = uid; this.openTestUid = openTestUid; this.testResult = testResult; createView(vg); } /** * * @param openTestUid */ public void setOpenTestUuid(String openTestUid) { this.openTestUid = openTestUid; } public void initialize(EndTaskListener resultFetchEndTaskListener) { this.resultFetchEndTaskListener = resultFetchEndTaskListener; if ((testResultOpenDataTask == null || testResultOpenDataTask != null || testResultOpenDataTask.isCancelled()) && uid != null) { if (this.testResult != null) { System.out.println("TESTRESULT found GraphView"); taskEnded(this.testResult); } else { System.out.println("TESTRESULT NOT found GraphView"); System.out.println("initializing ResultGraphView"); testResultOpenDataTask = new CheckTestResultDetailTask(activity, ResultDetailType.OPENDATA); testResultOpenDataTask.setEndTaskListener(this); testResultOpenDataTask.execute(uid, openTestUid); } } } /** * * @param inflater * @return */ public View createView(ViewGroup vg) { final LayoutInflater inflater = (LayoutInflater) vg.getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); try { //view = inflater.inflate(R.layout.result_graph, vg, false); view = inflater.inflate(R.layout.result_graph, this); signalGraph = (CustomizableGraphView) view.findViewById(R.id.graph_signal); ulGraph = (CustomizableGraphView) view.findViewById(R.id.graph_upload); ulGraph.setShowLog10Lines(false); dlGraph = (CustomizableGraphView) view.findViewById(R.id.graph_download); dlGraph.setShowLog10Lines(false); signalProgress = (ProgressBar) view.findViewById(R.id.signal_progress); ulProgress = (ProgressBar) view.findViewById(R.id.upload_progress); dlProgress = (ProgressBar) view.findViewById(R.id.download_progress); } catch (Exception e) { e.printStackTrace(); } return view; } /** * * @return */ public View getView() { return view; } // @Override // protected void onDraw(Canvas canvas) { // super.onDraw(canvas); // // if (view == null) { // Log.d("ResultGraphView", "ONDRAW"); // //removeAllViews(); // createView(); // // taskEnded(testResult); // } // } @Override public void taskEnded(JSONArray result) { //addView(view); if (result != null) { testResult = result; } if (view == null || result == null) { return; } if (resultFetchEndTaskListener != null) { resultFetchEndTaskListener.taskEnded(result); } if (testResult != null) { redraw(testResult); } } public void refresh(JSONArray result) { this.testResult = result; redraw(result); } private void redraw(JSONArray result) { try { JSONObject curve = result.getJSONObject(0).getJSONObject("speed_curve"); if (curve != null) { uploadArray = curve.getJSONArray("upload"); downloadArray = curve.getJSONArray("download"); signalArray = curve.getJSONArray("signal"); } //System.out.println(signalArray); long maxTimeUpload = result.getJSONObject(0).optLong("time_ul_ms") + result.getJSONObject(0).optLong("duration_upload_ms"); long timeElapsed = Math.round((double) maxTimeUpload / 1000); if (signalGraph != null && signalArray != null && signalArray.length() > 0 && signalGraph.getGraphs().size() < 1) { Log.d("ResultGraphView", "DRAWING SIGNAL GRAPH\n" + signalArray); final long maxTimeSignal = signalArray.optJSONObject(signalArray.length() - 1) .optLong("time_elapsed"); final long timeElapsedMs = Math.max(maxTimeSignal, maxTimeUpload); timeElapsed = Math.round((double) timeElapsedMs / 1000); signalGraph.getLabelHMaxList().clear(); signalGraph.addLabelHMax(String.valueOf(timeElapsed < 7 ? 7 : timeElapsed)); signalGraph.updateGrid((int) timeElapsed, 4); /* [{"network_type":"WLAN","time_elapsed":0,"signal_strength":-56}, * {"network_type":"WLAN","time_elapsed":10121,"signal_strength":-55}, * {"network_type":"WLAN","time_elapsed":37478,"signal_strength":-57}] */ MinMax<Integer> signalBoundsRsrp = NetworkUtil .getSignalStrengthBounds(InformationCollector.SINGAL_TYPE_RSRP); MinMax<Integer> signalBoundsWlan = NetworkUtil .getSignalStrengthBounds(InformationCollector.SINGAL_TYPE_WLAN); MinMax<Integer> signalBoundsMobile = NetworkUtil .getSignalStrengthBounds(InformationCollector.SINGAL_TYPE_MOBILE); List<GraphService> signalList = new ArrayList<GraphService>(); boolean has4G = false; boolean has3G = false; boolean hasWlan = false; String lastNetworkType = ""; String lastCatTechnology = ""; GraphService curGraph = null; double prevValue = 0d; boolean hasSignalCategoryChanged = false; double lastLabelYPosition = -1d; double time = 0d; double signalChangeStartTime = 0d; double value = 0d; double oldValidValue = 0d; System.out.println("MAXTIME: " + timeElapsedMs); for (int i = 0; i < signalArray.length(); i++) { JSONObject signalObject = signalArray.getJSONObject(i); String networkType = signalObject.optString("network_type"); String catTechnology = signalObject.optString("cat_technology"); //set proper signal strength attribute String signalAttribute = "signal_strength"; String signalColor = "#ffffff"; time = i > 0 ? ((double) signalObject.getInt("time_elapsed") / (double) timeElapsedMs) : 0d; oldValidValue = value > 0d ? value : oldValidValue; if ("LTE".equals(networkType)) { if (!lastNetworkType.equals(networkType) && !lastCatTechnology.equals(catTechnology)) { if (curGraph != null) { curGraph.addValue((1 - prevValue), time); } GraphService newGraph = StaticGraph.addGraph(signalGraph, Color.parseColor(COLOR_SIGNAL_4G), signalArray.length() == 1 ? true : false); signalList.add(newGraph); if (curGraph != null) { curGraph.addValue((1 - prevValue), time); } signalChangeStartTime = time; hasSignalCategoryChanged = true; curGraph = newGraph; } has4G = true; signalAttribute = "lte_rsrp"; signalColor = COLOR_SIGNAL_4G; value = getRelativeSignal(signalBoundsRsrp, signalAttribute, signalObject); } else if ("WLAN".equals(networkType)) { if (!lastNetworkType.equals(networkType) && !lastCatTechnology.equals(catTechnology)) { if (curGraph != null) { curGraph.addValue((1 - prevValue), time); } GraphService newGraph = StaticGraph.addGraph(signalGraph, Color.parseColor(COLOR_SIGNAL_WLAN), signalArray.length() == 1 ? true : false); signalList.add(newGraph); if (curGraph != null) { curGraph.addValue((1 - prevValue), time); } signalChangeStartTime = time; hasSignalCategoryChanged = true; curGraph = newGraph; } hasWlan = true; signalAttribute = "signal_strength"; signalColor = COLOR_SIGNAL_WLAN; value = getRelativeSignal(signalBoundsWlan, signalAttribute, signalObject); } else { if (!lastNetworkType.equals(networkType)) { signalChangeStartTime = time; hasSignalCategoryChanged = true; if (curGraph != null) { curGraph.addValue((1 - prevValue), time); } if ((!lastCatTechnology.equals(catTechnology)) && ("4G".equals(lastCatTechnology) || "WLAN".equals(lastCatTechnology) || "".equals(lastCatTechnology))) { GraphService newGraph = StaticGraph.addGraph(signalGraph, Color.parseColor(COLOR_SIGNAL_3G), signalArray.length() == 1 ? true : false); signalList.add(newGraph); if (curGraph != null) { curGraph.addValue((1 - prevValue), time); } curGraph = newGraph; } } has3G = true; signalAttribute = "signal_strength"; signalColor = COLOR_SIGNAL_3G; value = getRelativeSignal(signalBoundsMobile, signalAttribute, signalObject); } if (value > 0d) { System.out.println("SIGNAL: " + value + "@" + time + " = " + signalObject); if (value >= 0d && curGraph != null) { if (hasSignalCategoryChanged) { curGraph.addValue((1 - value), signalChangeStartTime); hasSignalCategoryChanged = false; if (lastLabelYPosition == -1d) { lastLabelYPosition = (float) (1 - (value > 0d ? value : prevValue)); } else { if (Math.abs(signalChangeStartTime - time) < .125d) { float curPosition = (float) (1 - (value > 0d ? value : prevValue)); if (Math.abs(curPosition - lastLabelYPosition) <= .11d) { lastLabelYPosition = curPosition + (curPosition > lastLabelYPosition ? +.1d : -.1d); } else { lastLabelYPosition = curPosition; } } else { lastLabelYPosition = (float) (1 - (value > 0d ? value : prevValue)); } } //lastLabelXPosition = (float) time; double labelDiff = lastLabelYPosition - (1 - value); System.out.println("i" + i + " -> " + lastLabelYPosition + " : " + (1 - value) + " diff: " + Math.abs(labelDiff) + " istoolow (<.09d)? " + (Math.abs(labelDiff) < .09d)); if (Math.abs(labelDiff) < .09d && i == 0) { if (labelDiff < 0d) { lastLabelYPosition = lastLabelYPosition < .50d ? lastLabelYPosition - .075d : lastLabelYPosition + .075d; } else { lastLabelYPosition = lastLabelYPosition < .50d ? lastLabelYPosition + .075d : lastLabelYPosition - .075d; } } signalGraph.addLabel((float) signalChangeStartTime, (float) lastLabelYPosition, networkType, signalColor); } //System.out.println("ADDING VALUE TO GRAPH " + (1 - value) + " on: " + time); curGraph.addValue((1 - value), time); prevValue = value; } } lastNetworkType = networkType; lastCatTechnology = catTechnology; } //draw signal graph to the end if (prevValue > 0 && curGraph != null) { curGraph.addValue((1 - prevValue), 1f); } signalGraph.clearLabels(CustomizableGraphView.LABELLIST_VERTICAL_MAX); signalGraph.clearLabels(CustomizableGraphView.LABELLIST_VERTICAL_MIN); if (has3G) { signalGraph.addLabelVMax(String.valueOf(signalBoundsMobile.max), COLOR_SIGNAL_3G); signalGraph.addLabelVMin(String.valueOf(signalBoundsMobile.min), COLOR_SIGNAL_3G); } if (has4G) { signalGraph.addLabelVMax(String.valueOf(signalBoundsRsrp.max), COLOR_SIGNAL_4G); signalGraph.addLabelVMin(String.valueOf(signalBoundsRsrp.min), COLOR_SIGNAL_4G); } if (hasWlan) { signalGraph.addLabelVMax(String.valueOf(signalBoundsWlan.max), COLOR_SIGNAL_WLAN); signalGraph.addLabelVMin(String.valueOf(signalBoundsWlan.min), COLOR_SIGNAL_WLAN); } //signalGraph.repaint(getContext()); } else if (signalGraph != null && signalGraph.getGraphs().size() > 0) { Log.d("ResultGraphView", "REDRAWING SIGNAL GRAPH"); //signalGraph.repaint(getContext()); signalGraph.invalidate(); } signalProgress.setVisibility(View.GONE); if (uploadArray != null && uploadArray != null && uploadArray.length() > 0 && ulGraph.getGraphs().size() < 1) { Log.d("ResultGraphView", "DRAWING UL GRAPH"); drawCurve(uploadArray, ulGraph, COLOR_UL_GRAPH, String .valueOf(Math.round(result.getJSONObject(0).optDouble("duration_upload_ms") / 1000d))); addStaticMarker(signalArray, signalGraph, COLOR_UL_GRAPH, 70, result.getJSONObject(0).optDouble("time_ul_ms"), result.getJSONObject(0).optDouble("time_ul_ms") + result.getJSONObject(0).optDouble("duration_upload_ms"), timeElapsed * 1000); double timeUl = result.getJSONObject(0).optDouble("duration_upload_ms"); long timeElapsedUl = Math.round(timeUl / 1000); ulGraph.setRowLinesLabelList(SPEED_LABELS); ulGraph.updateGrid((int) timeElapsedUl, 4.5f); } else if (uploadArray.length() > 0 && ulGraph != null && ulGraph.getGraphs().size() > 0) { Log.d("ResultGraphView", "REDRAWING UL GRAPH"); //ulGraph.repaint(getContext()); ulGraph.invalidate(); } ulProgress.setVisibility(View.GONE); if (downloadArray != null && downloadArray != null && downloadArray.length() > 0 && dlGraph.getGraphs().size() < 1) { Log.d("ResultGraphView", "DRAWING DL GRAPH"); drawCurve(downloadArray, dlGraph, COLOR_DL_GRAPH, String .valueOf(Math.round(result.getJSONObject(0).optDouble("duration_download_ms") / 1000d))); addStaticMarker(signalArray, signalGraph, COLOR_DL_GRAPH, 70, result.getJSONObject(0).optDouble("time_dl_ms"), result.getJSONObject(0).optDouble("time_dl_ms") + result.getJSONObject(0).optDouble("duration_download_ms"), timeElapsed * 1000); double timeDl = result.getJSONObject(0).optDouble("duration_download_ms"); long timeElapsedDl = Math.round(timeDl / 1000); dlGraph.setRowLinesLabelList(SPEED_LABELS); dlGraph.updateGrid((int) timeElapsedDl, 4.5f); } else if (downloadArray.length() > 0 && dlGraph != null && dlGraph.getGraphs().size() > 0) { Log.d("ResultGraphView", "REDRAWING DL GRAPH"); //dlGraph.repaint(getContext()); dlGraph.invalidate(); } dlProgress.setVisibility(View.GONE); } catch (Exception e) { if (signalGraph != null) { signalGraph.invalidate(); } if (ulGraph != null) { ulGraph.invalidate(); } if (dlGraph != null) { dlGraph.invalidate(); } e.printStackTrace(); //TODO show no data available view } } public double getRelativeSignal(final MinMax<Integer> signalBounds, final String signalAttribute, final JSONObject signalObject) throws JSONException { final int signal = signalObject.getInt(signalAttribute); final double value = signal < 0 ? ((double) (signal - signalBounds.max) / (double) (signalBounds.min - signalBounds.max)) : signal; System.out.println("signalAttrib: " + signalAttribute + ", signal: " + signal + " value: " + value); return value; } /** * * @param graphArray * @param graphView * @param color * @throws JSONException */ public void addStaticMarker(JSONArray graphArray, CustomizableGraphView graphView, String color, double absoluteMarkerMs, double maxTimeMs) throws JSONException { StaticGraph markerGraph = StaticGraph.addGraph(graphView, Color.parseColor(color), false); final double startTime = (absoluteMarkerMs / maxTimeMs); markerGraph.addValue(1, startTime); markerGraph.addValue(0, startTime); } /** * * @param graphArray * @param graphView * @param color * @param alpha * @param absoluteMarkerStartMs * @param absoluteMarkerEndMs * @param maxTimeMs * @throws JSONException */ public void addStaticMarker(JSONArray graphArray, CustomizableGraphView graphView, String color, int alpha, double absoluteMarkerStartMs, double absoluteMarkerEndMs, double maxTimeMs) throws JSONException { StaticGraph markerGraph = StaticGraph.addGraph(graphView, Color.parseColor(color), false); StaticGraph markerGraphStartLine = StaticGraph.addGraph(graphView, Color.parseColor(color), false); StaticGraph markerGraphEndLine = StaticGraph.addGraph(graphView, Color.parseColor(color), false); markerGraph.setFillAlpha(alpha / 2); markerGraph.setPaintAlpha(alpha / 2); markerGraphStartLine.setPaintAlpha(alpha); markerGraphEndLine.setPaintAlpha(alpha); final double startTime = (absoluteMarkerStartMs / maxTimeMs); final double endTime = (absoluteMarkerEndMs / maxTimeMs); markerGraph.addValue(1, startTime); markerGraph.addValue(1, endTime); markerGraphStartLine.addValue(1, startTime); markerGraphStartLine.addValue(0, startTime); markerGraphEndLine.addValue(1, endTime); markerGraphEndLine.addValue(0, endTime); } /** * * @param graphArray * @param graphView * @throws JSONException */ public void drawCurve(JSONArray graphArray, CustomizableGraphView graphView, String color, String labelHMax) throws JSONException { final double maxTime = graphArray.optJSONObject(graphArray.length() - 1).optDouble("time_elapsed"); //final double pointDistance = (0.25d / (maxTime / 1000)); graphView.getLabelHMaxList().clear(); graphView.addLabelHMax(labelHMax); //StaticGraph signal = StaticGraph.addGraph(graphView, Color.parseColor(color)); GraphService signal = SmoothGraph.addGraph(graphView, Color.parseColor(color), RMBTTestFragment.SMOOTHING_DATA_AMOUNT, RMBTTestFragment.SMOOTHING_FUNCTION, false); if (graphArray != null && graphArray.length() > 0) { long bytes = 0; for (int i = 0; i < graphArray.length(); i++) { JSONObject uploadObject = graphArray.getJSONObject(i); double time_elapsed = uploadObject.getInt("time_elapsed"); bytes = uploadObject.getInt("bytes_total"); double bitPerSec = (bytes * 8000 / time_elapsed); double time = (time_elapsed / maxTime); if (i + 1 == graphArray.length()) { signal.addValue(IntermediateResult.toLog((long) bitPerSec), time, SmoothGraph.FLAG_ALIGN_RIGHT); } else { signal.addValue(IntermediateResult.toLog((long) bitPerSec), time, i == 0 ? SmoothGraph.FLAG_ALIGN_LEFT : SmoothGraph.FLAG_NONE); } } } } @Override public void invalidate() { setFillViewport(true); super.invalidate(); } @Override protected void onConfigurationChanged(Configuration newConfig) { view = null; super.onConfigurationChanged(newConfig); } @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putString("test_result", testResult.toString()); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; try { testResult = new JSONArray(bundle.getString("test_result")); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } return; } } public void recycle() { if (dlGraph != null) { dlGraph.recycle(); dlGraph = null; } if (ulGraph != null) { ulGraph.recycle(); ulGraph = null; } if (signalGraph != null) { signalGraph.recycle(); signalGraph = null; } } }