package net.osmand.plus.activities;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.FileProvider;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.listener.ChartTouchListener;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import net.osmand.Location;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.plus.GPXUtilities;
import net.osmand.plus.GPXUtilities.GPXFile;
import net.osmand.plus.GPXUtilities.GPXTrackAnalysis;
import net.osmand.plus.GPXUtilities.Track;
import net.osmand.plus.GPXUtilities.TrkSegment;
import net.osmand.plus.GPXUtilities.WptPt;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.IconsCache;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
import net.osmand.plus.mapcontextmenu.other.MapRouteInfoMenu;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.TurnPathHelper;
import net.osmand.util.Algorithms;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.binary.RouteDataObject.HEIGHT_UNDEFINED;
public class ShowRouteInfoDialogFragment extends DialogFragment {
public static final String TAG = "ShowRouteInfoDialogFragment";
private RoutingHelper helper;
private View view;
private ListView listView;
private RouteInfoAdapter adapter;
private GPXFile gpx;
private OrderedLineDataSet elevationDataSet;
private OrderedLineDataSet slopeDataSet;
private GpxDisplayItem gpxItem;
private boolean hasHeights;
public ShowRouteInfoDialogFragment() {
}
private OsmandApplication getMyApplication() {
return (OsmandApplication) getActivity().getApplication();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean isLightTheme = getMyApplication().getSettings().OSMAND_THEME.get() == OsmandSettings.OSMAND_LIGHT_THEME;
int themeId = isLightTheme ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme;
setStyle(STYLE_NO_FRAME, themeId);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final OsmandApplication app = getMyApplication();
helper = app.getRoutingHelper();
view = inflater.inflate(R.layout.route_info_layout, container, false);
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
toolbar.setNavigationIcon(getMyApplication().getIconsCache().getThemedIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha));
toolbar.setNavigationContentDescription(R.string.shared_string_close);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
((ImageView) view.findViewById(R.id.distance_icon))
.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_polygom_dark));
((ImageView) view.findViewById(R.id.time_icon))
.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_time_span));
buildMenuButtons();
listView = (ListView) view.findViewById(android.R.id.list);
listView.setBackgroundColor(getResources().getColor(
app.getSettings().isLightContent() ? R.color.ctx_menu_info_view_bg_light
: R.color.ctx_menu_info_view_bg_dark));
View topShadowView = inflater.inflate(R.layout.list_shadow_header, listView, false);
listView.addHeaderView(topShadowView, null, false);
View bottomShadowView = inflater.inflate(R.layout.list_shadow_footer, listView, false);
listView.addFooterView(bottomShadowView, null, false);
adapter = new RouteInfoAdapter(helper.getRouteDirections());
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position < 2) {
return;
}
RouteDirectionInfo item = adapter.getItem(position - 2);
Location loc = helper.getLocationFromRouteDirection(item);
if(loc != null){
MapRouteInfoMenu.directionInfo = position - 2;
OsmandSettings settings = getMyApplication().getSettings();
settings.setMapLocationToShow(loc.getLatitude(),loc.getLongitude(),
Math.max(13, settings.getLastKnownMapZoom()),
new PointDescription(PointDescription.POINT_TYPE_MARKER, item.getDescriptionRoutePart() + " " + getTimeDescription(item)),
false, null);
MapActivity.launchMapActivityMoveToTop(getActivity());
dismiss();
}
}
});
int dist = helper.getLeftDistance();
int time = helper.getLeftTime();
int hours = time / (60 * 60);
int minutes = (time / 60) % 60;
((TextView)view.findViewById(R.id.distance)).setText(OsmAndFormatter.getFormattedDistance(dist, app));
StringBuilder timeStr = new StringBuilder();
if (hours > 0) {
timeStr.append(hours).append(" ").append(getString(R.string.osmand_parking_hour)).append(" ");
}
if (minutes > 0) {
timeStr.append(minutes).append(" ").append(getString(R.string.osmand_parking_minute));
}
((TextView)view.findViewById(R.id.time)).setText(timeStr);
view.findViewById(R.id.go_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivity activity = (MapActivity)getActivity();
if (activity != null) {
activity.getMapLayers().getMapControlsLayer().startNavigation();
dismiss();
}
}
});
makeGpx();
if (hasHeights) {
View headerView = inflater.inflate(R.layout.route_info_header, null);
buildHeader(headerView);
listView.addHeaderView(headerView);
}
return view;
}
private void makeGpx() {
double lastHeight = HEIGHT_UNDEFINED;
gpx = new GPXFile();
List<Location> locations = helper.getRoute().getRouteLocations();
if (locations != null) {
Track track = new Track();
TrkSegment seg = new TrkSegment();
for (Location l : locations) {
WptPt point = new WptPt();
point.lat = l.getLatitude();
point.lon = l.getLongitude();
if (l.hasAltitude()) {
if (!hasHeights) {
hasHeights = true;
}
float h = (float) l.getAltitude();
point.ele = h;
if (lastHeight == HEIGHT_UNDEFINED && seg.points.size() > 0) {
for (WptPt pt : seg.points) {
if (Double.isNaN(pt.ele)) {
pt.ele = h;
}
}
}
lastHeight = h;
}
seg.points.add(point);
}
track.segments.add(seg);
gpx.tracks.add(track);
String groupName = getMyApplication().getString(R.string.current_route);
GpxDisplayGroup group = getMyApplication().getSelectedGpxHelper().buildGpxDisplayGroup(gpx, 0, groupName);
if (group != null && group.getModifiableList().size() > 0) {
gpxItem = group.getModifiableList().get(0);
if (gpxItem != null) {
gpxItem.route = true;
}
}
}
}
private void buildHeader(View headerView) {
OsmandApplication app = getMyApplication();
final LineChart mChart = (LineChart) headerView.findViewById(R.id.chart);
GpxUiHelper.setupGPXChart(app, mChart, 4);
mChart.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
listView.requestDisallowInterceptTouchEvent(true);
return false;
}
});
GPXTrackAnalysis analysis = gpx.getAnalysis(0);
if (analysis.hasElevationData) {
List<ILineDataSet> dataSets = new ArrayList<>();
elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, mChart, analysis,
GPXDataSetAxisType.DISTANCE, false, true);
if (elevationDataSet != null) {
dataSets.add(elevationDataSet);
}
slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, mChart, analysis,
GPXDataSetAxisType.DISTANCE, elevationDataSet.getValues(), true, true);
if (slopeDataSet != null) {
dataSets.add(slopeDataSet);
}
LineData data = new LineData(dataSets);
mChart.setData(data);
mChart.setOnChartGestureListener(new OnChartGestureListener() {
float highlightDrawX = -1;
@Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
if (mChart.getHighlighted() != null && mChart.getHighlighted().length > 0) {
highlightDrawX = mChart.getHighlighted()[0].getDrawX();
} else {
highlightDrawX = -1;
}
}
@Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
gpxItem.chartMatrix = new Matrix(mChart.getViewPortHandler().getMatrixTouch());
Highlight[] highlights = mChart.getHighlighted();
if (highlights != null && highlights.length > 0) {
gpxItem.chartHighlightPos = highlights[0].getX();
} else {
gpxItem.chartHighlightPos = -1;
}
}
@Override
public void onChartLongPressed(MotionEvent me) {
}
@Override
public void onChartDoubleTapped(MotionEvent me) {
}
@Override
public void onChartSingleTapped(MotionEvent me) {
}
@Override
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {
}
@Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
}
@Override
public void onChartTranslate(MotionEvent me, float dX, float dY) {
if (highlightDrawX != -1) {
Highlight h = mChart.getHighlightByTouchPoint(highlightDrawX, 0f);
if (h != null) {
mChart.highlightValue(h);
}
}
}
});
mChart.setVisibility(View.VISIBLE);
} else {
elevationDataSet = null;
slopeDataSet = null;
mChart.setVisibility(View.GONE);
}
((TextView) headerView.findViewById(R.id.average_text))
.setText(OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app));
String min = OsmAndFormatter.getFormattedAlt(analysis.minElevation, app);
String max = OsmAndFormatter.getFormattedAlt(analysis.maxElevation, app);
((TextView) headerView.findViewById(R.id.range_text))
.setText(min + " - " + max);
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
((TextView) headerView.findViewById(R.id.descent_text)).setText(desc);
((TextView) headerView.findViewById(R.id.ascent_text)).setText(asc);
((ImageView) headerView.findViewById(R.id.average_icon))
.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_altitude_average));
((ImageView) headerView.findViewById(R.id.range_icon))
.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_altitude_average));
((ImageView) headerView.findViewById(R.id.descent_icon))
.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_altitude_descent));
((ImageView) headerView.findViewById(R.id.ascent_icon))
.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_altitude_ascent));
headerView.findViewById(R.id.details_view).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openDetails();
}
});
}
void openDetails() {
if (gpxItem != null) {
LatLon location = null;
WptPt wpt = null;
gpxItem.chartTypes = new GPXDataSetType[] { GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE };
if (gpxItem.chartHighlightPos != -1) {
TrkSegment segment = gpx.tracks.get(0).segments.get(0);
if (segment != null) {
float distance = gpxItem.chartHighlightPos * elevationDataSet.getDivX();
for (WptPt p : segment.points) {
if (p.distance >= distance) {
wpt = p;
break;
}
}
if (wpt != null) {
location = new LatLon(wpt.lat, wpt.lon);
}
}
}
if (location == null) {
location = new LatLon(gpxItem.locationStart.lat, gpxItem.locationStart.lon);
}
if (wpt != null) {
gpxItem.locationOnMap = wpt;
} else {
gpxItem.locationOnMap = gpxItem.locationStart;
}
final MapActivity activity = (MapActivity)getActivity();
if (activity != null) {
dismiss();
final OsmandSettings settings = activity.getMyApplication().getSettings();
settings.setMapLocationToShow(location.getLatitude(), location.getLongitude(),
settings.getLastKnownMapZoom(),
new PointDescription(PointDescription.POINT_TYPE_WPT, gpxItem.name),
false,
gpxItem);
final MapRouteInfoMenu mapRouteInfoMenu = activity.getMapLayers().getMapControlsLayer().getMapRouteInfoMenu();
if (MapRouteInfoMenu.isVisible()) {
// We arrived here by the route info menu.
// First, we close it and then show the details.
mapRouteInfoMenu.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
mapRouteInfoMenu.setOnDismissListener(null);
MapActivity.launchMapActivityMoveToTop(activity);
}
});
mapRouteInfoMenu.hide();
} else {
// We arrived here by the dashboard.
MapActivity.launchMapActivityMoveToTop(activity);
}
}
}
}
private void buildMenuButtons() {
IconsCache iconsCache = getMyApplication().getIconsCache();
ImageButton printRoute = (ImageButton) view.findViewById(R.id.print_route);
printRoute.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_gprint_dark));
printRoute.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
print();
}
});
ImageButton saveRoute = (ImageButton) view.findViewById(R.id.save_as_gpx);
saveRoute.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_gsave_dark));
saveRoute.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivityActions.createSaveDirections(getActivity(), helper).show();
}
});
ImageButton shareRoute = (ImageButton) view.findViewById(R.id.share_as_gpx);
shareRoute.setImageDrawable(iconsCache.getThemedIcon(R.drawable.ic_action_gshare_dark));
shareRoute.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final GPXFile gpx = helper.generateGPXFileWithRoute();
final Uri fileUri = Uri.fromFile(new File(gpx.path));
File dir = new File(getActivity().getCacheDir(), "share");
if (!dir.exists()) {
dir.mkdir();
}
File dst = new File(dir, "route.gpx");
try {
FileWriter fw = new FileWriter(dst);
GPXUtilities.writeGpx(fw, gpx, getMyApplication());
fw.close();
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(generateHtml(adapter,
helper.getGeneralRouteInformation()).toString()));
sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_route_subject));
sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
sendIntent.putExtra(
Intent.EXTRA_STREAM,
FileProvider.getUriForFile(getActivity(),
getActivity().getPackageName() + ".fileprovider", dst));
sendIntent.setType("text/plain");
startActivity(sendIntent);
} catch (IOException e) {
// Toast.makeText(getActivity(), "Error sharing favorites: " + e.getMessage(),
// Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
});
}
public static void showDialog(FragmentManager fragmentManager) {
ShowRouteInfoDialogFragment fragment = new ShowRouteInfoDialogFragment();
fragment.show(fragmentManager, TAG);
}
class RouteInfoAdapter extends ArrayAdapter<RouteDirectionInfo> {
public class CumulativeInfo {
public int distance;
public int time;
public CumulativeInfo() {
distance = 0;
time = 0;
}
}
private final int lastItemIndex;
private boolean light;
RouteInfoAdapter(List<RouteDirectionInfo> list) {
super(getActivity(), R.layout.route_info_list_item, list);
lastItemIndex = list.size() - 1;
this.setNotifyOnChange(false);
light = getMyApplication().getSettings().isLightContent();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater =
(LayoutInflater) getMyApplication().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.route_info_list_item, parent, false);
}
RouteDirectionInfo model = getItem(position);
TextView label = (TextView) row.findViewById(R.id.description);
TextView distanceLabel = (TextView) row.findViewById(R.id.distance);
TextView timeLabel = (TextView) row.findViewById(R.id.time);
TextView cumulativeDistanceLabel = (TextView) row.findViewById(R.id.cumulative_distance);
TextView cumulativeTimeLabel = (TextView) row.findViewById(R.id.cumulative_time);
ImageView icon = (ImageView) row.findViewById(R.id.direction);
row.findViewById(R.id.divider).setVisibility(position == getCount() - 1 ? View.INVISIBLE : View.VISIBLE);
TurnPathHelper.RouteDrawable drawable = new TurnPathHelper.RouteDrawable(getResources(), true);
drawable.setColorFilter(new PorterDuffColorFilter(light ? getResources().getColor(R.color.icon_color) : Color.WHITE, PorterDuff.Mode.SRC_ATOP));
drawable.setRouteType(model.getTurnType());
icon.setImageDrawable(drawable);
label.setText(String.valueOf(position + 1) + ". " + model.getDescriptionRoutePart());
if (model.distance > 0) {
distanceLabel.setText(OsmAndFormatter.getFormattedDistance(
model.distance, getMyApplication()));
timeLabel.setText(getTimeDescription(model));
row.setContentDescription(label.getText() + " " + timeLabel.getText()); //$NON-NLS-1$
} else {
if (label.getText().equals(String.valueOf(position + 1) + ". ")) {
label.setText(String.valueOf(position + 1) + ". " + getString((position != lastItemIndex) ? R.string.arrived_at_intermediate_point : R.string.arrived_at_destination));
}
distanceLabel.setText(""); //$NON-NLS-1$
timeLabel.setText(""); //$NON-NLS-1$
row.setContentDescription(""); //$NON-NLS-1$
}
CumulativeInfo cumulativeInfo = getRouteDirectionCumulativeInfo(position);
cumulativeDistanceLabel.setText(OsmAndFormatter.getFormattedDistance(
cumulativeInfo.distance, getMyApplication()));
cumulativeTimeLabel.setText(Algorithms.formatDuration(cumulativeInfo.time, getMyApplication().accessibilityEnabled()));
return row;
}
public CumulativeInfo getRouteDirectionCumulativeInfo(int position) {
CumulativeInfo cumulativeInfo = new CumulativeInfo();
for (int i = 0; i < position; i++) {
RouteDirectionInfo routeDirectionInfo = (RouteDirectionInfo) getItem(i);
cumulativeInfo.time += routeDirectionInfo.getExpectedTime();
cumulativeInfo.distance += routeDirectionInfo.distance;
}
return cumulativeInfo;
}
}
private String getTimeDescription(RouteDirectionInfo model) {
final int timeInSeconds = model.getExpectedTime();
return Algorithms.formatDuration(timeInSeconds, getMyApplication().accessibilityEnabled());
}
void print() {
File file = generateRouteInfoHtml(adapter, helper.getGeneralRouteInformation());
if (file.exists()) {
Uri uri = Uri.fromFile(file);
Intent browserIntent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // use Android Print Framework
browserIntent = new Intent(getActivity(), PrintDialogActivity.class)
.setDataAndType(uri, "text/html");
} else { // just open html document
browserIntent = new Intent(Intent.ACTION_VIEW).setDataAndType(
uri, "text/html");
}
startActivity(browserIntent);
}
}
private File generateRouteInfoHtml(RouteInfoAdapter routeInfo, String title) {
File file = null;
if (routeInfo == null) {
return file;
}
final String fileName = "route_info.html";
StringBuilder html = generateHtmlPrint(routeInfo, title);
FileOutputStream fos = null;
try {
file = getMyApplication().getAppPath(fileName);
fos = new FileOutputStream(file);
fos.write(html.toString().getBytes("UTF-8"));
fos.flush();
} catch (IOException e) {
file = null;
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (Exception e) {
file = null;
e.printStackTrace();
}
}
}
return file;
}
private StringBuilder generateHtml(RouteInfoAdapter routeInfo, String title) {
StringBuilder html = new StringBuilder();
if (!TextUtils.isEmpty(title)) {
html.append("<h1>");
html.append(title);
html.append("</h1>");
}
final String NBSP = " ";
final String BR = "<br>";
for (int i = 0; i < routeInfo.getCount(); i++) {
RouteDirectionInfo routeDirectionInfo = (RouteDirectionInfo) routeInfo.getItem(i);
StringBuilder sb = new StringBuilder();
sb.append(OsmAndFormatter.getFormattedDistance(routeDirectionInfo.distance, getMyApplication()));
sb.append(", ").append(NBSP);
sb.append(getTimeDescription(routeDirectionInfo));
String distance = sb.toString().replaceAll("\\s", NBSP);
String description = routeDirectionInfo.getDescriptionRoutePart();
html.append(BR);
html.append("<p>" + String.valueOf(i + 1) + ". " + NBSP + description + NBSP + "(" + distance + ")</p>");
}
return html;
}
private StringBuilder generateHtmlPrint(RouteInfoAdapter routeInfo, String title) {
StringBuilder html = new StringBuilder();
html.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
html.append("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">");
html.append("<head>");
html.append("<title>Route info</title>");
html.append("<meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />");
html.append("<style>");
html.append("table, th, td {");
html.append("border: 1px solid black;");
html.append("border-collapse: collapse;}");
html.append("th, td {");
html.append("padding: 5px;}");
html.append("</style>");
html.append("</head>");
html.append("<body>");
if (!TextUtils.isEmpty(title)) {
html.append("<h1>");
html.append(title);
html.append("</h1>");
}
html.append("<table style=\"width:100%\">");
final String NBSP = " ";
final String BR = "<br>";
for (int i = 0; i < routeInfo.getCount(); i++) {
RouteDirectionInfo routeDirectionInfo = (RouteDirectionInfo) routeInfo.getItem(i);
html.append("<tr>");
StringBuilder sb = new StringBuilder();
sb.append(OsmAndFormatter.getFormattedDistance(routeDirectionInfo.distance, getMyApplication()));
sb.append(", ");
sb.append(getTimeDescription(routeDirectionInfo));
String distance = sb.toString().replaceAll("\\s", NBSP);
html.append("<td>");
html.append(distance);
html.append("</td>");
String description = routeDirectionInfo.getDescriptionRoutePart();
html.append("<td>");
html.append(String.valueOf(i + 1) + ". " + description);
html.append("</td>");
RouteInfoAdapter.CumulativeInfo cumulativeInfo = routeInfo.getRouteDirectionCumulativeInfo(i);
html.append("<td>");
sb = new StringBuilder();
sb.append(OsmAndFormatter.getFormattedDistance(cumulativeInfo.distance, getMyApplication()));
sb.append(" - ");
sb.append(OsmAndFormatter.getFormattedDistance(cumulativeInfo.distance + routeDirectionInfo.distance,
getMyApplication()));
sb.append(BR);
sb.append(Algorithms.formatDuration(cumulativeInfo.time, getMyApplication().accessibilityEnabled()));
sb.append(" - ");
sb.append(Algorithms.formatDuration(cumulativeInfo.time + routeDirectionInfo.getExpectedTime(),
getMyApplication().accessibilityEnabled()));
String cumulativeTimeAndDistance = sb.toString().replaceAll("\\s", NBSP);
html.append(cumulativeTimeAndDistance);
html.append("</td>");
html.append("</tr>");
}
html.append("</table>");
html.append("</body>");
html.append("</html>");
return html;
}
}