diff --git a/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java b/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java
index d70d83cf3a..28384d0bcb 100644
--- a/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java
+++ b/OsmAnd-java/src/main/java/net/osmand/binary/RouteDataObject.java
@@ -676,7 +676,72 @@ public class RouteDataObject {
}
return false;
}
-
+
+ public boolean isExitPoint() {
+ if (pointTypes != null) {
+ int ptSz = pointTypes.length;
+ for (int i = 0; i < ptSz; i++) {
+ int[] point = pointTypes[i];
+ if (point != null) {
+ int pSz = point.length;
+ for (int j = 0; j < pSz; j++) {
+ if (region.routeEncodingRules.get(point[j]).getValue().equals("motorway_junction")) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+// public boolean isMotorWayLink() {
+// int sz = types.length;
+// for (int i = 0; i < sz; i++) {
+// RouteTypeRule r = region.quickGetEncodingRule(types[i]);
+// if (r.getTag().equals("highway") && r.getValue().equals("motorway_link")) {
+// return true;
+// }
+// }
+// return false;
+// }
+
+ public String getExitName() {
+ if (pointNames != null && pointNameTypes != null) {
+ int pnSz = pointNames.length;
+ for (int i = 0; i < pnSz; i++) {
+ String[] point = pointNames[i];
+ if (point != null) {
+ int pSz = point.length;
+ for (int j = 0; j < pSz; j++) {
+ if (pointNameTypes[i][j] == region.nameTypeRule) {
+ return point[j];
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public String getExitRef() {
+ if (pointNames != null && pointNameTypes != null) {
+ int pnSz = pointNames.length;
+ for (int i = 0; i < pnSz; i++) {
+ String[] point = pointNames[i];
+ if (point != null) {
+ int pSz = point.length;
+ for (int j = 0; j < pSz; j++) {
+ if (pointNameTypes[i][j] == region.refTypeRule) {
+ return point[j];
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
public int getOneway() {
int sz = types.length;
for (int i = 0; i < sz; i++) {
diff --git a/OsmAnd-java/src/main/java/net/osmand/router/ExitInfo.java b/OsmAnd-java/src/main/java/net/osmand/router/ExitInfo.java
new file mode 100644
index 0000000000..3f51d0f9d0
--- /dev/null
+++ b/OsmAnd-java/src/main/java/net/osmand/router/ExitInfo.java
@@ -0,0 +1,25 @@
+package net.osmand.router;
+
+
+public class ExitInfo {
+
+ private String ref;
+
+ private String exitStreetName;
+
+ public String getRef() {
+ return ref;
+ }
+
+ public void setRef(String ref) {
+ this.ref = ref;
+ }
+
+ public String getExitStreetName() {
+ return exitStreetName;
+ }
+
+ public void setExitStreetName(String exitStreetName) {
+ this.exitStreetName = exitStreetName;
+ }
+}
diff --git a/OsmAnd/res/drawable/bg_topbar_shield_exit_ref.xml b/OsmAnd/res/drawable/bg_topbar_shield_exit_ref.xml
new file mode 100644
index 0000000000..fff0e2dbf0
--- /dev/null
+++ b/OsmAnd/res/drawable/bg_topbar_shield_exit_ref.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/OsmAnd/res/layout-land/map_hud_top.xml b/OsmAnd/res/layout-land/map_hud_top.xml
index f017986c92..e74c33eec6 100644
--- a/OsmAnd/res/layout-land/map_hud_top.xml
+++ b/OsmAnd/res/layout-land/map_hud_top.xml
@@ -335,43 +335,74 @@
android:background="@drawable/btn_round"
android:minHeight="@dimen/map_address_height">
-
+
+
+ android:background="@drawable/bg_topbar_shield_exit_ref"
+ android:gravity="center"
+ android:minWidth="@dimen/map_widget_height"
+ android:textColor="@color/color_white"
+ android:textSize="@dimen/map_widget_text_size"
+ android:visibility="gone"
+ tools:text="8"
+ tools:visibility="visible" />
-
+
+
+
+
-
+ android:layout_height="wrap_content">
-
-
+
+
-
+
+
+
-
-
+
+
+
-
+ tools:visibility="visible" />
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+ android:orientation="vertical">
+
+
+
+
+
+
diff --git a/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java b/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java
index 9d600c4c1f..6592198107 100644
--- a/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java
+++ b/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java
@@ -49,6 +49,8 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
@@ -389,6 +391,11 @@ public class OsmandRenderer {
}
}
+ public Drawable getShieldDrawable(String shieldId){
+ Bitmap shield = RenderingIcons.getIcon(context, shieldId, true);
+ return new BitmapDrawable(context.getResources(),shield);
+ }
+
protected void drawBitmap(Canvas cv, Bitmap ico, RectF rf) {
if(ico == null) {
return;
diff --git a/OsmAnd/src/net/osmand/plus/render/TextRenderer.java b/OsmAnd/src/net/osmand/plus/render/TextRenderer.java
index 429db5200b..4df7d5db34 100644
--- a/OsmAnd/src/net/osmand/plus/render/TextRenderer.java
+++ b/OsmAnd/src/net/osmand/plus/render/TextRenderer.java
@@ -43,7 +43,7 @@ public class TextRenderer {
private Typeface italicTypeface;
private Typeface boldTypeface;
- static class TextDrawInfo {
+ public static class TextDrawInfo {
public TextDrawInfo(String text) {
this.text = text;
@@ -95,6 +95,30 @@ public class TextRenderer {
}
textOrder = render.getIntPropertyValue(render.ALL.R_TEXT_ORDER, 100);
}
+
+ public float getCenterX() {
+ return centerX;
+ }
+
+ public void setCenterX(float centerX) {
+ this.centerX = centerX;
+ }
+
+ public float getCenterY() {
+ return centerY;
+ }
+
+ public void setCenterY(float centerY) {
+ this.centerY = centerY;
+ }
+
+ public String getShieldResIcon() {
+ return shieldResIcon;
+ }
+
+ public void setShieldResIcon(String shieldResIcon) {
+ this.shieldResIcon = shieldResIcon;
+ }
}
public TextRenderer(Context context) {
@@ -288,13 +312,13 @@ public class TextRenderer {
}
}
- private void drawShieldIcon(RenderingContext rc, Canvas cv, TextDrawInfo text, String sr) {
+ public void drawShieldIcon(RenderingContext rc, Canvas cv, TextDrawInfo text, String sr) {
if (sr != null) {
float coef = rc.getDensityValue(rc.screenDensityRatio * rc.textScale);
Bitmap ico = RenderingIcons.getIcon(context, sr, true);
if (ico != null) {
- float left = text.centerX - ico.getWidth() / 2 * coef - 0.5f;
- float top = text.centerY - ico.getHeight() / 2 * coef - paintText.descent() - 0.5f;
+ float left = text.centerX - ico.getWidth() / 2 * coef;// - 0.5f;
+ float top = text.centerY - ico.getHeight() / 2 * coef - paintText.descent() * 1.5f;
if(rc.screenDensityRatio != 1f){
RectF rf = new RectF(left, top, left + ico.getWidth() * coef,
top + ico.getHeight() * coef);
@@ -308,7 +332,7 @@ public class TextRenderer {
}
}
- private void drawWrappedText(Canvas cv, TextDrawInfo text, float textSize) {
+ public void drawWrappedText(Canvas cv, TextDrawInfo text, float textSize) {
if (text.textWrap == 0) {
// set maximum for all text
text.textWrap = 40;
diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteDirectionsCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteDirectionsCard.java
index 09380e43d6..d56950cf6f 100644
--- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteDirectionsCard.java
+++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteDirectionsCard.java
@@ -17,6 +17,7 @@ import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.routepreparationmenu.RouteDetailsFragment;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.views.TurnPathHelper;
+import net.osmand.plus.views.mapwidgets.RouteInfoWidgetsFactory;
import net.osmand.util.Algorithms;
import java.util.List;
@@ -67,13 +68,25 @@ public class RouteDirectionsCard extends BaseCard {
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);
+ ImageView directionIcon = (ImageView) row.findViewById(R.id.direction);
+ ImageView lanesIcon = (ImageView) row.findViewById(R.id.lanes);
row.findViewById(R.id.divider).setVisibility(directionInfoIndex == directionsInfo.size() - 1 ? View.INVISIBLE : View.VISIBLE);
TurnPathHelper.RouteDrawable drawable = new TurnPathHelper.RouteDrawable(mapActivity.getResources(), true);
drawable.setColorFilter(new PorterDuffColorFilter(getActiveColor(), PorterDuff.Mode.SRC_ATOP));
drawable.setRouteType(model.getTurnType());
- icon.setImageDrawable(drawable);
+ directionIcon.setImageDrawable(drawable);
+
+ int[] lanes = model.getTurnType().getLanes();
+ if (lanes != null){
+ RouteInfoWidgetsFactory.LanesDrawable lanesDrawable = new RouteInfoWidgetsFactory.LanesDrawable(mapActivity,1);
+ lanesDrawable.lanes = lanes;
+ lanesDrawable.isTurnByTurn = true;
+ lanesDrawable.isNightMode = nightMode;
+ lanesDrawable.updateBounds();
+ lanesIcon.setImageDrawable(lanesDrawable);
+ lanesIcon.setVisibility(View.VISIBLE);
+ }
label.setText(model.getDescriptionRoutePart());
if (model.distance > 0) {
diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java
index 198b3c8cff..2faaca1a3a 100644
--- a/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java
+++ b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java
@@ -4,6 +4,7 @@ import android.content.Context;
import android.support.annotation.Nullable;
import net.osmand.Location;
+import net.osmand.PlatformUtil;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
import net.osmand.binary.RouteDataObject;
@@ -14,12 +15,15 @@ import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.routing.AlarmInfo.AlarmInfoType;
+import net.osmand.router.ExitInfo;
import net.osmand.router.RouteSegmentResult;
import net.osmand.router.RoutingContext;
import net.osmand.router.TurnType;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
+import org.apache.commons.logging.Log;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -27,6 +31,8 @@ import java.util.List;
import static net.osmand.binary.RouteDataObject.HEIGHT_UNDEFINED;
public class RouteCalculationResult {
+ private final static Log log = PlatformUtil.getLog(RouteCalculationResult.class);
+
private static double distanceClosestToIntermediate = 3000;
private static double distanceThresholdToIntermediate = 25;
// could not be null and immodifiable!
@@ -318,15 +324,55 @@ public class RouteCalculationResult {
info.routeEndPointOffset = roundAboutEnd;
}
RouteSegmentResult next = list.get(lind);
- info.setRef(next.getObject().getRef(ctx.getSettings().MAP_PREFERRED_LOCALE.get(),
- ctx.getSettings().MAP_TRANSLITERATE_NAMES.get(), next.isForwardDirection()));
+ String ref = next.getObject().getRef(ctx.getSettings().MAP_PREFERRED_LOCALE.get(),
+ ctx.getSettings().MAP_TRANSLITERATE_NAMES.get(), next.isForwardDirection());
+ info.setRef(ref);
info.setStreetName(next.getObject().getName(ctx.getSettings().MAP_PREFERRED_LOCALE.get(),
ctx.getSettings().MAP_TRANSLITERATE_NAMES.get()));
info.setDestinationName(next.getObject().getDestinationName(ctx.getSettings().MAP_PREFERRED_LOCALE.get(),
ctx.getSettings().MAP_TRANSLITERATE_NAMES.get(), next.isForwardDirection()));
+ if (s.getObject().isExitPoint() && next.getObject().getHighway().equals("motorway_link")) {
+ ExitInfo exitInfo = new ExitInfo();
+ exitInfo.setRef(next.getObject().getExitRef());
+ exitInfo.setExitStreetName(next.getObject().getExitName());
+ info.setExitInfo(exitInfo);
+ }
+
+ if (ref != null) {
+ RouteDataObject nextRoad = next.getObject();
+ boolean isNextShieldFound = false;
+ int[] nextSegmentNameIds = nextRoad.nameIds;
+ for (int nm = 0; nm < nextSegmentNameIds.length; nm++) {
+ if (nextRoad.region.quickGetEncodingRule(nextSegmentNameIds[nm]).getTag().startsWith("road_ref")) {
+ info.setRouteDataObject(nextRoad);
+ isNextShieldFound = true;
+ }
+ }
+
+ if (!isNextShieldFound) {
+ for (int ind = lind; ind < list.size(); ind++) {
+ if (list.get(ind).getTurnType() != null) {
+ info.setRouteDataObject(null);
+ break;
+ } else {
+ RouteDataObject obj = list.get(ind).getObject();
+ int[] nameIds = obj.nameIds;
+ for (int idx = 0; idx < nameIds.length; idx ++) {
+ if (obj.region.routeEncodingRules.get(obj.nameIds[idx]).getTag().startsWith("road_ref")) {
+ info.setRouteDataObject(obj);
+ break;
+ }
+ }
+ if (info.getRouteDataObject() != null) {
+ break;
+ }
+ }
+ }
+ }
+ }
}
- String description = toString(turn, ctx, false) + " " + RoutingHelper.formatStreetName(info.getStreetName(),
+ String description = toString(turn, ctx, false) + " " + RoutingHelper.formatStreetName(info.getStreetName(),
info.getRef(), info.getDestinationName(), ctx.getString(R.string.towards));
description = description.trim();
String[] pointNames = s.getObject().getPointNames(s.getStartPointIndex());
diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteDirectionInfo.java b/OsmAnd/src/net/osmand/plus/routing/RouteDirectionInfo.java
index f83be5ce3b..9c503ccd82 100644
--- a/OsmAnd/src/net/osmand/plus/routing/RouteDirectionInfo.java
+++ b/OsmAnd/src/net/osmand/plus/routing/RouteDirectionInfo.java
@@ -1,7 +1,11 @@
package net.osmand.plus.routing;
+import android.support.annotation.Nullable;
+
+import net.osmand.binary.RouteDataObject;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
+import net.osmand.router.ExitInfo;
import net.osmand.router.TurnType;
public class RouteDirectionInfo {
@@ -15,13 +19,18 @@ public class RouteDirectionInfo {
private String descriptionRoute = ""; //$NON-NLS-1$
// Speed after the action till next turn
private float averageSpeed;
-
+
private String ref;
-
+
private String streetName;
-
+
private String destinationName;
+ private RouteDataObject routeDataObject = null;
+
+ @Nullable
+ private ExitInfo exitInfo;
+
public String getDestinationName() {
return destinationName;
}
@@ -35,14 +44,22 @@ public class RouteDirectionInfo {
this.averageSpeed = averageSpeed == 0 ? 1 : averageSpeed;
this.turnType = turnType;
}
-
+
+ public RouteDataObject getRouteDataObject() {
+ return routeDataObject;
+ }
+
+ public void setRouteDataObject(RouteDataObject routeDataObject) {
+ this.routeDataObject = routeDataObject;
+ }
+
public String getDescriptionRoute(OsmandApplication ctx) {
if (!descriptionRoute.endsWith(OsmAndFormatter.getFormattedDistance(distance, ctx))) {
descriptionRoute += " " + OsmAndFormatter.getFormattedDistance(distance, ctx);
}
return descriptionRoute.trim();
}
-
+
public String getDescriptionRoute(OsmandApplication ctx, int collectedDistance) {
if (!descriptionRoute.endsWith(OsmAndFormatter.getFormattedDistance(collectedDistance, ctx))) {
descriptionRoute += " " + OsmAndFormatter.getFormattedDistance(collectedDistance, ctx);
@@ -69,7 +86,7 @@ public class RouteDirectionInfo {
public void setStreetName(String streetName) {
this.streetName = streetName;
}
-
+
public void setDescriptionRoute(String descriptionRoute) {
this.descriptionRoute = descriptionRoute;
}
@@ -87,11 +104,11 @@ public class RouteDirectionInfo {
return (int) Math.round(distance / averageSpeed);
}
-
+
public TurnType getTurnType() {
return turnType;
}
-
+
// calculated vars
// after action (excluding expectedTime)
@@ -104,6 +121,15 @@ public class RouteDirectionInfo {
}
public void setDistance(int distance) {
- this.distance = distance;
+ this.distance = distance;
}
-}
+
+ @Nullable
+ public ExitInfo getExitInfo() {
+ return exitInfo;
+ }
+
+ public void setExitInfo(@Nullable ExitInfo exitInfo) {
+ this.exitInfo = exitInfo;
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java
index ce4a7861ec..0cfff0e39f 100644
--- a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java
+++ b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java
@@ -835,12 +835,12 @@ public class RoutingHelper {
if(n.distanceTo > 0 && n.directionInfo != null && !n.directionInfo.getTurnType().isSkipToSpeak() &&
voiceRouter.isDistanceLess(speed, n.distanceTo, voiceRouter.PREPARE_DISTANCE * 0.75f, 0f)) {
String nm = n.directionInfo.getStreetName();
- String rf = n.directionInfo.getRef();
+// String rf = n.directionInfo.getRef();
String dn = n.directionInfo.getDestinationName();
if(next != null) {
next[0] = n.directionInfo.getTurnType();
}
- return formatStreetName(nm, rf, dn, "»");
+ return formatStreetName(nm, null, dn, "»");
}
RouteSegmentResult rs = getCurrentSegmentResult();
if(rs != null) {
@@ -864,10 +864,10 @@ public class RoutingHelper {
private String getRouteSegmentStreetName(RouteSegmentResult rs) {
String nm = rs.getObject().getName(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get());
- String rf = rs.getObject().getRef(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get(), rs.isForwardDirection());
+// String rf = rs.getObject().getRef(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get(), rs.isForwardDirection());
String dn = rs.getObject().getDestinationName(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), rs.isForwardDirection());
- return formatStreetName(nm, rf, dn, "»");
+ return formatStreetName(nm, null, dn, "»");
}
public RouteSegmentResult getCurrentSegmentResult() {
diff --git a/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java b/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java
index a05ebe5a40..80a2945f88 100644
--- a/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java
+++ b/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java
@@ -16,6 +16,7 @@ import net.osmand.plus.routing.data.StreetName;
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
import net.osmand.plus.voice.CommandBuilder;
import net.osmand.plus.voice.CommandPlayer;
+import net.osmand.router.ExitInfo;
import net.osmand.router.RouteSegmentResult;
import net.osmand.router.TurnType;
import net.osmand.util.MapUtils;
@@ -618,13 +619,29 @@ public class VoiceRouter {
}
} else {
- result.put("toRef", getNonNullString(getSpeakablePointName(i.getRef())));
+ result.put(TO_REF, getNonNullString(getSpeakablePointName(i.getRef())));
result.put(TO_STREET_NAME, getNonNullString(getSpeakablePointName(i.getStreetName())));
result.put(TO_DEST, "");
}
return new StreetName(result);
}
+ private StreetName getSpeakableExitName(RouteDirectionInfo routeInfo, ExitInfo exitInfo, boolean includeDest) {
+ Map result = new HashMap<>();
+ if (exitInfo == null || !router.getSettings().SPEAK_STREET_NAMES.get()) {
+ return new StreetName(result);
+ }
+ if (player != null && player.supportsStructuredStreetNames()) {
+ result.put(TO_REF, getNonNullString(getSpeakablePointName(exitInfo.getRef())));
+ result.put(TO_STREET_NAME, getNonNullString(getSpeakablePointName(exitInfo.getExitStreetName())));
+ result.put(TO_DEST, includeDest ? getNonNullString(getSpeakablePointName(routeInfo.getRef())) : "");
+ } else {
+ result.put(TO_REF, getNonNullString(getSpeakablePointName(exitInfo.getRef())));
+ result.put(TO_STREET_NAME, getNonNullString(getSpeakablePointName(exitInfo.getExitStreetName())));
+ result.put(TO_DEST, "");
+ }
+ return new StreetName(result);
+ }
private String getNonNullString(String speakablePointName) {
return speakablePointName == null ? "" : speakablePointName;
@@ -677,8 +694,14 @@ public class VoiceRouter {
if (p != null) {
String tParam = getTurnType(next.getTurnType());
boolean isPlay = true;
+ ExitInfo exitInfo = next.getExitInfo();
+ String lang = player.getLanguage();
if (tParam != null) {
- p.turn(tParam, dist, getSpeakableStreetName(currentSegment, next, true));
+ if (exitInfo != null) {
+ p.takeExit(tParam, dist, getSpeakableExitName(next, exitInfo, true));
+ } else {
+ p.turn(tParam, dist, getSpeakableStreetName(currentSegment, next, true));
+ }
suppressDest = true;
} else if (next.getTurnType().isRoundAbout()) {
p.roundAbout(dist, next.getTurnType().getTurnAngle(), next.getTurnType().getExitOut(), getSpeakableStreetName(currentSegment, next, true));
@@ -744,9 +767,15 @@ public class VoiceRouter {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
String tParam = getTurnType(next.getTurnType());
+ ExitInfo exitInfo = next.getExitInfo();
boolean isplay = true;
+ String lang = player.getLanguage();
if (tParam != null) {
- p.turn(tParam, getSpeakableStreetName(currentSegment, next, !suppressDest));
+ if (exitInfo != null) {
+ p.takeExit(tParam, getSpeakableExitName(next, exitInfo, !suppressDest));
+ } else {
+ p.turn(tParam, getSpeakableStreetName(currentSegment, next, !suppressDest));
+ }
} else if (next.getTurnType().isRoundAbout()) {
p.roundAbout(next.getTurnType().getTurnAngle(), next.getTurnType().getExitOut(), getSpeakableStreetName(currentSegment, next, !suppressDest));
} else if (next.getTurnType().getValue() == TurnType.TU || next.getTurnType().getValue() == TurnType.TRU) {
diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapInfoWidgetsFactory.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapInfoWidgetsFactory.java
index a58672ae60..2752dc3dc3 100644
--- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapInfoWidgetsFactory.java
+++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapInfoWidgetsFactory.java
@@ -1,13 +1,15 @@
package net.osmand.plus.views.mapwidgets;
-import android.animation.LayoutTransition;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.Bundle;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
@@ -19,6 +21,7 @@ import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.SwitchCompat;
import android.text.ClipboardManager;
+import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -34,6 +37,8 @@ import com.jwetherell.openmap.common.UTMPoint;
import net.osmand.AndroidUtils;
import net.osmand.Location;
import net.osmand.LocationConvert;
+import net.osmand.PlatformUtil;
+import net.osmand.binary.BinaryMapRouteReaderAdapter;
import net.osmand.binary.RouteDataObject;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
@@ -52,8 +57,11 @@ import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.WaypointDialogHelper;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.helpers.WaypointHelper.LocationPointWrapper;
+import net.osmand.plus.render.OsmandRenderer;
+import net.osmand.plus.render.TextRenderer;
import net.osmand.plus.routepreparationmenu.MapRouteInfoMenu;
import net.osmand.plus.routepreparationmenu.ShowAlongTheRouteBottomSheet;
+import net.osmand.plus.routing.RouteCalculationResult;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.OsmandMapLayer.DrawSettings;
@@ -61,10 +69,15 @@ import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.RulerControlLayer;
import net.osmand.plus.views.mapwidgets.MapWidgetRegistry.WidgetState;
import net.osmand.plus.views.mapwidgets.NextTurnInfoWidget.TurnDrawable;
+import net.osmand.render.RenderingRuleSearchRequest;
+import net.osmand.render.RenderingRulesStorage;
+import net.osmand.router.ExitInfo;
import net.osmand.router.TurnType;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
+import org.apache.commons.logging.Log;
+
import java.util.Iterator;
import java.util.LinkedList;
@@ -903,6 +916,9 @@ public class MapInfoWidgetsFactory {
private View topBar;
private TextView addressText;
private TextView addressTextShadow;
+ private TextView exitRefText;
+ private ImageView shieldIcon;
+ private ImageView turnIcon;
private OsmAndLocationProvider locationProvider;
private WaypointHelper waypointHelper;
private OsmandSettings settings;
@@ -911,12 +927,16 @@ public class MapInfoWidgetsFactory {
private TurnDrawable turnDrawable;
private boolean showMarker;
private int shadowRad;
+ private static final Log LOG = PlatformUtil.getLog(TopTextView.class);
public TopTextView(OsmandApplication app, MapActivity map) {
topBar = map.findViewById(R.id.map_top_bar);
addressText = (TextView) map.findViewById(R.id.map_address_text);
addressTextShadow = (TextView) map.findViewById(R.id.map_address_text_shadow);
waypointInfoBar = map.findViewById(R.id.waypoint_info_bar);
+ exitRefText = map.findViewById(R.id.map_exit_ref);
+ shieldIcon = map.findViewById(R.id.map_shield_icon);
+ turnIcon = map.findViewById(R.id.map_turn_icon);
this.routingHelper = app.getRoutingHelper();
locationProvider = app.getLocationProvider();
this.map = map;
@@ -940,6 +960,8 @@ public class MapInfoWidgetsFactory {
TextInfoWidget.updateTextColor((TextView) waypointInfoBar.findViewById(R.id.waypoint_text),
(TextView) waypointInfoBar.findViewById(R.id.waypoint_text_shadow),
textColor, textShadowColor, bold, rad / 2);
+ exitRefText.setTextColor(nightMode ? map.getResources().getColor(R.color.text_color_primary_dark) :
+ map.getResources().getColor(R.color.color_white));
ImageView all = (ImageView) waypointInfoBar.findViewById(R.id.waypoint_more);
ImageView remove = (ImageView) waypointInfoBar.findViewById(R.id.waypoint_close);
@@ -955,6 +977,11 @@ public class MapInfoWidgetsFactory {
TurnType[] type = new TurnType[1];
boolean showNextTurn = false;
boolean showMarker = this.showMarker;
+ boolean showExitInfo = false;
+ boolean showShield = false;
+ ExitInfo exitInfo = null;
+ RouteDataObject object = null;
+
if (routingHelper != null && routingHelper.isRouteCalculated() && !routingHelper.isDeviatedFromRoute()) {
if (routingHelper.isFollowingMode()) {
if (settings.SHOW_STREET_NAME.get()) {
@@ -968,6 +995,25 @@ public class MapInfoWidgetsFactory {
turnDrawable.setColor(R.color.nav_arrow);
}
}
+ RouteCalculationResult.NextDirectionInfo nextDirInfo = routingHelper.getNextRouteDirectionInfo(
+ new RouteCalculationResult.NextDirectionInfo(), true);
+ RouteDirectionInfo directionInfo = nextDirInfo.directionInfo;
+
+ if (directionInfo != null && directionInfo.getExitInfo() != null) {
+ exitInfo = directionInfo.getExitInfo();
+ showExitInfo = true;
+ } else {
+ showExitInfo = false;
+ }
+
+ if (showExitInfo) {
+ text = exitInfo.getExitStreetName();
+ }
+
+ if (nextDirInfo.directionInfo.getRouteDataObject() != null) {
+ object = nextDirInfo.directionInfo.getRouteDataObject();
+ showShield = true;
+ }
}
} else {
int di = MapRouteInfoMenu.getDirectionInfo();
@@ -977,10 +1023,7 @@ public class MapInfoWidgetsFactory {
RouteDirectionInfo next = routingHelper.getRouteDirections().get(di);
type[0] = next.getTurnType();
turnDrawable.setColor(R.color.nav_arrow_distant);
- text = RoutingHelper.formatStreetName(next.getStreetName(), next.getRef(), next.getDestinationName(), "»");
-// if (next.distance > 0) {
-// text += " " + OsmAndFormatter.getFormattedDistance(next.distance, map.getMyApplication());
-// }
+ text = RoutingHelper.formatStreetName(next.getStreetName(), null, next.getDestinationName(), "»");
if (text == null) {
text = "";
}
@@ -1029,25 +1072,37 @@ public class MapInfoWidgetsFactory {
AndroidUiHelper.updateVisibility(addressTextShadow, shadowRad > 0);
boolean update = turnDrawable.setTurnType(type[0]) || showMarker != this.showMarker;
this.showMarker = showMarker;
- int h = addressText.getHeight() / 4 * 3;
- if (h != turnDrawable.getBounds().bottom) {
- turnDrawable.setBounds(0, 0, h, h);
+ if (showShield) {
+ if (setRoadShield(shieldIcon, object)) {
+ AndroidUiHelper.updateVisibility(shieldIcon, true);
+ } else {
+ AndroidUiHelper.updateVisibility(shieldIcon, false);
+ }
+ } else {
+ AndroidUiHelper.updateVisibility(shieldIcon, false);
+ }
+
+ if (showExitInfo) {
+ String exitRef = exitInfo.getRef();
+ if (!Algorithms.isEmpty(exitRef)) {
+ exitRefText.setText(exitRef);
+ AndroidUiHelper.updateVisibility(exitRefText, true);
+ } else {
+ AndroidUiHelper.updateVisibility(exitRefText, false);
+ }
+ } else {
+ AndroidUiHelper.updateVisibility(exitRefText, false);
}
if (update) {
if (type[0] != null) {
- addressTextShadow.setCompoundDrawables(turnDrawable, null, null, null);
- addressTextShadow.setCompoundDrawablePadding(4);
- addressText.setCompoundDrawables(turnDrawable, null, null, null);
- addressText.setCompoundDrawablePadding(4);
+ turnIcon.setImageDrawable(turnDrawable);
+ AndroidUiHelper.updateVisibility(turnIcon, true);
} else if (showMarker) {
Drawable marker = map.getMyApplication().getUIUtilities().getIcon(R.drawable.ic_action_start_navigation, R.color.color_myloc_distance);
- addressTextShadow.setCompoundDrawablesWithIntrinsicBounds(marker, null, null, null);
- addressTextShadow.setCompoundDrawablePadding(4);
- addressText.setCompoundDrawablesWithIntrinsicBounds(marker, null, null, null);
- addressText.setCompoundDrawablePadding(4);
+ turnIcon.setImageDrawable(marker);
+ AndroidUiHelper.updateVisibility(turnIcon, true);
} else {
- addressTextShadow.setCompoundDrawables(null, null, null, null);
- addressText.setCompoundDrawables(null, null, null, null);
+ AndroidUiHelper.updateVisibility(turnIcon, false);
}
}
if (!text.equals(addressText.getText().toString())) {
@@ -1059,6 +1114,102 @@ public class MapInfoWidgetsFactory {
return false;
}
+ private boolean setRoadShield(ImageView view, RouteDataObject object) {
+
+ String nameTag = null;
+ String name = null;
+ StringBuilder additional = new StringBuilder();
+ for (int i = 0; i < object.nameIds.length; i++) {
+ String key = object.region.routeEncodingRules.get(object.nameIds[i]).getTag();
+ String val = object.names.get(object.nameIds[i]);
+ if (key.startsWith("road_ref")) {
+ nameTag = key;
+ name = val;
+ } else {
+ additional.append(key).append("=").append(val).append(";");
+ }
+ }
+// LOG.debug("Additionals (names): " + additional.toString() );
+
+ Context context = topBar.getContext();
+ int[] tps = object.getTypes();
+ OsmandApplication app = ((OsmandApplication) context.getApplicationContext());
+ RenderingRulesStorage storage = app.getRendererRegistry().getCurrentSelectedRenderer();
+ boolean nightMode = app.getDaynightHelper().isNightMode();
+ RenderingRuleSearchRequest rreq = map.getMyApplication().getResourceManager()
+ .getRenderer().getSearchRequestWithAppliedCustomRules(storage, nightMode);
+
+ for (int i : tps) {
+ BinaryMapRouteReaderAdapter.RouteTypeRule tp = object.region.quickGetEncodingRule(i);
+ if (tp.getTag().equals("highway") || tp.getTag().equals("route")) {
+ rreq.setInitialTagValueZoom(tp.getTag(), tp.getValue(), 13, null);
+ } else {
+ additional.append(tp.getTag()).append("=").append(tp.getValue()).append(";");
+ }
+ }
+
+ rreq.setIntFilter(rreq.ALL.R_TEXT_LENGTH, name.length());
+ rreq.setStringFilter(rreq.ALL.R_NAME_TAG, nameTag);
+ rreq.setStringFilter(rreq.ALL.R_ADDITIONAL, additional.toString());
+ rreq.search(RenderingRulesStorage.TEXT_RULES);
+
+ OsmandRenderer.RenderingContext rc = new OsmandRenderer.RenderingContext(context);
+
+ TextRenderer textRenderer = new TextRenderer(context);
+ TextRenderer.TextDrawInfo text = new TextRenderer.TextDrawInfo(name);
+
+
+ Paint p = textRenderer.getPaintText();
+ p.setTypeface(Typeface.create("Droid Serif", Typeface.BOLD));
+
+ int shieldRes = -1;
+
+ if (rreq.isSpecified(rreq.ALL.R_TEXT_SHIELD)) {
+ text.setShieldResIcon(rreq.getStringPropertyValue(rreq.ALL.R_TEXT_SHIELD));
+ shieldRes = app.getResources().getIdentifier("h_"+text.getShieldResIcon(),
+ "drawable", app.getPackageName());
+ }
+
+ if (rreq.isSpecified(rreq.ALL.R_TEXT_COLOR)) {
+ p.setColor(rreq.getIntPropertyValue(rreq.ALL.R_TEXT_COLOR));
+ }
+
+ if (rreq.isSpecified(rreq.ALL.R_TEXT_SIZE)) {
+ float ts = rreq.getFloatPropertyValue(rreq.ALL.R_TEXT_SIZE);
+ textRenderer.getPaintText().setTextSize(
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, ts,
+ app.getResources().getDisplayMetrics()));
+ }
+
+ if (shieldRes != -1) {
+ float xSize;
+ float ySize;
+ Bitmap shield;
+ shield = BitmapFactory.decodeResource(app.getResources(), shieldRes);
+ ySize = shield.getHeight();
+ xSize = shield.getWidth();
+ float xyRatio = xSize/ySize;
+ //setting view propotions (height is fixed by toolbar size - 48dp);
+ int viewHeightPx = AndroidUtils.dpToPx(context, 48);
+ int viewWidthPx = (int) (viewHeightPx * xyRatio);
+
+ ViewGroup.LayoutParams params = view.getLayoutParams();
+ params.width = viewWidthPx;
+ view.setLayoutParams(params);
+
+ //creating bitmap according to size of resource
+ Bitmap bitmap = Bitmap.createBitmap((int) xSize, (int) ySize, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ text.fillProperties(rc, rreq, xSize/2, ySize/2 - p.getFontMetrics().ascent/2f);
+ textRenderer.drawShieldIcon(rc, canvas, text, text.getShieldResIcon());
+ textRenderer.drawWrappedText(canvas, text, 20);
+
+ view.setImageBitmap(bitmap);
+ return true;
+ }
+ return false;
+ }
+
public boolean updateWaypoint() {
final LocationPointWrapper pnt = waypointHelper.getMostImportantLocationPoint(null);
boolean changed = this.lastPoint != pnt;
diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/RouteInfoWidgetsFactory.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/RouteInfoWidgetsFactory.java
index 21615c55cb..366c215a48 100644
--- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/RouteInfoWidgetsFactory.java
+++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/RouteInfoWidgetsFactory.java
@@ -875,9 +875,11 @@ public class RouteInfoWidgetsFactory {
}
- private static class LanesDrawable extends Drawable {
- int[] lanes = null;
+ public static class LanesDrawable extends Drawable {
+ public int[] lanes = null;
boolean imminent = false;
+ public boolean isTurnByTurn = false;
+ public boolean isNightMode = false;
private Context ctx;
private Paint paintBlack;
private Paint paintRouteDirection;
@@ -892,7 +894,7 @@ public class RouteInfoWidgetsFactory {
private int imgMinDelta;
private int imgMargin;
- LanesDrawable(MapActivity ctx, float scaleCoefficent) {
+ public LanesDrawable(MapActivity ctx, float scaleCoefficent) {
this.ctx = ctx;
OsmandSettings settings = ctx.getMyApplication().getSettings();
leftSide = settings.DRIVING_REGION.get().leftHandDriving;
@@ -916,7 +918,7 @@ public class RouteInfoWidgetsFactory {
paintSecondTurn.setColor(ctx.getResources().getColor(R.color.nav_arrow_distant));
}
- void updateBounds() {
+ public void updateBounds() {
float w = 0;
float h = 0;
float delta = imgMinDelta;
@@ -1031,8 +1033,13 @@ public class RouteInfoWidgetsFactory {
// canvas.translate((int) (16 * scaleCoefficient), 0);
for (int i = 0; i < lanes.length; i++) {
if ((lanes[i] & 1) == 1) {
- paintRouteDirection.setColor(imminent ? ctx.getResources().getColor(R.color.nav_arrow_imminent) :
- ctx.getResources().getColor(R.color.nav_arrow));
+ if (isTurnByTurn){
+ paintRouteDirection.setColor(isNightMode ? ctx.getResources().getColor(R.color.active_color_primary_dark) :
+ ctx.getResources().getColor(R.color.active_color_primary_light));
+ } else {
+ paintRouteDirection.setColor(imminent ? ctx.getResources().getColor(R.color.nav_arrow_imminent) :
+ ctx.getResources().getColor(R.color.nav_arrow));
+ }
} else {
paintRouteDirection.setColor(ctx.getResources().getColor(R.color.nav_arrow_distant));
}
diff --git a/OsmAnd/src/net/osmand/plus/voice/CommandBuilder.java b/OsmAnd/src/net/osmand/plus/voice/CommandBuilder.java
index 2e7bdaf72a..65a28b70e6 100644
--- a/OsmAnd/src/net/osmand/plus/voice/CommandBuilder.java
+++ b/OsmAnd/src/net/osmand/plus/voice/CommandBuilder.java
@@ -39,6 +39,7 @@ public class CommandBuilder {
protected static final String C_ATTENTION = "attention"; //$NON-NLS-1$
protected static final String C_OFF_ROUTE = "off_route"; //$NON-NLS-1$
protected static final String C_BACK_ON_ROUTE ="back_on_route"; //$NON-NLS-1$
+ protected static final String C_TAKE_EXIT = "take_exit"; //$NON-NLS-1$
protected static final String C_BEAR_LEFT = "bear_left"; //$NON-NLS-1$
@@ -178,6 +179,14 @@ public class CommandBuilder {
return alt(prepareStruct(C_TURN, param, dist, streetName), prepareStruct(C_TURN, param, dist));
}
+ public CommandBuilder takeExit(String turnType, StreetName streetName) {
+ return alt(prepareStruct(C_TAKE_EXIT, turnType, streetName), prepareStruct(C_TAKE_EXIT, turnType));
+ }
+
+ public CommandBuilder takeExit(String turnType, double dist, StreetName streetName) {
+ return alt(prepareStruct(C_TAKE_EXIT, turnType, dist, streetName), prepareStruct(C_TAKE_EXIT, turnType, dist));
+ }
+
/**
*
* @param param A_LEFT, A_RIGHT, ...
diff --git a/OsmAnd/src/net/osmand/plus/voice/JSCommandBuilder.java b/OsmAnd/src/net/osmand/plus/voice/JSCommandBuilder.java
index f963eb81e6..dfdfcea29a 100644
--- a/OsmAnd/src/net/osmand/plus/voice/JSCommandBuilder.java
+++ b/OsmAnd/src/net/osmand/plus/voice/JSCommandBuilder.java
@@ -115,6 +115,14 @@ public class JSCommandBuilder extends CommandBuilder {
return addCommand(C_TURN, param, dist, convertStreetName(streetName));
}
+ public JSCommandBuilder takeExit(String turnType, StreetName streetName) {
+ return takeExit(turnType, -1, streetName);
+ }
+
+ public JSCommandBuilder takeExit(String turnType, double dist, StreetName streetName) {
+ return addCommand(C_TAKE_EXIT, turnType, dist, convertStreetName(streetName));
+ }
+
/**
*
* @param param A_LEFT, A_RIGHT, ...