/* * Copyright (c) 2013, Will Szumski * Copyright (c) 2013, Doug Szumski * * This file is part of Cyclismo. * * Cyclismo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Cyclismo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Cyclismo. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright 2012 Google Inc. * * 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 org.cowboycoders.cyclismo.util; import android.app.Activity; import android.location.Location; import android.util.Log; import android.view.View; import android.widget.TextView; import org.cowboycoders.cyclismo.R; import org.cowboycoders.cyclismo.content.MyTracksLocation; import org.cowboycoders.cyclismo.content.Sensor; import org.cowboycoders.cyclismo.stats.TripStatistics; /** * Utilities for updating the statistics UI labels and values. * * @author Jimmy Shih */ public class StatsUtils { public static final String TAG = "StatsUtils"; private StatsUtils() {} /** * Set sensor data values * * @param activity the activity * @param location the location containing the sensor data */ public static void setSensorDataValues(Activity activity, MyTracksLocation location) { // Try and get sensor data Sensor.SensorDataSet sensorDataSet; if (location.getSensorDataSet() != null) { sensorDataSet = location.getSensorDataSet(); } else { Log.d(TAG, "Failed to get sensor data"); return; } // Set instantaneous power boolean showPower = PreferencesUtils.getBoolean( activity, R.string.stats_show_power_key, PreferencesUtils.STATS_SHOW_POWER_DEFAULT); View powerLabelTableRow = activity.findViewById(R.id.stats_power_label_table_row); View powerValueTableRow = activity.findViewById(R.id.stats_power_value_table_row); if (powerLabelTableRow == null || powerValueTableRow == null) { return; } powerLabelTableRow.setVisibility(showPower ? View.VISIBLE : View.GONE); powerValueTableRow.setVisibility(showPower ? View.VISIBLE : View.GONE); double instPower = Double.NaN; if (showPower && sensorDataSet!= null) { if (sensorDataSet.hasPower() && sensorDataSet.getPower().getState() == Sensor.SensorState.SENDING && sensorDataSet.getPower().hasValue()) { instPower = sensorDataSet.getPower().getValue(); } } setSensorValue(activity, R.id.stats_inst_power_value, instPower, R.string.value_integer_power); // Set instantaneous cadence boolean showCadence = PreferencesUtils.getBoolean( activity, R.string.stats_show_cadence_key, PreferencesUtils.STATS_SHOW_CADENCE_DEFAULT); View cadenceLabelTableRow = activity.findViewById(R.id.stats_cadence_label_table_row); View cadenceValueTableRow = activity.findViewById(R.id.stats_cadence_value_table_row); if (cadenceLabelTableRow == null || cadenceValueTableRow == null) { return; } cadenceLabelTableRow.setVisibility(showCadence ? View.VISIBLE : View.GONE); cadenceValueTableRow.setVisibility(showCadence ? View.VISIBLE : View.GONE); double instCadence = Double.NaN; if (showCadence && sensorDataSet!= null) { if (sensorDataSet.hasCadence() && sensorDataSet.getCadence().getState() == Sensor.SensorState.SENDING && sensorDataSet.getCadence().hasValue()) { instCadence = sensorDataSet.getCadence().getValue(); } } setSensorValue(activity, R.id.stats_inst_cadence_value, instCadence, R.string.value_integer_cadence); // Set instantaneous heart rate boolean showHeartRate = PreferencesUtils.getBoolean( activity, R.string.stats_show_heartrate_key, PreferencesUtils.STATS_SHOW_HEARTRATE_DEFAULT); View heartRateLabelTableRow = activity.findViewById(R.id.stats_heartrate_label_table_row); View heartRateValueTableRow = activity.findViewById(R.id.stats_heartrate_value_table_row); if (heartRateLabelTableRow == null || heartRateValueTableRow == null) { return; } heartRateLabelTableRow.setVisibility(showHeartRate ? View.VISIBLE : View.GONE); heartRateValueTableRow.setVisibility(showHeartRate ? View.VISIBLE : View.GONE); double instHeartRate = Double.NaN; if (showHeartRate && sensorDataSet!= null) { if (sensorDataSet.hasHeartRate() && sensorDataSet.getHeartRate().getState() == Sensor.SensorState.SENDING && sensorDataSet.getHeartRate().hasValue()) { instHeartRate = sensorDataSet.getHeartRate().getValue(); } } setSensorValue(activity, R.id.stats_inst_heartrate_value, instHeartRate, R.string.value_integer_heartrate); } /** * Sets the location values. * * @param activity the activity * @param location the location * @param showAll true to show all the fields, false to show only the * elevation field */ public static void setLocationValues(Activity activity, Location location, boolean showAll) { boolean metricUnits = PreferencesUtils.getBoolean( activity, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT); boolean reportSpeed = PreferencesUtils.getBoolean( activity, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT); // Set elevation boolean showElevation = PreferencesUtils.getBoolean( activity, R.string.stats_show_elevation_key, PreferencesUtils.STATS_SHOW_ELEVATION_DEFAULT); if (showElevation) { double altitude = location == null ? Double.NaN : location.getAltitude(); setElevationValue(activity, R.id.stats_elevation_value, altitude, metricUnits); } if (!showAll) { return; } // Set speed/pace setSpeedLabel( activity, R.id.stats_speed_label, R.string.stats_speed, R.string.stats_pace, reportSpeed); double speed = location == null ? Double.NaN : location.getSpeed(); setSpeedValue(activity, R.id.stats_speed_value, speed, metricUnits, reportSpeed); // Set coordinate boolean showCoordinate = PreferencesUtils.getBoolean(activity, R.string.stats_show_coordinate_key, PreferencesUtils.STATS_SHOW_COORDINATE_DEFAULT); View coordinateLabelTableRow = activity.findViewById(R.id.stats_coordinate_label_table_row); View coordinateValueTableRow = activity.findViewById(R.id.stats_coordinate_value_table_row); if (coordinateLabelTableRow == null || coordinateValueTableRow == null) { return; } coordinateLabelTableRow.setVisibility(showCoordinate ? View.VISIBLE : View.GONE); coordinateValueTableRow.setVisibility(showCoordinate ? View.VISIBLE : View.GONE); if (showCoordinate) { double latitude = location == null ? Double.NaN : location.getLatitude(); double longitude = location == null ? Double.NaN : location.getLongitude(); setCoordinateValue(activity, R.id.stats_latitude_value, latitude); setCoordinateValue(activity, R.id.stats_longitude_value, longitude); } } /** * Sets the total time value. * * @param activity the activity * @param totalTime the total time */ public static void setTotalTimeValue(Activity activity, long totalTime) { setTimeValue(activity, R.id.stats_total_time_value, totalTime); } /** * Sets the trip statistics values. * * @param activity the activity * @param tripStatistics the trip statistics */ public static void setTripStatisticsValues(Activity activity, TripStatistics tripStatistics) { boolean metricUnits = PreferencesUtils.getBoolean( activity, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT); boolean reportSpeed = PreferencesUtils.getBoolean( activity, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT); boolean showTotalTime = PreferencesUtils.getBoolean(activity, R.string.stats_show_total_time_key, PreferencesUtils.STATS_SHOW_TOTAL_TIME_DEFAULT); boolean showMovingTime = PreferencesUtils.getBoolean(activity, R.string.stats_show_moving_time_key, PreferencesUtils.STATS_SHOW_MOVING_TIME_DEFAULT); // Set total distance double totalDistance = tripStatistics == null ? Double.NaN : tripStatistics.getTotalDistance(); setDistanceValue(activity, R.id.stats_distance_value, totalDistance, metricUnits); // Set total time setItemVisibility(activity, R.id.stats_total_time_label, -1, R.id.stats_total_time_value, showTotalTime); if (showTotalTime) { setTimeValue(activity, R.id.stats_total_time_value, tripStatistics != null ? tripStatistics.getTotalTime() : -1L); } // Set moving time. Only show the spacer if total time and moving time are shown. setItemVisibility(activity, R.id.stats_moving_time_label, R.id.stats_moving_time_spacer, R.id.stats_moving_time_value, showMovingTime, showMovingTime && showTotalTime); if (showMovingTime) { setTimeValue(activity, R.id.stats_moving_time_value, tripStatistics != null ? tripStatistics.getMovingTime() : -1L); } // Set average speed setSpeedLabel(activity, R.id.stats_average_speed_label, R.string.stats_average_speed, R.string.stats_average_pace, reportSpeed); double averageSpeed = tripStatistics != null ? tripStatistics.getAverageSpeed() : Double.NaN; setSpeedValue(activity, R.id.stats_average_speed_value, averageSpeed, metricUnits, reportSpeed); // Set average moving speed setItemVisibility(activity, R.id.stats_average_moving_speed_label, R.id.stats_average_moving_speed_spacer, R.id.stats_average_moving_speed_value, showMovingTime); if (showMovingTime) { setSpeedLabel(activity, R.id.stats_average_moving_speed_label, R.string.stats_average_moving_speed, R.string.stats_average_moving_pace, reportSpeed); double averageMovingSpeed = tripStatistics != null ? tripStatistics.getAverageMovingSpeed() : Double.NaN; setSpeedValue(activity, R.id.stats_average_moving_speed_value, averageMovingSpeed, metricUnits, reportSpeed); } // TODO: Hide these fields when off in stats menu double avgPower = tripStatistics == null ? Double.NaN : tripStatistics.getAverageMovingPower(); setSensorValue(activity, R.id.stats_avg_power_value, avgPower, R.string.value_integer_power); double avgCadence = tripStatistics == null ? Double.NaN : tripStatistics.getAverageMovingCadence(); setSensorValue(activity, R.id.stats_avg_cadence_value, avgCadence, R.string.value_integer_cadence); double avgHeartRate = tripStatistics == null ? Double.NaN : tripStatistics.getAverageMovingHeartRate(); setSensorValue(activity, R.id.stats_avg_heartrate_value, avgHeartRate, R.string.value_integer_heartrate); // Set max speed setSpeedLabel(activity, R.id.stats_max_speed_label, R.string.stats_max_speed, R.string.stats_fastest_pace, reportSpeed); double maxSpeed = tripStatistics == null ? Double.NaN : tripStatistics.getMaxSpeed(); setSpeedValue(activity, R.id.stats_max_speed_value, maxSpeed, metricUnits, reportSpeed); // Set elevation boolean showElevation = PreferencesUtils.getBoolean( activity, R.string.stats_show_elevation_key, PreferencesUtils.STATS_SHOW_ELEVATION_DEFAULT); View elevationLabelTableRow1 = activity.findViewById(R.id.stats_elevation_label_table_row1); View elevationValueTableRow1 = activity.findViewById(R.id.stats_elevation_value_table_row1); View elevationLabelTableRow2 = activity.findViewById(R.id.stats_elevation_label_table_row2); View elevationValueTableRow2 = activity.findViewById(R.id.stats_elevation_value_table_row2); if (elevationLabelTableRow1 == null || elevationValueTableRow1 == null || elevationLabelTableRow2 == null || elevationValueTableRow2 == null) { return; } elevationLabelTableRow1.setVisibility(showElevation ? View.VISIBLE : View.GONE); elevationValueTableRow1.setVisibility(showElevation ? View.VISIBLE : View.GONE); elevationLabelTableRow2.setVisibility(showElevation ? View.VISIBLE : View.GONE); elevationValueTableRow2.setVisibility(showElevation ? View.VISIBLE : View.GONE); if (showElevation) { double elevationGain = tripStatistics == null ? Double.NaN : tripStatistics.getTotalElevationGain(); double minElevation = tripStatistics == null ? Double.NaN : tripStatistics.getMinElevation(); double maxElevation = tripStatistics == null ? Double.NaN : tripStatistics.getMaxElevation(); setElevationValue(activity, R.id.stats_elevation_gain_value, elevationGain, metricUnits); setElevationValue(activity, R.id.stats_min_elevation_value, minElevation, metricUnits); setElevationValue(activity, R.id.stats_max_elevation_value, maxElevation, metricUnits); } // Set grade boolean showGrade = PreferencesUtils.getBoolean( activity, R.string.stats_show_grade_key, PreferencesUtils.STATS_SHOW_GRADE_DEFAULT); View gradeLabelTableRow = activity.findViewById(R.id.stats_grade_label_table_row); View gradeValueTableRow = activity.findViewById(R.id.stats_grade_value_table_row); if (gradeLabelTableRow == null || gradeValueTableRow == null) { return; } gradeLabelTableRow.setVisibility(showGrade ? View.VISIBLE : View.GONE); gradeValueTableRow.setVisibility(showGrade ? View.VISIBLE : View.GONE); if (showGrade) { double minGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMinGrade(); double maxGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMaxGrade(); setGradeValue(activity, R.id.stats_min_grade_value, minGrade); setGradeValue(activity, R.id.stats_max_grade_value, maxGrade); } } private static void setItemVisibility( Activity activity, int labelId, int spacerId, int valueId, boolean show) { setItemVisibility(activity, labelId, spacerId, valueId, show, show); } private static void setItemVisibility( Activity activity, int labelId, int spacerId, int valueId, boolean show, boolean show_spacer) { View label = activity.findViewById(labelId); View spacer = activity.findViewById(spacerId); View value = activity.findViewById(valueId); if (label != null) { label.setVisibility(show ? View.VISIBLE : View.GONE); } if (spacer != null) { spacer.setVisibility(show_spacer ? View.VISIBLE : View.GONE); } if (value != null) { value.setVisibility(show ? View.VISIBLE : View.GONE); } } /** * Sets a speed label. * * @param activity the activity * @param id the speed label resource id * @param speedId the speed string id * @param paceId the pace string id * @param reportSpeed true to report speed */ private static void setSpeedLabel( Activity activity, int id, int speedId, int paceId, boolean reportSpeed) { TextView textView = (TextView) activity.findViewById(id); if (textView == null) { return; } textView.setText(reportSpeed ? speedId : paceId); } /** * Sets a speed value. * * @param activity the activity * @param id the speed value resource id * @param speed the speed in meters per second * @param metricUnits true to display in metric units * @param reportSpeed true to report speed */ private static void setSpeedValue( Activity activity, int id, double speed, boolean metricUnits, boolean reportSpeed) { TextView textView = (TextView) activity.findViewById(id); if (textView == null) { return; } textView.setText(StringUtils.formatSpeed(activity, speed, metricUnits, reportSpeed)); } /** * Sets a distance value. * * @param activity the activity * @param id the distance value resource id * @param distance the distance in meters * @param metricUnits true to display in metric units */ private static void setDistanceValue( Activity activity, int id, double distance, boolean metricUnits) { TextView textView = (TextView) activity.findViewById(id); if (textView == null) { return; } textView.setText(StringUtils.formatDistance(activity, distance, metricUnits)); } /** * Sets a time value. * * @param activity the activity * @param id the time value resource id * @param time the time */ private static void setTimeValue(Activity activity, int id, long time) { TextView textView = (TextView) activity.findViewById(id); if (textView == null) { return; } String value = time == -1L ? activity.getString(R.string.value_unknown) : StringUtils.formatElapsedTime(time); textView.setText(value); } /** * Sets an elevation value. * * @param activity the activity * @param id the elevation value resource id * @param elevation the elevation in meters * @param metricUnits true to display in metric units */ private static void setElevationValue( Activity activity, int id, double elevation, boolean metricUnits) { TextView textView = (TextView) activity.findViewById(id); if (textView == null) { return; } String value; if (Double.isNaN(elevation) || Double.isInfinite(elevation)) { value = activity.getString(R.string.value_unknown); } else { if (metricUnits) { value = activity.getString(R.string.value_float_meter, elevation); } else { elevation *= UnitConversions.M_TO_FT; value = activity.getString(R.string.value_float_feet, elevation); } } textView.setText(value); } /** * Sets a grade value. * * @param activity the activity * @param id the grade value resource id * @param grade the grade in fraction between 0 and 1 */ private static void setGradeValue(Activity activity, int id, double grade) { TextView textView = (TextView) activity.findViewById(id); if (textView == null) { return; } String value; if (Double.isNaN(grade) || Double.isInfinite(grade)) { value = activity.getString(R.string.value_unknown); } else { value = activity.getString(R.string.value_integer_percent, Math.round(grade * 100)); } textView.setText(value); } /** * Sets a sensor value. * * @param activity the activity * @param id the value resource id * @param sensorValue the sensor value */ private static void setSensorValue(Activity activity, int id, double sensorValue, int format) { TextView textView = (TextView) activity.findViewById(id); if (textView == null) { return; } String value; if (Double.isNaN(sensorValue) || Double.isInfinite(sensorValue)) { value = activity.getString(R.string.value_unknown); } else { value = activity.getString(format, Math.round(sensorValue)); } textView.setText(value); } /** * Sets a coordinate value. * * @param activity the activity * @param id the coordinate value resource id * @param coordinate the coordinate in degrees */ private static void setCoordinateValue(Activity activity, int id, double coordinate) { TextView textView = (TextView) activity.findViewById(id); if (textView == null) { return; } String value; if (Double.isNaN(coordinate) || Double.isInfinite(coordinate)) { value = activity.getString(R.string.value_unknown); } else { value = activity.getString( R.string.value_coordinate_degree, Location.convert(coordinate, Location.FORMAT_DEGREES)); } textView.setText(value); } }