Merge pull request #8147 from osmandapp/exit_and_shield_widget

Exit and shield widget
This commit is contained in:
vshcherb 2020-01-09 17:00:38 +01:00 committed by GitHub
commit b7d515e98a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 626 additions and 125 deletions

View file

@ -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++) {

View file

@ -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;
}
}

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/active_color_primary_light" />
<corners android:radius="3dp" />
</shape>

View file

@ -335,43 +335,74 @@
android:background="@drawable/btn_round"
android:minHeight="@dimen/map_address_height">
<FrameLayout
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/map_exit_ref"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
>
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" />
<TextView
android:id="@+id/map_address_text_shadow"
android:importantForAccessibility="no"
<ImageView
android:id="@+id/map_turn_icon"
android:layout_width="@dimen/map_widget_height"
android:layout_height="@dimen/map_widget_height"
android:scaleType="fitCenter"
tools:src="@drawable/map_turn_right_small" />
<ImageView
android:id="@+id/map_shield_icon"
android:layout_width="60dp"
android:layout_height="match_parent"
android:scaleType="fitCenter"
tools:src="@drawable/h_white_pillow_2_road_shield" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textSize="@dimen/map_widget_text_size"
tools:text="Long Street Name">
</TextView>
android:layout_height="wrap_content">
<TextView
android:id="@+id/map_address_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textSize="@dimen/map_widget_text_size"
tools:text="Long Street Name">
</TextView>
<TextView
android:id="@+id/map_address_text_shadow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:importantForAccessibility="no"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textSize="@dimen/map_widget_text_size"
tools:text="Long Street Name" />
<TextView
android:id="@+id/map_address_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textSize="@dimen/map_widget_text_size"
tools:text="Long Street Name" />
</FrameLayout>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/waypoint_info_bar"

View file

@ -112,43 +112,81 @@
android:background="@drawable/btn_flat"
android:minHeight="@dimen/map_address_height">
<!-- android:layout_weight="1" to show properly next turn -->
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp">
<!-- android:layout_weight="1" to show properly next turn -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/map_exit_ref"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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"
android:paddingLeft="@dimen/text_margin_small"
android:paddingRight="@dimen/text_margin_small"
android:textStyle="bold"
tools:text="8"
<TextView
android:id="@+id/map_address_text_shadow"
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textSize="@dimen/map_widget_text_size"
tools:text="Long Street Name">
</TextView>
tools:visibility="visible" />
<TextView
android:id="@+id/map_address_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textSize="@dimen/map_widget_text_size"
tools:text="Long Street Name">
</TextView>
</FrameLayout>
<ImageView
android:id="@+id/map_turn_icon"
android:layout_width="@dimen/map_widget_height"
android:layout_height="@dimen/map_widget_height"
android:scaleType="fitCenter"
android:visibility="gone"
tools:src="@drawable/map_turn_right_small" />
<ImageView
android:id="@+id/map_shield_icon"
android:layout_width="@dimen/map_widget_height"
android:layout_height="@dimen/map_widget_height"
android:scaleType="fitCenter"
android:visibility="gone"
tools:src="@drawable/h_white_pillow_2_road_shield" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/map_address_text_shadow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:importantForAccessibility="no"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textSize="@dimen/map_widget_text_size"
tools:text="Long Street Name" />
<TextView
android:id="@+id/map_address_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textSize="@dimen/map_widget_text_size"
tools:text="Long Street Name" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/waypoint_info_bar"

View file

@ -78,19 +78,36 @@
tools:text="@string/app_version"/>
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="@dimen/content_padding_half"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="@dimen/content_padding_half"
android:layout_weight="1"
android:textSize="@dimen/default_desc_text_size"
android:textColor="?android:textColorPrimary"
tools:text="Head Dmytrivska Street"
android:text=""/>
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text=""
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
tools:text="Head Dmytrivska Street" />
<ImageView
android:id="@+id/lanes"
android:layout_width="match_parent"
android:layout_height="18dp"
android:layout_marginTop="2dp"
android:scaleType="fitStart"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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());

View file

@ -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;
}
}

View file

@ -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() {

View file

@ -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<String, String> 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) {

View file

@ -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;

View file

@ -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));
}

View file

@ -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, ...

View file

@ -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, ...