/*
* 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 com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ChartURLGenerator;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
import android.content.Context;
import java.util.Vector;
/**
* An implementation of {@link DescriptionGenerator} for My Tracks.
*
* @author Jimmy Shih
*/
public class DescriptionGeneratorImpl implements DescriptionGenerator {
private static final String HTML_LINE_BREAK = "<br>";
private static final String HTML_PARAGRAPH_SEPARATOR = "<p>";
private static final String TEXT_LINE_BREAK = "\n";
private static final String TEXT_PARAGRAPH_SEPARATOR = "\n\n";
private Context context;
public DescriptionGeneratorImpl(Context context) {
this.context = context;
}
@Override
public String generateTrackDescription(
Track track, Vector<Double> distances, Vector<Double> elevations, boolean html) {
String paragraphSeparator = html ? HTML_PARAGRAPH_SEPARATOR : TEXT_PARAGRAPH_SEPARATOR;
String lineBreak = html ? HTML_LINE_BREAK : TEXT_LINE_BREAK;
StringBuilder builder = new StringBuilder();
// Created by
String beginAnchor = html
? "<a href='http://" + context.getString(R.string.my_tracks_web_url) + "'>"
: "";
String endAnchor = html ? "</a>" : "";
builder.append(context.getString(R.string.send_google_by_my_tracks, beginAnchor, endAnchor));
builder.append(paragraphSeparator);
writeString(track.getName(), builder, R.string.generic_name_line, lineBreak);
writeString(track.getCategory(), builder, R.string.description_activity_type, lineBreak);
writeString(track.getDescription(), builder, R.string.generic_description_line, lineBreak);
builder.append(generateTripStatisticsDescription(track.getTripStatistics(), html));
// Elevation chart
if (html && distances != null && elevations != null) {
builder.append("<img border=\"0\" src=\""
+ ChartURLGenerator.getChartUrl(distances, elevations, track, context) + "\"/>");
builder.append(HTML_LINE_BREAK);
}
return builder.toString();
}
@Override
public String generateWaypointDescription(TripStatistics tripStatistics) {
return generateTripStatisticsDescription(tripStatistics, false);
}
/**
* Writes a string to a string builder.
*
* @param text the string
* @param builder the string builder
* @param resId the resource id containing one string placeholder
* @param lineBreak the line break
*/
private void writeString(String text, StringBuilder builder, int resId, String lineBreak) {
if (text == null || text.length() == 0) {
text = context.getString(R.string.value_unknown);
}
builder.append(context.getString(resId, text));
builder.append(lineBreak);
}
/**
* Generates a description for a {@link TripStatistics}.
*
* @param stats the trip statistics
* @param html true to use "<br>" for line break instead of "\n"
*/
private String generateTripStatisticsDescription(TripStatistics stats, boolean html) {
String lineBreak = html ? HTML_LINE_BREAK : TEXT_LINE_BREAK;
StringBuilder builder = new StringBuilder();
// Total distance
writeDistance(
stats.getTotalDistance(), builder, R.string.description_total_distance, lineBreak);
// Total time
writeTime(stats.getTotalTime(), builder, R.string.description_total_time, lineBreak);
// Moving time
writeTime(stats.getMovingTime(), builder, R.string.description_moving_time, lineBreak);
// Average speed
writeSpeed(stats.getAverageSpeed(), builder, R.string.description_average_speed, lineBreak);
// Average moving speed
writeSpeed(stats.getAverageMovingSpeed(), builder, R.string.description_average_moving_speed,
lineBreak);
// Max speed
writeSpeed(stats.getMaxSpeed(), builder, R.string.description_max_speed, lineBreak);
// Average pace
writePace(
stats.getAverageSpeed(), builder, R.string.description_average_pace_in_minute, lineBreak);
// Average moving pace
writePace(stats.getAverageMovingSpeed(), builder,
R.string.description_average_moving_pace_in_minute, lineBreak);
// Fastest pace
writePace(stats.getMaxSpeed(), builder, R.string.description_fastest_pace_in_minute, lineBreak);
// Max elevation
writeElevation(stats.getMaxElevation(), builder, R.string.description_max_elevation, lineBreak);
// Min elevation
writeElevation(stats.getMinElevation(), builder, R.string.description_min_elevation, lineBreak);
// Elevation gain
writeElevation(
stats.getTotalElevationGain(), builder, R.string.description_elevation_gain, lineBreak);
// Max grade
writeGrade(stats.getMaxGrade(), builder, R.string.description_max_grade, lineBreak);
// Min grade
writeGrade(stats.getMinGrade(), builder, R.string.description_min_grade, lineBreak);
// Recorded time
builder.append(
context.getString(R.string.description_recorded_time,
StringUtils.formatDateTime(context, stats.getStartTime())));
builder.append(lineBreak);
return builder.toString();
}
/**
* Writes distance.
*
* @param distance distance in meters
* @param builder StringBuilder to append distance
* @param resId resource id of distance string
* @param lineBreak line break string
*/
@VisibleForTesting
void writeDistance(double distance, StringBuilder builder, int resId, String lineBreak) {
double distanceInKm = distance * UnitConversions.M_TO_KM;
double distanceInMi = distanceInKm * UnitConversions.KM_TO_MI;
builder.append(context.getString(resId, distanceInKm, distanceInMi));
builder.append(lineBreak);
}
/**
* Writes time.
*
* @param time time in milliseconds.
* @param builder StringBuilder to append time
* @param resId resource id of time string
* @param lineBreak line break string
*/
@VisibleForTesting
void writeTime(long time, StringBuilder builder, int resId, String lineBreak) {
builder.append(context.getString(resId, StringUtils.formatElapsedTime(time)));
builder.append(lineBreak);
}
/**
* Writes speed.
*
* @param speed speed in meters per second
* @param builder StringBuilder to append speed
* @param resId resource id of speed string
* @param lineBreak line break string
*/
@VisibleForTesting
void writeSpeed(
double speed, StringBuilder builder, int resId, String lineBreak) {
double speedInKmHr = speed * UnitConversions.MS_TO_KMH;
double speedInMiHr = speedInKmHr * UnitConversions.KM_TO_MI;
builder.append(context.getString(resId, speedInKmHr, speedInMiHr));
builder.append(lineBreak);
}
/**
* Writes pace.
*
* @param speed speed in meters per second
* @param builder StringBuilder to append pace
* @param resId resource id of pace string
* @param lineBreak line break string
*/
@VisibleForTesting
void writePace(double speed, StringBuilder builder, int resId, String lineBreak) {
String[] paceInMetrics = StringUtils.getSpeedParts(context, speed, true, false);
String[] paceInImperial = StringUtils.getSpeedParts(context, speed, false, false);
if (paceInMetrics[0] == null) {
paceInMetrics[0] = context.getString(R.string.value_unknown);
}
if (paceInImperial[0] == null) {
paceInImperial[0] = context.getString(R.string.value_unknown);
}
builder.append(context.getString(resId, paceInMetrics[0], paceInImperial[0]));
builder.append(lineBreak);
}
/**
* Writes elevation.
*
* @param elevation elevation in meters
* @param builder StringBuilder to append elevation
* @param resId resource id of elevation string
* @param lineBreak line break string
*/
@VisibleForTesting
void writeElevation(
double elevation, StringBuilder builder, int resId, String lineBreak) {
long elevationInM = Math.round(elevation);
long elevationInFt = Math.round(elevation * UnitConversions.M_TO_FT);
builder.append(context.getString(resId, elevationInM, elevationInFt));
builder.append(lineBreak);
}
/**
* Writes grade.
*
* @param grade grade in fraction
* @param builder StringBuilder to append grade
* @param resId resource id grade string
* @param lineBreak line break string
*/
@VisibleForTesting
void writeGrade(double grade, StringBuilder builder, int resId, String lineBreak) {
long gradeInPercent = Double.isNaN(grade) || Double.isInfinite(grade) ? 0L
: Math.round(grade * 100);
builder.append(context.getString(resId, gradeInPercent));
builder.append(lineBreak);
}
}